
本文旨在解决在使用Python的`Crypto`库实现密码管理器时遇到的"Padding is incorrect"错误。通过详细的代码示例和解释,我们将深入探讨AES加密中的Padding机制,并提供一种可靠的解决方案,确保密码能够正确地加密和解密,从而安全地存储在文件中。
在使用Python的Crypto库进行AES加密时,"Padding is incorrect"错误是一个常见的陷阱。这通常发生在解密过程中,表明数据在加密时使用的Padding方式与解密时期望的不一致。本教程将深入探讨这个问题,并提供一个清晰的解决方案。
理解Padding
AES(Advanced Encryption Standard)算法要求加密的数据长度必须是块大小的倍数。对于AES,块大小通常是16字节。如果明文数据的长度不是16的倍数,就需要进行Padding,即填充数据使其长度符合要求。
常见的Padding方案包括PKCS7。在PKCS7中,填充的字节的值等于填充的字节数。例如,如果需要填充3个字节,那么填充的字节的值都将是\x03。
问题分析
原始代码中使用了Crypto.Util.Padding.pad和Crypto.Util.Padding.unpad进行Padding和Unpadding。问题在于,当密码管理器多次运行时,由于IV(Initialization Vector)和密钥的管理不当,导致解密时无法正确地移除Padding,从而引发"Padding is incorrect"错误。
主要更新介绍: 完美整合Discuz!论坛,实现一站式登陆、退出、注册; 同步所有会员资料; 新增购物车功能,商品购买更加方便、快捷; 新增部分快捷菜单,网站访问更加方便; 限制首页商品、店铺标题显示长度; 修正会员后台管理不能更改密码的错误; 完善商品显示页面所有功能链接; 修正后台标签管理部分错误; 修正前台学校列表不按后台顺序显示的错误; 修正搜索功能中学校名称过长导致显示紊乱的现象; 修正
解决方案:自定义Padding和Unpadding
为了更可靠地处理Padding,我们可以使用自定义的Padding和Unpadding函数,并结合SHA256哈希算法处理密钥。以下是修改后的代码:
import re
import random
import string
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import hashlib
def password_generator(size=10):
if size <= 8:
print("Size must be at least 4")
return None
password = []
while len(password) < size:
password.append(random.choice(string.ascii_lowercase))
if len(password) < size:
password.append(random.choice(string.ascii_uppercase))
if len(password) < size:
password.append(random.choice(string.digits))
if len(password) < size:
password.append(random.choice(string.punctuation))
random.shuffle(password)
return ''.join(password)
def password_checker(password):
if len(password) >= 8:
if bool(re.match(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z\d])', password)):
print("The password is strong")
else:
print("The password is weak")
else:
print("You have entered a short or invalid password.")
generated_password = password_generator()
print(generated_password)
password_checker(generated_password)
class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key).digest()
def encrypt_data(self, iv, raw):
raw = self._pad(raw)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return cipher.iv, iv + cipher.encrypt(raw.encode())
def decrypt_data(self, iv, enc):
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return AESCipher._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s)-1:])]
iv = get_random_bytes(16)
key = get_random_bytes(32)
Cipher = AESCipher(key)
iv, encrypted_password = Cipher.encrypt_data(iv, generated_password)
print(f"Encrypted password: {encrypted_password}")
decrypted_password = Cipher.decrypt_data(iv, encrypted_password)
print(f"Decrypted password: {decrypted_password}")
with open(
'Password.txt',
'a', encoding='utf-8') as f:
f.write(f"{iv.hex()}:{encrypted_password.hex()}\n")
with open(
'Password.txt',
'r', encoding='utf-8') as f:
for line in f.readlines():
line = line.strip()
iv, encrypted_password = line.split(':')
decrypted_password = Cipher.decrypt_data(bytes.fromhex(iv), bytes.fromhex(encrypted_password))代码解释:
- AESCipher类: 封装了AES加密和解密操作。
- __init__(self, key): 构造函数,接收密钥并使用SHA256哈希算法对其进行处理,生成一个安全的密钥。
- encrypt_data(self, iv, raw): 加密数据,先进行Padding,然后使用AES加密。
- decrypt_data(self, iv, enc): 解密数据,先使用AES解密,然后移除Padding。
- _pad(self, s): 自定义Padding函数,使用PKCS7方案进行Padding。
- _unpad(self, s): 自定义Unpadding函数,移除PKCS7 Padding。
改进建议
- 密钥管理: 在实际应用中,密钥的安全性至关重要。不要将密钥硬编码在代码中。考虑使用更安全的密钥管理方案,例如密钥派生函数(KDF)或硬件安全模块(HSM)。
- 错误处理: 在解密过程中,添加适当的错误处理机制,例如捕获ValueError异常,以便在Padding不正确时能够优雅地处理错误。
- 数据完整性校验: 为了确保数据的完整性,可以考虑使用HMAC(Hash-based Message Authentication Code)来验证加密数据的完整性。
总结
通过自定义Padding和Unpadding函数,并结合SHA256哈希算法处理密钥,我们可以有效地解决密码管理器中的"Padding is incorrect"错误。同时,加强密钥管理和错误处理,可以进一步提高密码管理器的安全性。记住,安全性是一个持续改进的过程,需要不断地学习和实践。









