PyCryptodome AES-CBC解密报错:16字节边界对齐及填充错误
问题分析与解决方案
核心问题根源
CBC模式下AES要求数据长度必须是16字节(AES块大小)的整数倍,你的两个错误本质是加密和解密的填充逻辑不匹配,或是加密后的数据在存储/读取时因编码问题损坏,导致长度或内容异常。
常见错误点排查
- 加密时未用标准填充方式:如果加密时没给明文做PKCS7填充,密文长度不符合块大小要求,解密就会报16字节边界错误;若加密填充方式和解密时的去填充逻辑不一致,就会触发“Padding is incorrect”。
- 二进制数据处理不当:加密后的密文是二进制流,直接存为字符串会乱码,导致数据长度改变或内容损坏,解密自然失败。
- 解密时手动填充:手动给密文补字节完全错误,CBC解密的正确流程是先确保密文完整,再用对应方式自动去除加密时添加的填充。
修正后的代码示例
标准加密函数
from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from Crypto.Random import get_random_bytes import base64 def encrypt_data(plaintext, master_password): # 用主密码生成密钥(生产环境建议用PBKDF2HMAC加盐派生,这里简化示例) key = master_password.encode('utf-8')[:32] # AES-256用32字节密钥,按需调整 iv = get_random_bytes(16) # CBC模式必须用随机IV,不能固定 cipher = AES.new(key, AES.MODE_CBC, iv) # 对明文做PKCS7填充后加密 ciphertext = cipher.encrypt(pad(plaintext.encode('utf-8'), AES.block_size)) # 将IV和密文一起转base64,方便存储为字符串 return base64.b64encode(iv + ciphertext).decode('utf-8')
对应解密函数
def decrypt_data(ciphertext_b64, master_password): key = master_password.encode('utf-8')[:32] # 解码base64,分离IV和密文 raw_data = base64.b64decode(ciphertext_b64) iv = raw_data[:16] ciphertext = raw_data[16:] cipher = AES.new(key, AES.MODE_CBC, iv) # 解密后自动去除PKCS7填充 try: plaintext = unpad(cipher.decrypt(ciphertext), AES.block_size) return plaintext.decode('utf-8') except ValueError: raise Exception("主密码错误或数据已损坏")
主函数调用示例
def main(): master_pwd = "your_strong_master_pwd" # 加密测试 encrypted_str = encrypt_data("your_email_password", master_pwd) print("加密结果:", encrypted_str) # 解密测试 try: decrypted_str = decrypt_data(encrypted_str, master_pwd) print("解密结果:", decrypted_str) except Exception as e: print("解密失败:", str(e)) if __name__ == "__main__": main()
关键注意事项
- 密钥生成:示例直接截取主密码字节是简化处理,实际必须用
PBKDF2HMAC这类密钥派生函数,加入随机盐值和足够迭代次数,防止暴力破解。 - IV管理:每次加密必须生成随机IV,且要和密文一起存储,固定IV会严重降低加密安全性。
- 数据完整性:建议加入HMAC校验,解密前先验证密文完整性,避免填充错误被用作攻击手段。
内容的提问来源于stack exchange,提问作者vghbjc
相关产品推荐
相关产品推荐

