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

AES/GCM解密触发OPENSSL_internal:BAD_DECRYPT错误的原因排查

问题描述

在测试中,发送包装值获取加密密钥后,尝试使用AES/GCM/NOPADDING及有效的transportKeyIV解密,在cipher.doFinal()方法中抛出如下错误:

javax.crypto.AEADBadTagException: error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at com.android.org.conscrypt.OpenSSLAeadCipher.throwAEADBadTagExceptionIfAvailable(OpenSSLAeadCipher.java:320)
at com.android.org.conscrypt.OpenSSLAeadCipher.doFinalInternal(OpenSSLAeadCipher.java:371)
at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:374)
at javax.crypto.Cipher.doFinal(Cipher.java:2056)
at com.geopagos.core.security.keystore.KeystoreWrapTest.decodeWrappedCertificate(KeystoreWrapTest.kt:274)
at com.geopagos.core.security.keystore.KeystoreWrapTest.access$decodeWrappedCertificate(KeystoreWrapTest.kt:36)
at com.geopagos.core.security.keystore.KeystoreWrapTest$testUnwrapCertManually$1.invokeSuspend(KeystoreWrapTest.kt:215)
at com.geopagos.core.security.keystore.KeystoreWrapTest$testUnwrapCertManually$1.invoke(Unknown Source:8)
at com.geopagos.core.security.keystore.KeystoreWrapTest$testUnwrapCertManually$1.invoke(Unknown Source:4)

对应的解密代码:

private  fun decode(
    certificateStr : String,
    expectedTransportKey : String,
    expectedSecureKey : String
) {
    val derValue = DERGeneralString.fromByteArray(certificateStr.hexToByteArray()) as DLSequence

    val encryptedSecureKey = (derValue.elementAt(4) as DEROctetString).octets

    // Decrypting
    val secretKey = SecretKeySpec(plainTransportKey, KeyProperties.KEY_ALGORITHM_AES)
    val cipher = Cipher.getInstance("${KeyProperties.KEY_ALGORITHM_AES}/${KeyProperties.BLOCK_MODE_GCM}/${KeyProperties.ENCRYPTION_PADDING_NONE}")
    val parameterSpec: AlgorithmParameterSpec = GCMParameterSpec(128, transportKeyIV)
    cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec)

    // HERE is where it crashed
    val result = cipher.doFinal(encryptedSecureKey)

    expectThat(plainSecureKey.toHexString()).isEqualTo(result)
}
可能的原因

AEADBadTagException本质是GCM模式解密时完整性验证标签不匹配,导致解密失败,常见原因如下:

  • 加密解密密钥不一致:代码中用plainTransportKey生成SecretKey,需确认该密钥和加密端使用的完全一致——包括密钥的hex转byte是否正确、长度是否符合AES标准(128/192/256位),任何偏差都会触发标签验证失败。

  • IV值不匹配:即便你认为transportKeyIV有效,也要确认:

    • IV长度是否和加密端一致(GCM常用12字节,也支持其他长度,但必须两边统一);
    • IV的字节序列是否和加密时完全相同,GCM要求加密解密必须使用同一个IV,差一个字节都会报错。
  • 待解密数据不完整或篡改:从DER序列取出的encryptedSecureKey可能不是完整的GCM密文——GCM密文通常包含密文本身+16字节认证标签,如果只取了密文部分、标签被截断或篡改,解密时会直接验证失败。需确认加密端输出的完整内容是否都被存入DER序列的第4个元素中。

  • 附加认证数据(AAD)缺失或不匹配:如果加密端使用了GCM的附加认证数据,解密时必须传入完全相同的AAD才能通过验证。你的代码未设置AAD,需确认加密端也未使用AAD;若加密端用了,解密时需调用cipher.updateAAD(aadBytes)添加对应数据。

  • 编码解码错误:检查certificateStr.hexToByteArray()的转换逻辑是否正确,比如hex字符串是否存在大小写问题、长度是否为偶数,这些错误会导致取出的encryptedSecureKey本身就是错误的字节序列。

  • GCM标签长度不匹配:确认加密端使用的标签长度和你设置的GCMParameterSpec(128, ...)一致,标签长度必须两边统一,比如加密端用了96位标签,解密时设置128位就会验证失败。

内容的提问来源于stack exchange,提问作者Nicote Ool

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:37:46