一、背景
最近工作中涉及到RSA加密的相關需求任務,之前對加密算法了解不多,開發過程中遇到了一些坑記錄一下。
二、RSA原理
RSA加密是非對稱加密,公開私鑰,保留私鑰。通信時數據通過公開的公鑰加密,接收方用私鑰解密,達到安全傳輸的目的。RSA算法原理在這就不詳述了,放個鏈接 https://blog.csdn.net/raalghul/article/details/51883354
三、JAVA實現
公鑰和私鑰 都是由 兩個數的組合構成,這樣儲存不太方便。 用base64將PublicKey 和PrivateKey對象 轉為公鑰、私鑰 字符串。
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
generator.initialize(2048, new SecureRandom());
KeyPair keyPair = generator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
String pubKey = new String(Base64.encodeBase64(publicKey.getEncoded()));
System.out.println("公鑰:"+pubKey);
PrivateKey privateKey = keyPair.getPrivate();
String priKey = new String(Base64.encodeBase64(privateKey.getEncoded()));
System.out.println("私鑰:"+priKey);
在加密解密的過程中需要的仍是 PublicKey 和PrivateKey對象, 需要將 公鑰、私鑰字符串轉換為 PublicKey 和PrivateKey對象 來實現加密 解密。
//公鑰string 轉publicKey對象
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new sun.misc.BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
//公鑰string 轉publicKey對象
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new sun.misc.BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
其他部分代碼貼出,如果不注意編碼問題會拋出javax.crypto.IllegalBlockSizeException,在代碼中標出
public static PrivateKey getPrivateKey(String key) throws Exception{
byte[] keyBytes;
keyBytes = (new sun.misc.BASE64Decoder()).decodeBuffer(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
//加密
public static byte[] encrypt(byte[] content, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(content);
}
/**
* byte[] b1 byte[] b2 byte[] b1 String
* String data----getBytes(默認編碼)-----公鑰加密(ISO字符集,使用其他字符集數據丟失)---------私鑰解密----------new String(默認編碼)----String data
*
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
generator.initialize(2048, new SecureRandom());
KeyPair keyPair = generator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
String pubKey = new String(Base64.encodeBase64(publicKey.getEncoded()));
System.out.println("公鑰:"+pubKey);
PrivateKey privateKey = keyPair.getPrivate();
String priKey = new String(Base64.encodeBase64(privateKey.getEncoded()));
System.out.println("私鑰:"+priKey);
//公鑰加密 此時的getBytes() 的編碼 為默認 應該和最后的 new String() 的編碼一樣
byte[] encryptedBytes = encrypt(data.getBytes(), publicKey);
//將密文字節數組轉String時 不使用ISO編碼 可能導致數據丟失 解密失敗
//如果下面兩句 沒有指明編碼,或者使用其他編碼,會導致數據的錯誤,導致字節數組b1長度超出限制, 報出異常javax.crypto.IllegalBlockSizeException,具體原因可能是因為在公鑰加密時使用的字符集問題。
String s1 = new String(encryptedBytes,"ISO8859-1");
byte[] b1 = s1.getBytes("ISO8859-1");
//解密
byte[] decryptedByte = decrypt(b1, privateKey);
System.out.println("解密后:"+new String(decryptedByte));
}
public static byte[] decrypt(byte[] content, PrivateKey privateKey) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(content);
}
}
運行結果:
歡迎大家關注我的個人微信訂閱號:Java從零單排 分享學習資料,交流學習經驗~