You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 04:35:16