AES.MODE_EAX加密遇UnicodeDecodeError问题求助
解决AES-EAX加解密时UnicodeDecodeError及密文不一致问题
问题核心原因
- Nonce不一致:你的代码中
nonce = uuid.uuid4().bytes是全局动态生成的,每次程序重启或重新运行都会生成新的nonce。如果加密后更换了运行环境/重启程序,解密时使用的nonce和加密时完全不同,导致解密出的字节流是乱码,无法通过UTF-8解码。你提到“固定使用nonce”,但当前逻辑并没有真正固定nonce,这是触发错误的核心原因。 - 多余的手动填充:AES-EAX属于流加密模式,不需要像CBC/ECB模式那样手动填充数据到块大小。你手动添加空格填充的操作不仅多余,还可能引入不必要的字符处理风险。
- 未利用EAX的认证标签:EAX模式自带消息认证功能,你没有存储和验证认证标签,无法确保密文在存储过程中没有被篡改,这也可能加剧解密乱码问题。
修正步骤与代码实现
方案1:固定nonce(适用于需要相同明文生成相同密文的查询场景)
注意:固定nonce会降低加密安全性,仅适用于对安全性要求较低且需支持密文查询的场景。
import binascii from Crypto.Cipher import AES # 固定nonce(可自定义为任意16字节值) FIXED_NONCE = b'\x12\x34\x56\x78\x90\xab\xcd\xef\x12\x34\x56\x78\x90\xab\xcd\xef' STR_KEY = "wq5RdHHfzCW1/2eE" # 16字符对应AES-128密钥长度 def sym_encrypt(data): key = STR_KEY.encode("utf-8") cipher = AES.new(key, AES.MODE_EAX, nonce=FIXED_NONCE) ciphertext, tag = cipher.encrypt_and_digest(data.encode("utf-8")) # 密文与认证标签用冒号分隔,一起转十六进制存储 return f"{ciphertext.hex()}:{tag.hex()}" def sym_decrypt(data): key = STR_KEY.encode("utf-8") ciphertext_hex, tag_hex = data.split(":") ciphertext = binascii.unhexlify(ciphertext_hex) tag = binascii.unhexlify(tag_hex) cipher = AES.new(key, AES.MODE_EAX, nonce=FIXED_NONCE) plaintext = cipher.decrypt_and_verify(ciphertext, tag) return plaintext.decode("utf8")
方案2:动态生成nonce并与密文绑定(更安全)
此方案每个密文对应唯一nonce,避免重复使用nonce的安全风险,但相同明文加密结果不同,无法直接基于密文查询。
import binascii import uuid from Crypto.Cipher import AES STR_KEY = "wq5RdHHfzCW1/2eE" # 16字符对应AES-128密钥长度 def sym_encrypt(data): key = STR_KEY.encode("utf-8") nonce = uuid.uuid4().bytes cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) ciphertext, tag = cipher.encrypt_and_digest(data.encode("utf-8")) # nonce、密文、认证标签用冒号分隔转十六进制存储 return f"{nonce.hex()}:{ciphertext.hex()}:{tag.hex()}" def sym_decrypt(data): key = STR_KEY.encode("utf-8") nonce_hex, ciphertext_hex, tag_hex = data.split(":") nonce = binascii.unhexlify(nonce_hex) ciphertext = binascii.unhexlify(ciphertext_hex) tag = binascii.unhexlify(tag_hex) cipher = AES.new(key, AES.MODE_EAX, nonce=nonce) plaintext = cipher.decrypt_and_verify(ciphertext, tag) return plaintext.decode("utf8")
验证说明
- 方案1中,相同明文每次加密生成相同密文,满足查询需求,但需承担固定nonce的安全风险。
- 方案2遵循加密安全最佳实践,每个密文对应独立nonce,安全性更高,但无法直接通过密文匹配查询相同明文。
内容的提问来源于stack exchange,提问作者Kakedis
相关产品推荐
相关产品推荐

