一.項目結構
二.代碼具體實現
1.密鑰對生成的兩種方式:一種生成公鑰私文件,一種生成公鑰私串
KeyPairGenUtil.java
package com.wangjinxiang.genkey.util; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import sun.misc.BASE64Encoder; public class KeyPairGenUtil { /** 指定加密算法為RSA */ private static final String ALGORITHM = "RSA"; /** 密鑰長度,用來初始化 */ private static final int KEYSIZE = 1024; /** 指定公鑰存放文件 */ private static String PUBLIC_KEY_FILE = "PublicKey"; /** 指定私鑰存放文件 */ private static String PRIVATE_KEY_FILE = "PrivateKey"; public static void main(String[] args) throws Exception { //generateKeyPair(); genKeyPair(); } /** * 生成密鑰對文件 * @throws Exception */ private static void generateKeyPair() throws Exception { // /** RSA算法要求有一個可信任的隨機數源 */ // SecureRandom secureRandom = new SecureRandom(); /** 為RSA算法創建一個KeyPairGenerator對象 */ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); /** 利用上面的隨機數據源初始化這個KeyPairGenerator對象 */ // keyPairGenerator.initialize(KEYSIZE, secureRandom); keyPairGenerator.initialize(KEYSIZE); /** 生成密匙對 */ KeyPair keyPair = keyPairGenerator.generateKeyPair(); /** 得到公鑰 */ Key publicKey = keyPair.getPublic(); /** 得到私鑰 */ Key privateKey = keyPair.getPrivate(); ObjectOutputStream oos1 = null; ObjectOutputStream oos2 = null; try { /** 用對象流將生成的密鑰寫入文件 */ oos1 = new ObjectOutputStream(new FileOutputStream(PUBLIC_KEY_FILE)); oos2 = new ObjectOutputStream(new FileOutputStream(PRIVATE_KEY_FILE)); oos1.writeObject(publicKey); oos2.writeObject(privateKey); } catch (Exception e) { throw e; } finally { /** 清空緩存,關閉文件輸出流 */ oos1.close(); oos2.close(); } } /** * 生成密鑰對 * @throws NoSuchAlgorithmException */ private static void genKeyPair() throws NoSuchAlgorithmException { /** RSA算法要求有一個可信任的隨機數源 */ SecureRandom secureRandom = new SecureRandom(); /** 為RSA算法創建一個KeyPairGenerator對象 */ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); /** 利用上面的隨機數據源初始化這個KeyPairGenerator對象 */ keyPairGenerator.initialize(KEYSIZE, secureRandom); //keyPairGenerator.initialize(KEYSIZE); /** 生成密匙對 */ KeyPair keyPair = keyPairGenerator.generateKeyPair(); /** 得到公鑰 */ Key publicKey = keyPair.getPublic(); /** 得到私鑰 */ Key privateKey = keyPair.getPrivate(); byte[] publicKeyBytes = publicKey.getEncoded(); byte[] privateKeyBytes = privateKey.getEncoded(); String publicKeyBase64 = new BASE64Encoder().encode(publicKeyBytes); String privateKeyBase64 = new BASE64Encoder().encode(privateKeyBytes); System.out.println("publicKeyBase64.length():" + publicKeyBase64.length()); System.out.println("publicKeyBase64:" + publicKeyBase64); System.out.println("privateKeyBase64.length():" + privateKeyBase64.length()); System.out.println("privateKeyBase64:" + privateKeyBase64); } }
2.將密鑰串生成方式的密鑰對在常量類里定義,以便后面的應用使用
Constants.java
package com.wangjinxiang.constant; public class Constants { //#priKeyText public final static String priKeyText = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJg7beoxy+/SCkaz3ut+bEhOOPPmb+yNngmBi88Gz4kfAP9IK/tMkIQpWbhpdMQ9NdGQ3suBSNBOcQYZLUkFjjPKqmeYlx+k3Fal2ADIT/imgwnytxm+qbXgM6M0f7r2bCkh0mTJIe7NQLNC0wnwYbajA1z1+tM6lmjOVxRZsZZ9AgMBAAECgYAoGzAgDTJ/YkTWz7ihLlN00Tbr+v/twHmsY3bj+hVfOM3Yc7kyob9JMmOy1AWxVbcCGTq5PrxiNOhOBQALRu1pivDsGDm2wA+Jb4vSIwL8dFCnIMlFFPMUb5VwtNIdlEZDQdZoLV7185OJ4IEK//GuNTwCklZNIOZ0j0YMEUw7uQJBAN5C3QpRWfwRhDf1S5+RaQPZWKehuc3DU2T67/tIUOKkSnY/KUX4KxPxCXXRsrbzU4mwoW0npBO3mtuOFDsk788CQQCvVzdjz7TZXFcGOjhk1e+id/ElW69/nt6DQmwUnJYyNS4cYfKoGD/RAxN0xaAoXsl6u3FGzY7TjLsuf6Wn3vvzAkAmLGW6d+50lK2YztCGP3tB5fqMEALRjFKubUr6ZZk+0+jWFlMIaW88pZFyYunG8lPOuj9/d+d+W3KFcwmWfumRAkApho1OrSVWiQDvL6CleOk84A0TXOhuYBCwo213YDJOB7w46pWOa9fJR2I3OIqapQAwee3057/YqC64b3CrFiszAkEAttDMWhXlagXMjwZAjEuuHK3CVCqRPNhZlnoX5A5RWIg0+BpHNQDfVSlYBtki361zB8L3HR8YfJIOWk/4S+ORLg=="; //#pubKeyText public final static String pubKeyText = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCYO23qMcvv0gpGs97rfmxITjjz5m/sjZ4JgYvPBs+JHwD/SCv7TJCEKVm4aXTEPTXRkN7LgUjQTnEGGS1JBY4zyqpnmJcfpNxWpdgAyE/4poMJ8rcZvqm14DOjNH+69mwpIdJkySHuzUCzQtMJ8GG2owNc9frTOpZozlcUWbGWfQIDAQAB"; }
DigestUtil.java
package com.wangjinxiang.util; public class DigestUtil { /** * 字節轉為十六進制字符串 * @param字節 * @return 十六進制字符串 */ public static String byte2hex(byte[] b) { String hs = ""; String stmp = ""; for (int n = 0; b != null && n < b.length; n++) { stmp = (java.lang.Integer.toHexString(b[n] & 0XFF)); if (stmp.length() == 1) hs = hs + "0" + stmp; else hs = hs + stmp; } return hs; } /** * 十六進制字符轉為字節 * @param 十六進制字符 * @return 字節 */ public static byte[] hex2byte(byte[] b) { if ((b.length % 2) != 0) throw new IllegalArgumentException("byte length is not correct"); byte[] b2 = new byte[b.length / 2]; for (int n = 0; n < b.length; n += 2) { String item = new String(b, n, 2); b2[n / 2] = (byte) Integer.parseInt(item, 16); } return b2; } /** * 字符串轉換成十六進制值 * @param bin String 我們看到的要轉換成十六進制的字符串 * @return */ public static String bin2hex(String bin) { char[] digital = "0123456789ABCDEF".toCharArray(); StringBuffer sb = new StringBuffer(""); byte[] bs = bin.getBytes(); int bit; for (int i = 0; i < bs.length; i++) { bit = (bs[i] & 0x0f0) >> 4; sb.append(digital[bit]); bit = bs[i] & 0x0f; sb.append(digital[bit]); } return sb.toString(); } }
3.加解密應用實例RSAUtil.java
說明:加解密是用公鑰加密,用私鑰解密
package com.wangjinxiang.util; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; import com.wangjinxiang.constant.Constants; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class RSAUtil { /** 指定加密算法為RSA */ private static final String ALGORITHM = "RSA"; public static void main(String[] args) throws Exception { String source = "深圳,您好!";// 要加密的字符串 System.out.println("准備用公鑰加密的字符串為:" + source); String cryptograph = encrypt(source);// 生成的密文 System.out.print("用公鑰加密后的結果為:" + cryptograph); System.out.println(); String target = decrypt(cryptograph);// 解密密文 System.out.println("用私鑰解密后的字符串為:" + target); System.out.println(); } /** * 加密方法 * @param source 源數據 * @return * @throws Exception */ public static String encrypt(String source) throws Exception { java.security.spec.X509EncodedKeySpec x509KeySpec = new java.security.spec.X509EncodedKeySpec(Base64.decodeBase64(Constants.pubKeyText)); // RSA算法 java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA"); // 取公鑰匙對象 java.security.PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); // 得到Cipher對象來實現對源數據的RSA加密 Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] b = source.getBytes(); /** 執行加密操作 */ byte[] b1 = cipher.doFinal(b); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(b1); } /** * 解密算法 * @param cryptograph 密文 * @return * @throws Exception */ public static String decrypt(String cryptograph) throws Exception { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(Constants.priKeyText)); KeyFactory keyf = KeyFactory.getInstance("RSA"); PrivateKey privateKey = keyf.generatePrivate(priPKCS8); /** 得到Cipher對象對已用公鑰加密的數據進行RSA解密 */ Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); BASE64Decoder decoder = new BASE64Decoder(); byte[] b1 = decoder.decodeBuffer(cryptograph); /** 執行解密操作 */ byte[] b = cipher.doFinal(b1); return new String(b); } }
運行結果:
准備用公鑰加密的字符串為:深圳,您好! 用公鑰加密后的結果為:Q5bZjBlIIPII04NOCIwYDPYBGNSC5Hv7XKc8TlkCRbZyAK4M4nm9uYcEded0Nbj7HeLXNZY8XrQD l2+FsYjfL0DlioCoJQm7bnwlVwYmdNMXOB3bfepywpeFRDSNswJxueLqVtmIKcbuCuXBvdIqrfDq PVbCVfI59/GhqAcqM6U= 用私鑰解密后的字符串為:深圳,您好!
4.加簽驗簽實例SignUtil.java
說明:加簽是用私鑰,驗簽是用公鑰
package com.wangjinxiang.util; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import org.apache.commons.codec.binary.Base64; import com.wangjinxiang.constant.Constants; public class SignUtil { private final static String CHARACTER_ENCODING_UTF_8 = "UTF-8"; public static void main(String[] args) { String signString = "深圳,您好!"; try { // 加簽 String localSignature = SignUtil.sign(Constants.priKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString); System.out.println(localSignature); //驗簽 boolean verifyResult = SignUtil.verify(Constants.pubKeyText.getBytes(CHARACTER_ENCODING_UTF_8), signString, localSignature); System.out.println("verifyResult:" + verifyResult); } catch (Exception e) { e.printStackTrace(); } } /** * RSA私鑰加簽 * @param priKeyText經過base64處理后的私鑰 * @param plainText明文內容 * @return 十六進制的簽名字符串 * @throws Exception */ public static String sign(byte[] priKeyText, String plainText) throws Exception { try { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyText)); KeyFactory keyf = KeyFactory.getInstance("RSA"); PrivateKey prikey = keyf.generatePrivate(priPKCS8); // 用私鑰對信息生成數字簽名 java.security.Signature signet = java.security.Signature.getInstance("SHA256withRSA"); signet.initSign(prikey); signet.update(plainText.getBytes("UTF-8")); return DigestUtil.byte2hex(signet.sign()); } catch (Exception e) { throw e; } } /** * 公鑰驗簽 * @param pubKeyText經過base64處理后的公鑰 * @param plainText明文內容 * @param signText十六進制的簽名字符串 * @return 驗簽結果 true驗證一致 false驗證不一致 */ public static boolean verify(byte[] pubKeyText, String plainText, String signText) { try { // 解密由base64編碼的公鑰,並構造X509EncodedKeySpec對象 java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec( Base64.decodeBase64(pubKeyText)); // RSA算法 java.security.KeyFactory keyFactory = java.security.KeyFactory.getInstance("RSA"); // 取公鑰匙對象 java.security.PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec); // 十六進制數字簽名轉為字節 byte[] signed = DigestUtil.hex2byte(signText.getBytes("UTF-8")); java.security.Signature signatureChecker = java.security.Signature.getInstance("SHA256withRSA"); signatureChecker.initVerify(pubKey); signatureChecker.update(plainText.getBytes("UTF-8")); // 驗證簽名是否正常 return signatureChecker.verify(signed); } catch (Throwable e) { return false; } } }
運行結果:
7ef0cd04a3dc41ae1396a90a3d8a8b799c68c65202361823dd3a71a05fc2bf57c09ebe2074ba49008cf58288297267d770137ee267c6c296a784c7d50c607c73e1d78799c7de5dadf183f011d604df7270ce5616e465ddc93a95df9095249702fc265e97ed7ab2adf4535d13237040653d7f000a3080a0c4f11f84bbe48849e7 verifyResult:true
5.從生成的密鑰對文件中讀取公私鑰加解密實例RSAUtil02.java
package com.wangjinxiang.util2; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.security.Key; import javax.crypto.Cipher; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class RSAUtil02 { /** 指定加密算法為RSA */ private static final String ALGORITHM = "RSA"; /** 指定公鑰存放文件 */ private static String PUBLIC_KEY_FILE = "PublicKey"; /** 指定私鑰存放文件 */ private static String PRIVATE_KEY_FILE = "PrivateKey"; public static void main(String[] args) throws Exception { String source = "深圳,您好!";// 要加密的字符串 System.out.println("准備用公鑰加密的字符串為:" + source); String cryptograph = encrypt(source);// 生成的密文 System.out.print("用公鑰加密后的結果為:" + cryptograph); System.out.println(); String target = decrypt(cryptograph);// 解密密文 System.out.println("用私鑰解密后的字符串為:" + target); System.out.println(); } /** * 加密方法 * @param source 源數據 * @return * @throws Exception */ public static String encrypt(String source) throws Exception { Key publicKey = getKey(PUBLIC_KEY_FILE); /** 得到Cipher對象來實現對源數據的RSA加密 */ Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] b = source.getBytes(); /** 執行加密操作 */ byte[] b1 = cipher.doFinal(b); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(b1); } /** * 解密算法 * @param cryptograph 密文 * @return * @throws Exception */ public static String decrypt(String cryptograph) throws Exception { Key privateKey = getKey(PRIVATE_KEY_FILE); /** 得到Cipher對象對已用公鑰加密的數據進行RSA解密 */ Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, privateKey); BASE64Decoder decoder = new BASE64Decoder(); byte[] b1 = decoder.decodeBuffer(cryptograph); /** 執行解密操作 */ byte[] b = cipher.doFinal(b1); return new String(b); } private static Key getKey(String fileName) throws Exception, IOException { Key key; ObjectInputStream ois = null; try { /** 將文件中的私鑰對象讀出 */ ois = new ObjectInputStream(new FileInputStream(fileName)); key = (Key) ois.readObject(); } catch (Exception e) { throw e; } finally { ois.close(); } return key; } }
運行結果:
准備用公鑰加密的字符串為:深圳,您好! 用公鑰加密后的結果為:Ep2Y6EstlUWQnmVxsZ0/NIV1NFIPAlg8rJguRdQB+2uBD+/sunrPiVoCm3zbuj317CNG5hwijNBf qKETmd7HoftpnHxzYwn+lWqlVdUHIO+ZrFn2OB6omlA/aFHCZzIHtKDU72cNuiBiwONxCXyaWq4Z scDfvzbz3//UYOhlDs4= 用私鑰解密后的字符串為:深圳,您好!