RSA加密和解密問題
開始寫部落格完成就是記錄自己的工作內容,感覺比其他的方式更好一些
今天的問題是,大平臺有個介面,是返回一個公鑰的,我需要通過返回的公鑰字串在轉換成PublicKey然後加密資料在傳給大平臺,大平臺會通過私鑰進行解密。解密後會通過我傳入的引數返回給小平臺相應的資料。
直接進入主題
1、生成公私鑰
無論業務怎麼耍,一個應用繫結一個金鑰對也好,或者每次重新生成也好,這都無關緊要。
public static Map<String, byte[]> generateKeyBytes() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, byte[]> keyMap = new HashMap<String, byte[]>();
keyMap.put("publicKey", publicKey.getEncoded());
keyMap.put("privateKey", privateKey.getEncoded());
return keyMap;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
以上講解幾點:
1) 1024沒必要填寫,預設就是1024,RSA金鑰長度必須是64的倍數,在512~65536之間
2) 生成金鑰對KeyPair,再由金鑰對獲取公私鑰
3) 一般情況下,你的公私鑰和業務單元繫結時,就是儲存時,需要BASE64編一下:
String pubKeyString = Base64.encodeBase64String(keyMap.get("publicKey"));
String priKeyString = Base64.encodeBase64String(keyMap.get("privateKey"));
生成這個公私鑰後,要做的就是和你的一個業務單元繫結,以後的資料由公鑰加密,私鑰解密。所以公鑰是要下發下去的。
2、加密解密
1) 一般的流程是,小平臺傳一個業務單元的code去大平臺,大平臺會根據code把對應的公鑰返回,返回的是String,所以第一步就是把符合RSA的String轉換成PublicKey.
下面是程式碼
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = new Base64().decode(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
感覺沒什麼好解釋的,傳入的就是你拿到的String公鑰。
2) 加密是很簡單的,有了公鑰,有了需要加密的內容就可以了
public static byte[] RSAEncode(PublicKey key, byte[] plainText) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText);
} catch (NoSuchAlgorithmException | NoSuchPaddingException| InvalidKeyException | IllegalBlockSizeException| BadPaddingException e) {
e.printStackTrace();
}
return null;
}
內容下面一起解釋
3) 解密和加密差不多
public static String RSADecode(PrivateKey key, byte[] encodedText) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(encodedText));
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
return null;
}
4) 呼叫一下就OK了
public static void main(String[] args) throws Exception {
PublicKey publicKey = getPublicKey(key);
byte[] encodedText = RSAEncode(publicKey, PLAIN_TEXT.getBytes());
System.out.println("RSA encoded: " + Base64.encodeBase64String(encodedText));
// 解密
PrivateKey privateKey = restorePrivateKey(keyMap.get(“privateKey”));
System.out.println("RSA decoded: " + RSADecode(privateKey, encodedText));
}
太長了,本來不想記錄解密來著,感覺也多不了多少內容,就記下吧,下面是還原私鑰的方法
/**
* 還原私鑰,PKCS8EncodedKeySpec 用於構建私鑰的規範
* @param keyBytes 編碼後的byte[]格式的私鑰
* @return
*/
public static PrivateKey restorePrivateKey(byte[] keyBytes) {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
keyBytes);
try {
KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);
return privateKey;
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
return null;
}
因為存庫的時候,存的是String,所以呼叫返還私鑰的方法時,需要轉成byte[],這個很簡單 ,類似公鑰String轉byte[]的時候也有寫