使用 AndroidKeyStore 存儲 RSA 私鑰後,調用 PrivateKey.getEncoded() 返回 null,導致傳統 Cipher.getInstance("RSA") 初始化失敗,解密拋出異常。
AndroidKeyStore 為了安全,永不導出私鑰原始字節。私鑰僅存在於安全硬件(TEE/StrongBox)中,只能通過 Cipher 間接使用,不能直接獲取字節數組。
public static byte[] decryptRSA(byte[] encryptedData, PrivateKey privateKey) {
try {
// 關鍵:必須指定完整的變換字符串,包含模式和填充
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedData);
} catch (Exception e) {
Log.e("RSA_Decrypt", "解密失敗", e);
return null;
}
}
"RSA" 等價於 "RSA/ECB/PKCS1Padding",但在某些 Android 版本上省略模式/填充會導致預設值不一致,顯式指定最安全。PrivateKey 實例已封裝硬件操作,無需也不允許提取字節。"RSA/ECB/PKCS1Padding",且公鑰可通過 Certificate.getPublicKey() 獲取並正常導出。// 存儲
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.PrivateKeyEntry entry = new KeyStore.PrivateKeyEntry(privateKey, certificateChain);
ks.setEntry("alias", entry, new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build());
// 取出並解密
KeyStore.PrivateKeyEntry retrieved = (KeyStore.PrivateKeyEntry) ks.getEntry("alias", null);
PrivateKey pk = retrieved.getPrivateKey();
byte[] plain = decryptRSA(cipherText, pk);
setDigests(KeyProperties.DIGEST_NONE) 若不簽名僅加密。