Node.js AES-256-GCM加密数据无法被Java解密问题求助
解决Node.js AES-256-GCM加密后Java解密报AEADBadTagException的问题
你的Java解密代码存在几个关键错误,直接导致标签验证失败,下面是问题分析和修复方案:
问题点
- 缺失Base64解码:Node.js输出的密文、标签、IV都是Base64编码后的字符串,但Java端直接调用
getBytes()将这些字符串转成字节——这相当于把Base64字符的UTF-8编码当成了原始加密字节,完全不符合要求,必须先对Base64字符串解码。 - GCM标签处理错误:Java里用
cipher.update(tag)传递认证标签是错误的逻辑,GCM模式下的认证标签需要在doFinal阶段处理,不能通过update方法传入。 - 密钥编码未统一:Java端
KEY.getBytes()未指定编码,如果Node.js的密钥是UTF-8编码的字符串,Java默认编码可能与之不匹配,导致密钥字节不一致。
修复后的Java解密代码
import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AESDecryptor { // 替换成和Node.js端一致的32字节密钥,保持UTF-8编码 private static final String KEY = "your-32-byte-secret-key-here"; public static String decrypt(String encryData) throws Exception { String[] parts = encryData.split("\\."); // 对Base64字符串解码,还原加密时的原始字节 byte[] encryptedBytes = Base64.getDecoder().decode(parts[0]); byte[] tagBytes = Base64.getDecoder().decode(parts[1]); byte[] ivBytes = Base64.getDecoder().decode(parts[2]); GCMParameterSpec gcmSpec = new GCMParameterSpec(128, ivBytes); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); // 指定UTF-8编码,确保密钥字节和Node.js端完全一致 SecretKeySpec secretKey = new SecretKeySpec(KEY.getBytes("UTF-8"), "AES"); cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec); // 先处理密文,再传入标签完成解密和验证 byte[] partialDecrypt = cipher.update(encryptedBytes); byte[] finalDecrypt = cipher.doFinal(tagBytes); // 合并解密后的字节数组 byte[] result = new byte[partialDecrypt.length + finalDecrypt.length]; System.arraycopy(partialDecrypt, 0, result, 0, partialDecrypt.length); System.arraycopy(finalDecrypt, 0, result, partialDecrypt.length, finalDecrypt.length); return new String(result, "UTF-8"); } }
额外注意事项
- 密钥必须是32字节(256位):AES-256要求密钥长度严格为32字节,Node.js里的
key参数如果是字符串,要确保它的UTF-8编码结果是32字节,否则Node.js会自动截断,导致Java端密钥不匹配。 - 全程统一UTF-8编码:所有涉及字符串转字节的操作(密钥、明文、解密结果)都要指定UTF-8,避免编码差异导致的字节不一致。
- IV长度符合标准:你Node.js里使用的12字节IV是GCM模式推荐的长度,Java端无需修改这部分逻辑。
内容的提问来源于stack exchange,提问作者Genos
相关产品推荐
相关产品推荐

