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

使用Python和Pycryptodome实现输入字符串加解密失败问题排查

解决Pycryptodome中CBC模式的"Data must be padded to 16 byte boundary"错误

你遇到的ValueError: Data must be padded to 16 byte boundary in CBC mode错误,核心原因有三个:

  • CBC模式要求加密和解密使用相同的初始化向量(IV),原代码每次创建AES对象时自动生成新IV,导致解密时无法还原正确数据,进而触发填充校验失败。
  • 密文是二进制数据,直接通过input()获取后用encode()转换会破坏原始二进制结构,导致解密时数据长度或内容不符合要求。
  • 代码中salt被注释,PBKDF2需要随机salt生成稳定密钥,缺失salt会导致密钥生成逻辑异常。

修正方案

  1. 统一IV的使用:加密时生成随机IV,将IV与密文绑定(比如拼接后转Base64),解密时拆分出IV再使用。
  2. 二进制数据用Base64编码:把二进制的IV、密文转成Base64字符串,避免输入输出时的数据损坏。
  3. 补全随机salt生成:使用Crypto.Random.get_random_bytes生成随机salt,且加密时需将salt与IV、密文一同保存,确保解密时能生成相同密钥。

修正后的完整代码

from Crypto.Protocol.KDF import PBKDF2
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes
import base64

class SingleEncryption:

    def __init__(self, password, salt=None):
        self.password = password.encode()  # 统一转字节
        # 若未传入salt则生成随机salt(长度推荐16字节)
        self.salt = salt if salt else get_random_bytes(16)
        # PBKDF2迭代次数建议设为10000+,增强密钥安全性
        self.key = PBKDF2(self.password, self.salt, dkLen=32, count=100000)

    def saveKey(self):
        choice = input(f"是否保存密钥及salt到文件?Y/N ")
        if choice.upper() == "Y":
            file_path = input("请输入保存路径:")
            # 用with语句自动管理文件,避免资源泄漏
            with open(file_path, "wb") as file_out:
                # 先存salt再存密钥,方便后续读取
                file_out.write(self.salt + self.key)
            print(f"密钥及salt已保存到 {file_path}")
        else:
            print(f"未保存,salt: {base64.b64encode(self.salt).decode()}, 密钥: {base64.b64encode(self.key).decode()}")

    def encrypt(self, data):
        # 生成随机IV(AES块大小为16字节,IV长度需与块大小一致)
        iv = get_random_bytes(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        ciphered_data = cipher.encrypt(pad(data, AES.block_size))
        # 将salt、IV、密文拼接后转Base64,方便传输/存储
        return base64.b64encode(self.salt + iv + ciphered_data).decode()

    def decrypt(self, encrypted_str):
        # 解码Base64字符串为二进制
        encrypted_data = base64.b64decode(encrypted_str)
        # 拆分salt(前16字节)、IV(中间16字节)、密文(剩余部分)
        salt = encrypted_data[:16]
        iv = encrypted_data[16:32]
        cipher_data = encrypted_data[32:]
        # 用拆分出的salt重新生成密钥(确保和加密时一致)
        key = PBKDF2(self.password, salt, dkLen=32, count=100000)
        cipher2 = AES.new(key, AES.MODE_CBC, iv)
        original_data = unpad(cipher2.decrypt(cipher_data), AES.block_size)
        return original_data.decode()


if __name__ == "__main__":
    password = input("请输入加密密码:")
    encrypt = SingleEncryption(password)
    while True:
        q = input("选择操作:Encrypt(加密)/ Decrypt(解密)/ Quit(退出)")
        if q == "Encrypt":
            data = input("请输入要加密的内容:").encode()
            print("加密结果:", encrypt.encrypt(data))
        elif q == "Decrypt":
            encrypted_str = input("请输入加密后的字符串:")
            try:
                print("解密结果:", encrypt.decrypt(encrypted_str))
            except ValueError as e:
                print("解密失败:", str(e))
        elif q == "Quit":
            break
        else:
            print("输入错误,请区分大小写,重新输入。")

关键说明

  • IV的作用:CBC模式下IV用于保证相同明文加密后得到不同密文,必须随机且与密文一同传递,解密时必须使用同一个IV。
  • Base64编码:二进制数据无法直接通过文本输入框正确传输,转成Base64字符串后可安全存储和输入。
  • PBKDF2参数:增加count参数(迭代次数)可以提升密钥破解难度,推荐设置100000次以上。

内容的提问来源于stack exchange,提问作者FireFlower

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:10:23