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

AES CBC模式批量文件夹解密报错:数据长度非块长度倍数

批量AES加密文件夹后解密报错:数据长度不是块长度的倍数

为提升业务安全性,我用Python编写了AES加密脚本批量加密文件夹,加密过程正常,但执行自动生成的decryptor.py时触发ValueError,提示「提供的数据长度不是块长度的倍数」。以下是相关代码、报错信息及可用的单个文件加密解密代码,寻求技术解决。


加密代码

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = os.urandom(32)  # 256 bit
iv = os.urandom(16)  # 128 bit

# cryptografy
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()

# loop all files and folders
for root, dirs, files in os.walk('.'):
    # ignores main.py (that is the file name to not encrypt it)
    if 'main.py' in files:
        continue
    # crypt files
    for file in files:
        # create a new encryptor
        cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
        encryptor = cipher.encryptor()

        # read datas
        file_path = os.path.join(root, file)
        data = open(file_path, 'rb').read()

        # adding padding
        padder = padding.PKCS7(128).padder()
        padded_data = padder.update(data) + padder.finalize()

        # encrypts the data
        cipher_data = encryptor.update(padded_data) + encryptor.finalize()

        # writes the encrypted data to the file
        file = open(file_path, 'wb')
        file.write(cipher_data)
        file.close()

# write the code for decryption in the file
decryptor_file = open('decryptor.py', 'w')
decryptor_file.write("import os\n")
decryptor_file.write("from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\n")
decryptor_file.write("from cryptography.hazmat.backends import default_backend\n")
decryptor_file.write("from cryptography.hazmat.primitives import padding\n\n")

decryptor_file.write("backend = default_backend()\n")
decryptor_file.write("key = \"" + key.hex() + "\"\n")
decryptor_file.write("iv = \"" + iv.hex() + "\"\n\n")

decryptor_file.write("# descryptografy\n")
decryptor_file.write("cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)\n")
decryptor_file.write("decryptor = cipher.decryptor()\n\n")

decryptor_file.write("# loops all files and folders\n")
decryptor_file.write("for root, dirs, files in os.walk('.'):\n")
decryptor_file.write("    # decrypt files\n")
decryptor_file.write("    for file in files:\n")
decryptor_file.write("        # data reading\n")
decryptor_file.write("        file_path = os.path.join(root, file)\n")
decryptor_file.write("        data = open(file_path, 'rb').read()\n\n")

decryptor_file.write("        # decrypt data \n")
decryptor_file.write("        decrypted_data = decryptor.update(data) + decryptor.finalize()\n\n")

decryptor_file.write("        # remove padding\n")
decryptor_file.write("        unpadder = padding.PKCS7(128).unpadder()\n")
decryptor_file.write("        unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()\n\n")

decryptor_file.write("        # writes the data descrypted in the file\n")
decryptor_file.write("        file = open(file_path, 'wb')\n")
decryptor_file.write("        file.write(unpadded_data)\n")
decryptor_file.write("        file.close()\n\n")

decryptor_file.close()

# shows a alert message
print('All files and folders have been encrypted and the decrypt file has been created!')

自动生成的decryptor.py核心逻辑

上述加密脚本生成的decryptor.py实际执行代码如下:

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = "生成的key hex值"
iv = "生成的iv hex值"

# descryptografy
cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)
decryptor = cipher.decryptor()

# loops all files and folders
for root, dirs, files in os.walk('.'):
    # decrypt files
    for file in files:
        # data reading
        file_path = os.path.join(root, file)
        data = open(file_path, 'rb').read()

        # decrypt data 
        decrypted_data = decryptor.update(data) + decryptor.finalize()

        # remove padding
        unpadder = padding.PKCS7(128).unpadder()
        unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()

        # writes the data descrypted in the file
        file = open(file_path, 'wb')
        file.write(unpadded_data)
        file.close()

报错信息

Traceback (most recent call last):
  File "C:\Users\User\Desktop\cryptor\decryptor.py", line 23, in <module>
    decrypted_data = decryptor.update(data) + decryptor.finalize()
  File "C:\Program Files\Python38\lib\site-packages\cryptography\hazmat\primitives\ciphers\base.py", line 186, in finalize
    data = self._ctx.finalize()
  File "C:\Program Files\Python38\lib\site-packages\cryptography\hazmat\backends\openssl\ciphers.py", line 223, in finalize
    raise ValueError(
ValueError: The length of the provided data is not a multiple of the block length.

单个文件加密解密可用代码

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = os.urandom(32) # 256 bit
iv = os.urandom(16) # 128 bit

# cryptography
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()

# read from file
file = open('text.txt', 'rb')
data = file.read()
file.close()

# adding the padding
padder = padding.PKCS7(128).padder()
padded_data = padder.update(data) + padder.finalize()

# encrypt the data
cipher_data = encryptor.update(padded_data) + encryptor.finalize()

# write the encrypted data to the file
file = open('crypto.txt', 'wb')
file.write(cipher_data)
file.close()

# delete the old file
os.remove('text.txt')

# display alert message
print('Your file has been encrypted!')

# create the decryption file
decryptor_file = open('decryptor.py', 'w')

# write the decryption code to the file
decryptor_file.write("import os\n")
decryptor_file.write("from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\n")
decryptor_file.write("from cryptography.hazmat.backends import default_backend\n")
decryptor_file.write("from cryptography.hazmat.primitives import padding\n\n")

decryptor_file.write("backend = default_backend()\n")
decryptor_file.write("key = \"" + key.hex() + "\"\n")
decryptor_file.write("iv = \"" + iv.hex() + "\"\n\n")

decryptor_file.write("# decryption\n")
decryptor_file.write("cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)\n")
decryptor_file.write("decryptor = cipher.decryptor()\n\n")

decryptor_file.write("# read file\n")
decryptor_file.write("file = open('crypto.txt', 'rb')\n")
decryptor_file.write("data = file.read()\n")
decryptor_file.write("file.close()\n\n")

decryptor_file.write("# decrypt data\n")
decryptor_file.write("decrypted_data = decryptor.update(data) + decryptor.finalize()\n\n")

decryptor_file.write("# remove padding\n")
decryptor_file.write("unpadder = padding.PKCS7(128).unpadder()\n")
decryptor_file.write("unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()\n\n")

decryptor_file.write("# write decrypted data to file\n")
decryptor_file.write("file = open('text.txt', 'wb')\n")
decryptor_file.write("file.write(unpadded_data)\n")
decryptor_file.write("file.close()\n\n")

decryptor_file.close()

问题根源与修复方案

问题根源

解密脚本中复用了同一个decryptor实例处理所有文件。CBC模式的解密器在调用finalize()后,内部状态会被销毁,无法再次用于解密操作。后续文件使用已失效的解密器时,会导致数据处理逻辑异常,触发块长度不匹配的报错。

对比单个文件的代码,单个文件仅执行一次解密流程,所以不会出现这个问题;但批量处理时,每个文件都需要独立的解密器实例。

另外,加密脚本中已经做到了为每个文件创建新的encryptor,但解密脚本未同步这个逻辑。

修复后的decryptor.py代码

将解密器的创建逻辑移到文件循环内部,确保每个文件都使用全新的解密器:

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = "加密脚本生成的key hex值"
iv = "加密脚本生成的iv hex值"

# loops all files and folders
for root, dirs, files in os.walk('.'):
    # 跳过解密脚本自身,避免误处理
    if 'decryptor.py' in files:
        continue
    # decrypt files
    for file in files:
        # 为每个文件创建新的解密器
        cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)
        decryptor = cipher.decryptor()
        
        # data reading
        file_path = os.path.join(root, file)
        with open(file_path, 'rb') as f:
            data = f.read()

        # decrypt data 
        decrypted_data = decryptor.update(data) + decryptor.finalize()

        # remove padding
        unpadder = padding.PKCS7(128).unpadder()
        unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()

        # writes the data decrypted in the file
        with open(file_path, 'wb') as f:
            f.write(unpadded_data)

加密脚本的额外优化

  1. 修复目录文件跳过逻辑:原代码中if 'main.py' in files: continue会跳过整个目录的文件处理,应改为在文件循环中判断跳过单个文件:
# loop all files and folders
for root, dirs, files in os.walk('.'):
    # crypt files
    for file in files:
        # 跳过加密脚本自身
        if file == 'main.py':
            continue
        # 后续加密逻辑不变...
  1. 使用with语句管理文件操作,避免忘记关闭文件导致的资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:10:28