Kotlin加密密文Java解密时触发javax.crypto.AEADBadTagException标签不匹配
解决AES/GCM解密时的
javax.crypto.AEADBadTagException: Tag mismatch!异常 问题场景
从Kotlin应用向Java应用发送AES/GCM加密后的密文,Java端解密时触发以下异常:
Exception in thread "main" javax.crypto.AEADBadTagException: Tag mismatch! at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:620) at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1116) at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1053) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853) at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) at javax.crypto.Cipher.doFinal(Cipher.java:2168) at crypto.CryptoCore.c3andC4(CryptoCore.java:61) at PokusMain.main(PokusMain.java:197)
两端代码
Kotlin加密代码
fun getFinalCipher(): String { //generating key from some parameters var ukeyString = hash(appParameters.userKey + "user" + userCryptogram.nonce.toString() + receiverCryptogram.nonce.toString(), "SHA-1") if (ukeyString != null) { ukeyString = ukeyString!!.substring(0,16) } val command = "unlock" val ukey: SecretKey = SecretKeySpec(ukeyString!!.toByteArray(), "AES") val parameterSpec = GCMParameterSpec(128, getUserIv()) //IV has the length of 12 val cipherC3 = Cipher.getInstance("AES/GCM/NoPadding") cipherC3.init(Cipher.ENCRYPT_MODE, ukey, parameterSpec) val plaintext = appParameters.atu + command.toByteArray() var ciphertext = cipherC3.doFinal(plaintext) val ciphertextHex = ciphertext.toHex() return ciphertextHex }
Java解密代码
public void c3andC4(String ciphertextHex) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException { byte[] ciphertext = decodeHexString(ciphertextHex); String userKey = hash(obuParameters.getDriverKey() + userCryptogram.getHatu(), "SHA-1"); String ukeyString = hash(userKey + "user" + userCryptogram.getNonce() + receiverCryptogram.getNonce(),"SHA-1"); userKey= userKey.substring(0, 16); ukeyString = ukeyString.substring(0,16); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); SecretKey ukey = new SecretKeySpec(ukeyString.getBytes(),"AES"); GCMParameterSpec parameterSpec = new GCMParameterSpec(128, userCryptogram.getIv()); //IV has the length of 12 cipher.init(Cipher.DECRYPT_MODE,ukey, parameterSpec); byte[] decryptedMessage = cipher.doFinal(ciphertext); //this line throws exception }
问题分析
Tag mismatch!是AES/GCM模式的典型异常,说明解密端的密钥、IV、密文(含认证标签)三者中至少有一个与加密端不一致。从代码对比看,核心问题是:
密钥生成逻辑完全不一致
- Kotlin端直接用原始的
appParameters.userKey拼接字符串后做SHA-1,取前16字节作为密钥 - Java端先对
obuParameters.getDriverKey() + userCryptogram.getHatu()做SHA-1得到userKey,再用这个hash结果拼接字符串生成密钥
这导致两端AES密钥完全不同,是触发异常的主要原因。
- Kotlin端直接用原始的
其他潜在问题:
- IV一致性:需确认Kotlin的
getUserIv()返回的字节数组与Java的userCryptogram.getIv()完全一致,避免toString或编码转换导致的差异 - Hex编解码:Kotlin的
toHex()方法与Java的decodeHexString()需采用相同规则(如大小写、无分隔符) - 明文拼接:Kotlin端
appParameters.atu + command.toByteArray()如果atu是String,需确认其字节编码(如UTF-8)与解密端预期一致
- IV一致性:需确认Kotlin的
修复建议
对齐密钥生成逻辑
修改Java端代码,去掉多余的hash步骤,直接用原始的obuParameters.getDriverKey()生成密钥:// 移除这一行:String userKey = hash(obuParameters.getDriverKey() + userCryptogram.getHatu(), "SHA-1"); String ukeyString = hash(obuParameters.getDriverKey() + "user" + userCryptogram.getNonce() + receiverCryptogram.getNonce(),"SHA-1"); ukeyString = ukeyString.substring(0,16);验证IV一致性
打印两端IV的字节数组十六进制值,确认完全相同,避免类型转换(如Long转String再转字节)导致的差异。确认Hex编解码逻辑
确保Kotlin的toHex()生成纯十六进制字符串(无空格/分隔符),Java的decodeHexString()能正确解析对应大小写格式。
内容的提问来源于stack exchange,提问作者F. Texl
相关产品推荐
相关产品推荐

