You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

问题根源及解决方法

核心问题

  1. Nonce不匹配:AES-GCM要求解密必须使用与加密完全相同的nonce,但你在解密代码中重新创建了cipher = AES.new(key,AES.MODE_GCM)生成新的随机nonce,导致解密时无法正确还原明文。
  2. 加密值存储损坏:直接复制打印的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:40:15