Python中AES.MODE_GCM模式解密时出现填充错误问题
解密CSV中AES-GCM加密值时出现Padding错误的问题
我将一个整数加密后写入CSV,尝试读取CSV中的加密值解密时,遇到了Padding错误,具体细节如下:
加密代码
from Crypto.Random import get_random_bytes from Crypto.Cipher import AES from Crypto.Protocol.KDF import scrypt from Crypto.Util.Padding import pad,unpad from random import randrange from Crypto.Hash import SHA256 import binascii import pandas as pd import numpy as np import hashlib BUFFER_SIZE = 1024 * 1024 # 每次读取、加密、写入的字节大小 password = 'QWERTY123' salt = 'QWERTY123' print("Salt is created") key = scrypt(password, salt, key_len=32, N=2**17, r=8, p=1) # 用密码和盐生成密钥 print("Key is created",key) cipher = AES.new(key, AES.MODE_GCM) # 创建加密用的Cipher对象 nonce = cipher.nonce print("Nonce is created") print ("Key is :", type(key)) print ("Nonce is :", type(nonce)) val=100 plain_text =val.to_bytes(2, 'big') print("Plaintext is ",plain_text) cipher_decrypt= AES.new(key, AES.MODE_GCM, nonce=nonce) cipher_text = cipher.encrypt(pad(plain_text,AES.block_size)) print("Encrypted text:", cipher_text)
加密输出
Salt is created Key is created b'\x1eev\xb1\x95,\xa7\xb2&Dk\x12\x88n\xcf\xe1\xe3\xda\xf13p\x8f;\x02>\x99\x82L+\x9a\x8a$' Nonce is created Key is : <class 'bytes'> Nonce is : <class 'bytes'> Plaintext is b'\x00d' Encrypted text: b'\x02(\x0bM\x00I\x07M\xc7J;\xdc\xe7h\xd5\x00'
操作说明
我将加密后的文本值复制粘贴到CSV文件中,解密时使用相同的密码和盐(已知此做法不推荐,但为生成相同密钥必须这么做)。
解密代码
from Crypto.Random import get_random_bytes from Crypto.Cipher import AES from Crypto.Protocol.KDF import scrypt from Crypto.Util.Padding import pad,unpad from random import randrange from Crypto.Hash import SHA256 import binascii import pandas as pd import numpy as np import hashlib import ast BUFFER_SIZE = 1024 * 1024 # 每次读取、加密、写入的字节大小 password = 'QWERTY123' salt = 'QWERTY123' print("Salt is created") key = scrypt(password, salt, key_len=32, N=2**17, r=8, p=1) # 用密码和盐生成密钥 print("Key is created",key) cipher = AES.new(key,AES.MODE_GCM) # 创建加密用的Cipher对象 nonce = cipher.nonce print("Nonce is created") print ("Key is :", type(key)) print ("Nonce is :", type(nonce)) cipher_decrypt= AES.new(key, AES.MODE_GCM, nonce=nonce) input_file = pd.read_csv('/path/random.csv') encrypt_val=input_file.iat[0,1] print("Remaining are",encrypt_val) print(type(encrypt_val)) a=ast.literal_eval(encrypt_val) print(a) print(type(a)) text = unpad(cipher_decrypt.decrypt(a),AES.block_size) print(text) print(type(text)) b=ast.literal_eval(text)
解密错误输出
Salt is created Key is created b'\x1eev\xb1\x95,\xa7\xb2&Dk\x12\x88n\xcf\xe1\xe3\xda\xf13p\x8f;\x02>\x99\x82L+\x9a\x8a$' Nonce is created Key is : <class 'bytes'> Nonce is : <class 'bytes'> Remaining are b"H\x13\x0c\xa0J\x07\x98<QN])z'S\xdc" <class 'str'> b"H\x13\x0c\xa0J\x07\x98<QN])z'S\xdc" <class 'bytes'> --------------------------------------------------------------------------- ValueError Traceback (most recent call last) Untitled-2.ipynb Cell 1 in <module> 36 print(a) 37 print(type(a)) ---> 38 text = unpad(cipher_decrypt.decrypt(a),AES.block_size) 39 print(text) 40 print(type(text)) File /opt/homebrew/lib/python3.9/site-packages/Crypto/Util/Padding.py:92, in unpad(padded_data, block_size, style) 90 padding_len = bord(padded_data[-1]) 91 if padding_len<1 or padding_len>min(block_size, pdata_len): ---> 92 raise ValueError("Padding is incorrect.") 93 if style == 'pkcs7': 94 if padded_data[-padding_len:]!=bchr(padding_len)*padding_len: ValueError: Padding is incorrect.
问题根源及解决方法
核心问题
- Nonce不匹配:AES-GCM要求解密必须使用与加密完全相同的nonce,但你在解密代码中重新创建了
cipher = AES.new(key,AES.MODE_GCM)生成新的随机nonce,导致解密时无法正确还原明文。 - 加密值存储损坏:直接复制打印的bytes字符串到CSV会导致数据失真——打印的bytes是字符串表示(如
b'\x02(...)'),转义字符在复制或CSV存储过程中可能被篡改,读取后得到的bytes与原始加密值不一致。
修正步骤
第一步:修正加密流程,正确保存解密所需参数
将nonce、密文、GCM认证标签编码为Base64字符串(二进制数据的安全存储方式),并写入CSV:
# 加密代码末尾添加以下内容 import base64 # 将二进制数据编码为Base64字符串 nonce_b64 = base64.b64encode(nonce).decode('utf-8') ciphertext_b64 = base64.b64encode(cipher_text).decode('utf-8') tag_b64 = base64.b64encode(cipher.digest()).decode('utf-8') # 保存到CSV df = pd.DataFrame({ 'nonce': [nonce_b64], 'ciphertext': [ciphertext_b64], 'tag': [tag_b64] }) df.to_csv('encrypted_data.csv', index=False)
第二步:修正解密流程,使用正确参数
读取CSV中的Base64字符串,解码回二进制,并用加密时的nonce和认证标签解密:
# 替换原解密代码为以下内容 from Crypto.Cipher import AES from Crypto.Protocol.KDF import scrypt from Crypto.Util.Padding import unpad import base64 import pandas as pd password = 'QWERTY123' salt = 'QWERTY123' key = scrypt(password, salt, key_len=32, N=2**17, r=8, p=1) # 读取CSV中的加密参数 input_file = pd.read_csv('encrypted_data.csv') nonce = base64.b64decode(input_file['nonce'][0]) ciphertext = base64.b64decode(input_file['ciphertext'][0]) tag = base64.b64decode(input_file['tag'][0]) # 创建解密Cipher对象,传入加密时的nonce cipher_decrypt = AES.new(key, AES.MODE_GCM, nonce=nonce) try: # GCM模式需验证认证标签,防止数据篡改 plaintext_padded = cipher_decrypt.decrypt_and_verify(ciphertext, tag) # 去除填充并转换回整数 plaintext = unpad(plaintext_padded, AES.block_size) val = int.from_bytes(plaintext, 'big') print("解密结果:", val) except ValueError as e: print("解密失败:", e)
额外注意事项
- AES-GCM的nonce必须每次加密唯一,但解密时必须与加密时的nonce完全一致,绝对不能在解密时重新生成。
- 二进制数据禁止直接以字符串形式存储/复制,必须用Base64、Hex等编码转换为可打印字符串。
- 生产环境中不要硬编码密码和盐,应使用随机生成的盐并与密文一起存储。
内容的提问来源于stack exchange,提问作者rishab ajain445
相关产品推荐
相关产品推荐

