如何在Bouncy Castle中从AES_CBC切换到AES_CFB解密私钥?
解决Bouncy Castle AES_CFB模式下PKCS8加密私钥解密异常问题
问题背景
在Android项目中使用基于Bouncy Castle的依赖库,加密模式从AES_CBC切换到AES_CFB后,原解密代码抛出异常,无法读取加密数据。
原AES_CBC模式下可用的Kotlin解密代码
private fun getPrivateKey(certObject: PKCS8EncryptedPrivateKeyInfo, keyPassPhrase: String): PrivateKey? { val bouncyCastleProvider = BouncyCastleProvider() val decryptionProvider: InputDecryptorProvider = JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(bouncyCastleProvider) .build(keyPassPhrase.toCharArray()) val info = certObject.decryptPrivateKeyInfo(decryptionProvider) val converter = JcaPEMKeyConverter() return converter.getPrivateKey(info) }
AES_CFB模式下抛出的异常
Method threw 'org.bouncycastle.pkcs.PKCSException' exception. unable to read encrypted data: no key size for algorithm:2.16.840.1.101.3.4.1.44
注:OID 2.16.840.1.101.3.4.1.44 对应AES-256-CFB算法
附Java示例代码
public class Application { private final static String passphrase = "password"; public static void main(String[] args) { try { BouncyCastleProvider securityProvider = new BouncyCastleProvider(); Security.addProvider(securityProvider); PKCS8EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = getPrivateKeyInfo(); System.out.println("Private key algorithm encrypted: " + encryptedPrivateKeyInfo.getEncryptionAlgorithm().getAlgorithm()); InputDecryptorProvider decryptionProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder() .setProvider(securityProvider) .build(passphrase.toCharArray()); PrivateKeyInfo privateKeyInfo = encryptedPrivateKeyInfo.decryptPrivateKeyInfo(decryptionProvider); System.out.println("Private key algorithm decrypted: " + privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm()); }catch (Exception e){ System.out.println(e); } } private static PKCS8EncryptedPrivateKeyInfo getPrivateKeyInfo() throws IOException { InputStream privateKeyInputStream = new FileInputStream("src/main/resources/key.k8"); PEMParser pemParser = new PEMParser(new InputStreamReader(privateKeyInputStream, StandardCharsets.UTF_8)); Object pemObject = pemParser.readObject(); return (PKCS8EncryptedPrivateKeyInfo) pemObject; } }
加密私钥文件内容(key.k8)
-----BEGIN ENCRYPTED PRIVATE KEY----- <private key encrypted with AES_CFB_256 encryption using bouncy castle> -----END ENCRYPTED PRIVATE KEY-----
解决方案
1. 确保Bouncy Castle Provider正确注册到Security框架
原代码仅创建了Provider实例,但未添加到Security全局配置中,这会导致部分算法无法被正确识别。修改代码时先检查并添加Provider:
private fun getPrivateKey(certObject: PKCS8EncryptedPrivateKeyInfo, keyPassPhrase: String): PrivateKey? { val bcProvider = BouncyCastleProvider() // 检查Provider是否已注册,避免重复添加 if (Security.getProvider(bcProvider.name) == null) { Security.addProvider(bcProvider) } // 构建解密器时指定Provider val decryptorProvider = JceOpenSSLPKCS8DecryptorProviderBuilder() .setProvider(bcProvider) .build(keyPassPhrase.toCharArray()) val privateKeyInfo = certObject.decryptPrivateKeyInfo(decryptorProvider) // 密钥转换时也需指定Provider val converter = JcaPEMKeyConverter().setProvider(bcProvider) return converter.getPrivateKey(privateKeyInfo) }
2. 确认Bouncy Castle版本兼容性
确保使用的Bouncy Castle依赖版本支持AES_CFB的PKCS8解密,推荐使用适配Android的最新稳定版本:
// 在build.gradle中添加依赖 implementation 'org.bouncycastle:bcprov-android:1.77'
3. 处理Android加密强度限制(针对旧版本系统)
如果运行在Android 6.0及以下版本,需要启用无限制加密政策文件。可以通过以下方式检查并启用:
// 检查是否支持强加密 val isUnlimited = Cipher.getMaxAllowedKeyLength("AES") >= 256 if (!isUnlimited) { // 尝试启用无限制政策(需要对应权限或系统支持) try { val field = Security::class.java.getDeclaredField("isRestricted") field.isAccessible = true field.set(null, false) } catch (e: Exception) { // 处理异常或提示用户 } }
内容的提问来源于stack exchange,提问作者user_8275
相关产品推荐
相关产品推荐

