Android中使用RSA解密AES密钥的问题排查与实现指引
问题根源与解决方案
我来帮你排查并解决这个问题,咱们一步步拆解:
1. 核心错误:RSA密钥对不匹配
你在生成密钥对的时候犯了一个致命错误——连续调用了两次keyGen.genKeyPair(),一次提取公钥,一次提取私钥。这会生成两组完全独立的RSA密钥对,用这个公钥加密的数据,用那个无关的私钥自然解不开,直接触发BadPaddingException。
修正后的密钥生成代码
KeyPairGenerator keyGen = null; try { keyGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } keyGen.initialize(1024); // 只生成一次密钥对!公钥私钥必须来自同一对 KeyPair keyPair = keyGen.genKeyPair(); byte[] publicKey = keyPair.getPublic().getEncoded(); byte[] privateKey = keyPair.getPrivate().getEncoded(); Util.save("privateKey", rsa.encryptBASE64(privateKey), this); Util.save("publicKey", rsa.encryptBASE64(publicKey), this);
2. Base64工具类参数错误
你的Base64编码/解码方法里重复设置了NO_PADDING,而且URL_SAFE与NO_PADDING组合可能导致数据长度不匹配(Base64通常需要填充到4的倍数才能正确解码)。建议调整参数,保持编码解码的一致性:
public static byte[] decryptBASE64(String key) { // 去掉重复的NO_PADDING,保持参数统一 return Base64.decode(key, Base64.NO_WRAP | Base64.URL_SAFE); } public static String encryptBASE64(byte[] key) { return Base64.encodeToString(key, Base64.NO_WRAP | Base64.URL_SAFE); }
如果不需要URL安全的字符替换,直接用Base64.DEFAULT也可以,能避免不必要的兼容性问题。
3. 解密后AES密钥的转换
当你用RSA解密出AES密钥的字节数组后,直接用SecretKeySpec生成可用的AES密钥即可——因为你加密的本来就是secretKey.getEncoded()(AES密钥的原始字节):
// 解密得到AES密钥的原始字节数组 byte[] aesKeyRecovered = rsa.decryptByPrivateKey(rsa.decryptBASE64(aesKeyCipherBase64),myPrivateKeyString); // 转换为可直接使用的AES密钥 SecretKey recoveredAesKey = new SecretKeySpec(aesKeyRecovered, "AES");
这样就可以用这个密钥解密之前AES加密的文件了。
测试逻辑验证
你的加密解密连续测试逻辑是对的,修正密钥对后可以加上断言验证一致性:
// 假设secretKey是你的原始16字节AES密钥 String aesKeyCipherBase64 = rsa.encryptBASE64(rsa.encryptByPublicKey(secretKey.getEncoded(), myPublicKeyString)); byte[] aesKeyRecovered = rsa.decryptByPrivateKey(rsa.decryptBASE64(aesKeyCipherBase64),myPrivateKeyString); // 验证解密后的密钥与原始密钥是否一致 assert Arrays.equals(secretKey.getEncoded(), aesKeyRecovered);
额外建议
- RSA 1024位目前已被认为安全性不足,建议至少升级到2048位密钥。
- 确保加密和解密时的Cipher算法字符串完全一致(你用的
RSA/ECB/PKCS1Padding是标准且正确的)。 - 异常处理不要只打印堆栈,最好添加业务层面的错误提示,避免程序无响应崩溃。
内容的提问来源于stack exchange,提问作者Sijo Josan
相关产品推荐
相关产品推荐

