AES-GCM解密报错:Authentication tag does not match tag length求助
解决AES-GCM解密时"Authentication tag does not match tag length"错误
核心问题是你误解了node-forge中AES-GCM的标签处理逻辑:GCM的认证标签不会自动附加到密文输出里,cipher.finish()执行后,标签会单独存在于cipher.tag属性中。你当前只存储了IV和密文,解密时缺少必要的标签校验,所以触发错误。
修复步骤
1. 加密函数修改:追加认证标签到存储内容中
加密时需要把IV、密文、标签三者拼接后再编码为Base64:
import forge from 'node-forge'; // Convert hex to ByteStringBuffer const hexToBytes = (hex) => forge.util.createBuffer(forge.util.hexToBytes(hex)); // 加密函数修改版 export const encryptDataWithSessionKey = (data, sessionKeyHex) => { console.log('data during encryption: ', data); try { const sessionKey = hexToBytes(sessionKeyHex); const iv = forge.random.getBytesSync(12); // 96 bits IV for GCM console.log('iv during encryption: ', iv); const dataBytes = forge.util.encodeUtf8(data); const cipher = forge.cipher.createCipher('AES-GCM', sessionKey); console.log('cipher during encryption: ', cipher); cipher.start({ iv, tagLength: 128 }); cipher.update(forge.util.createBuffer(dataBytes)); cipher.finish(); // 取出密文和认证标签 const encryptedBytes = cipher.output.getBytes(); const tagBytes = cipher.tag.getBytes(); // 新增:获取GCM认证标签 console.log('encrypted during encryption: ', encryptedBytes, encryptedBytes.length); console.log('tag during encryption: ', tagBytes, tagBytes.length); // 拼接IV + 密文 + 标签,再转Base64 const encryptedBase64 = forge.util.encode64(iv + encryptedBytes + tagBytes); // 修改:加入标签 console.log('encryptedBase64 during encryption: ', encryptedBase64, encryptedBase64.length); return encryptedBase64; } catch (error) { console.error('Error encrypting data:', error); throw error; } };
2. 解密函数修改:拆分IV、密文、标签并传入解密器
解密时需要从解码后的字节中拆分出IV(前12字节)、密文(中间部分)、标签(最后16字节,对应128位tagLength),然后在启动解密器时传入标签:
// 解密函数修改版 export const decryptDataWithSessionKey = (encryptedData, sessionKeyHex) => { console.log('encryptedData during decryption: ', encryptedData); try { const sessionKey = hexToBytes(sessionKeyHex); const encryptedBytesWithIVTag = forge.util.decode64(encryptedData); // 拆分IV、密文、标签 const iv = encryptedBytesWithIVTag.slice(0, 12); const tag = encryptedBytesWithIVTag.slice(-16); // 新增:取出最后16字节作为标签 const encryptedBytes = encryptedBytesWithIVTag.slice(12, -16); // 修改:截取中间部分作为密文 console.log('iv during decryption: ', iv); console.log('tag during decryption: ', tag); console.log('encryptedBytes during decryption: ', encryptedBytes, encryptedBytes.length); const decipher = forge.cipher.createDecipher('AES-GCM', sessionKey); console.log('decipher during decryption: ', decipher); console.log(1); // 修改:启动解密器时传入tag参数 decipher.start({ iv, tagLength: 128, tag: forge.util.createBuffer(tag) }); decipher.update(forge.util.createBuffer(encryptedBytes)); console.log(2); const result = decipher.finish(); console.log(3, result); const decrypted = decipher.output.getBytes(); const decryptedData = forge.util.decodeUtf8(decrypted); return decryptedData; } catch (error) { console.error('Error decrypting data:', error); throw error; } };
关键修改点说明
- 加密时必须把
cipher.tag的字节内容追加到密文后,一起编码存储 - 解密时要从总字节中拆分出标签,通过
tag参数传入decipher.start(),node-forge的GCM实现不会自动从密文末尾读取标签
内容的提问来源于stack exchange,提问作者MD DANISH
相关产品推荐
相关产品推荐

