AES-256 GCM解密报错MAC check failed问题求助
解决AES-256 GCM解密MAC校验失败及乱码问题
MAC校验失败(ValueError: MAC check failed)的核心原因及排查方向
- 密钥长度不匹配:AES-256要求密钥必须是32字节(256位),如果用了16字节(AES-128)或24字节(AES-192)的密钥,会直接导致校验失败。
- IV/Nonce错误:GCM模式的IV(Nonce)必须与加密时完全一致,且通常为12字节(GCM推荐长度)。如果JSON中的IV是Base64/十六进制编码,必须正确解码为bytes,不能用字符串直接传入。
- Tag值错误:Tag是GCM的完整性校验值,必须和加密时生成的完全一致。注意JSON中的Tag是否经过编码(如Base64),解码错误会直接触发校验失败。
- 附加数据(AD)不一致:如果加密过程中使用了附加数据(Authenticated Data),解密时必须传入完全相同的附加数据,否则MAC校验不通过。
直接使用decrypt方法出现乱码的原因
GCM模式的decrypt方法不会自动校验Tag,跳过校验后输出的内容可能是被篡改的明文,或者因为密钥/IV参数错误导致解密出的字节本身就是无效的,最终解码为乱码。必须使用decrypt_and_verify方法才能同时完成解密和完整性校验。
正确的解密代码示例
假设JSON中的content、iv、tag均为Base64编码(如果是十六进制,替换为bytes.fromhex()):
from Crypto.Cipher import AES import base64 import json def decrypt_aes256_gcm(encrypted_json_str, aes_key): # 解析JSON数据 encrypted_data = json.loads(encrypted_json_str) # 解码加密字段为bytes类型 ciphertext = base64.b64decode(encrypted_data["content"]) iv = base64.b64decode(encrypted_data["iv"]) tag = base64.b64decode(encrypted_data["tag"]) # 验证密钥长度合法性 if len(aes_key) != 32: raise ValueError("AES-256 requires a 32-byte key") # 初始化GCM密码器 cipher = AES.new(aes_key, AES.MODE_GCM, nonce=iv) # 若加密时使用了附加数据,需先调用update传入对应数据 # cipher.update(b"your_authenticated_data_here") try: # 解密并校验Tag plaintext_bytes = cipher.decrypt_and_verify(ciphertext, tag) # 转换为字符串(若加密时未做填充,无需unpad) return plaintext_bytes.decode("utf-8") except ValueError as e: raise RuntimeError(f"Decryption failed: {str(e)}") # 使用示例 encrypted_msg = '{"content": "abc123...", "iv": "def456...", "tag": "ghi789..."}' # 32字节的AES密钥,注意必须是bytes类型 aes_256_key = b"your_32_byte_secret_key_12345678" try: plaintext = decrypt_aes256_gcm(encrypted_msg, aes_256_key) print(plaintext) except Exception as e: print(e)
额外排查要点
- 确认加密端是否对明文做了填充:如果加密时用了PKCS7填充,解密后需要调用
unpad(plaintext_bytes, AES.block_size)去除填充。 - 检查字符编码:明文通常是UTF-8编码,若加密端用了其他编码(如GBK),需对应调整解码方式。
- 避免密钥/IV的字符串编码错误:不要直接用
str(key)转换,确保密钥是原生bytes类型。
内容的提问来源于stack exchange,提问作者mlav
相关产品推荐
相关产品推荐

