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

Python AES加密后Java解密触发AEADBadTagException问题求助

AES-GCM Tag Mismatch When Java Uses DECRYPT_MODE (PyCryptodome Encryption)

问题背景

基于PyCryptodome实现的AES-GCM加密代码,需对接固定的Java解密工具。RSA加密AES密钥、传递AES nonce流程正常,但Java端使用Cipher.DECRYPT_MODE解密时抛出javax.crypto.AEADBadTagException: Tag mismatch,切换为Cipher.ENCRYPT_MODE可正常解密,但生产环境Java代码固定为DECRYPT_MODE无法修改。Python端调用cipher.decrypt()结果与encrypt()一致,复现代码如下:

Python原加密代码

import base64
import Crypto.Cipher.AES

aesnonce  = base64.b64decode(b"nsHTfsEFKyVytEk2")
aeskey    = base64.b64decode(b"2hn3S9IsCTut7Hr9SX/7Pg==")
cipher    = Crypto.Cipher.AES.new(aeskey, Crypto.Cipher.AES.MODE_GCM, nonce=aesnonce)

plaintext = b'''Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore.'''
crypted   = cipher.encrypt(plaintext)

print( base64.b64encode(crypted) )
# 输出:w0ehWquycruj2KGkRES4M8pc6w4ZM+9HyI+KOXgqybmiYIuU1nsjZJwisZprxx2mczP280ZT5KlCXzSX0h24136m708N8sbX6m+5QlDVa73/r9dRyfSzFeByi51NqVm35wP4oHdxYW5iVx9P8iFFpcYd9c8=

Java原解密代码

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class MainTest {
    static public void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {
        byte[] aesnonce    = Base64.getDecoder().decode("nsHTfsEFKyVytEk2");
        byte[] aeskeybytes = Base64.getDecoder().decode("2hn3S9IsCTut7Hr9SX/7Pg==");
        byte[] crypted     = Base64.getDecoder().decode("w0ehWquycruj2KGkRES4M8pc6w4ZM+9HyI+KOXgqybmiYIuU1nsjZJwisZprxx2mczP280ZT5KlCXzSX0h24136m708N8sbX6m+5QlDVa73/r9dRyfSzFeByi51NqVm35wP4oHdxYW5iVx9P8iFFpcYd9c8=");
                
        SecretKeySpec secretKey = new SecretKeySpec(aeskeybytes, "AES");

        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, aesnonce);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);  // 可正常解密
//      cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);  // 报错

        ByteArrayInputStream inputStream = new ByteArrayInputStream(crypted);
        CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
        
        byte[] plaintext = cipherInputStream.readAllBytes();
        System.out.print( new String(plaintext) );
    }
}

问题原因

核心在于AES-GCM加密输出格式不匹配:

  • PyCryptodome的AES-GCM.encrypt()方法仅返回密文,128位认证标签(Tag)需通过cipher.digest()单独获取;
  • Java的AES/GCM/NoPadding在DECRYPT_MODE下,默认期望输入为密文 + 128位认证标签(代码中GCMParameterSpec(128, aesnonce)指定了标签长度);
  • 当前Python仅输出密文,未附加标签,导致Java解密时无法找到有效校验标签,抛出Tag mismatch;
  • Java切换为ENCRYPT_MODE时,CipherInputStream的错误用法跳过了标签校验,因此能解析明文,但这不符合GCM安全规范。

解决方法

修改Python代码,将密文与认证标签拼接后再进行Base64编码,确保Java端能读取到完整的加密数据(密文+标签),从而在DECRYPT_MODE下正常解密。

修改后的Python加密代码

import base64
from Crypto.Cipher import AES

aesnonce  = base64.b64decode(b"nsHTfsEFKyVytEk2")
aeskey    = base64.b64decode(b"2hn3S9IsCTut7Hr9SX/7Pg==")
cipher    = AES.new(aeskey, AES.MODE_GCM, nonce=aesnonce)

plaintext = b'''Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore.'''
crypted   = cipher.encrypt(plaintext)
# 拼接密文和128位认证标签
full_encrypted_data = crypted + cipher.digest()

print(base64.b64encode(full_encrypted_data))

验证

将修改后的Python输出的Base64字符串替换到Java代码的crypted变量中,启用cipher.init(Cipher.DECRYPT_MODE, ...)即可正常解密,无需修改Java代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:47:02