Java解密PHP openssl_encrypt生成的AES-128-GCM密文出现Tag mismatch错误
问题原因及修复方案
你遇到的AEADBadTagException: Tag mismatch异常核心是加解密两侧的参数或逻辑不匹配,具体问题和修复方法如下:
1. 密钥字节生成不规范
Java代码中调用getBytes()时未显式指定字符集,会依赖运行环境的默认字符集,一旦和PHP侧的字符串字节处理逻辑不一致,会导致密钥不匹配,最终tag校验失败。
修复:显式指定字符集获取密钥字节,保证和PHP侧一致:
// 推荐用UTF-8,如果PHP侧是单字节处理也可以用StandardCharsets.ISO_8859_1 SecretKeySpec secretKeySpec = new SecretKeySpec("jKtbuVSQlhfbxF0zVjZh1839DLTNSvS5".substring(0,16).getBytes(StandardCharsets.UTF_8), "AES");
2. 算法与密钥长度匹配校验
你PHP侧指定的是aes-128-gcm,对应需要16字节密钥,Java侧截断前16字节的逻辑是合理的,但需要确认PHP侧没有因为传入32字节密钥自动切换为AES-256加密:
- 如果确认PHP侧确实用的是AES-128,保留截断逻辑即可
- 如果实际PHP侧用的是AES-256,Java侧不需要截断密钥,直接用完整32字节的密钥即可
3. 编码逻辑优化(可选)
当前PHP侧openssl_encrypt用$options=0返回Base64编码密文的逻辑是对的,为了避免后续编码歧义,建议统一改为先获取原始二进制密文再Base64编码:
$ciphertext = base64_encode(openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag));
调试建议
如果修改后还是报错,可以分别打印PHP侧和Java侧的密钥、iv、tag、密文的十六进制值,逐字节对比,就能快速定位不匹配的参数。
内容的提问来源于stack exchange,提问作者Simon Kuo
相关产品推荐
相关产品推荐

