【问题标题】:AES: Input strings must be a multiple of 16 in lengthAES:输入字符串的长度必须是 16 的倍数
【发布时间】:2017-05-08 07:03:21
【问题描述】:

我想制作一个脚本来解密我的文件,但是当我尝试运行我的脚本然后显示这条消息时,我该如何解决它?

Traceback(最近一次调用最后一次):文件“F:\bug_bounty\decrypt.py”, 第 46 行,在文件“F:\bug_bounty\decrypt.py”中,第 24 行,在 解密文件 “C:\Python27\lib\site-packages\Crypto\Cipher\blockalgo.py”,第 295 行, 在解密 return self._cipher.decrypt(ciphertext) ValueError: 输入字符串的长度必须是 16 的倍数

from Crypto.Hash import SHA256
from Crypto.Cipher import AES
import os
import random
import sys


def decrypt(key, filename):
    outFile = os.path.join(os.path.dirname(filename),
                           os.path.basename(filename[11:]))
    chunksize = 64 * 1024
    with open(filename, 'rb') as infile:
        filesize = infile.read(16)
        IV = infile.read(16)

        decryptor = AES.new(key, AES.MODE_CBC, IV)

        with open(outFile, 'wb') as outfile:
            while True:
                chunk = infile.read(chunksize)
                if len(chunk) == 0:
                    break

                outfile.write(decryptor.decrypt(chunk))

            outfile.truncate(int(filesize))


def allfiles():
    allFiles = []
    for (root, subfiles, files) in os.walk(os.getcwd()):
        for names in files:
            allFiles.append(os.path.join(root, names))

    return allFiles


password = 'M4st3rRul3zs'
files = allfiles();
for filename in files:
    if os.path.basename(filename).startswith("(encrypted)"):
       print "%s is already encrypted" %filename
       pass

    else:  
        decrypt(SHA256.new(password).digest(), filename)
        print "Done decrypting %s" %filename
        """os.remove(filename)"""

【问题讨论】:

标签: python aes


【解决方案1】:

来自Crypto++ wiki。

块大小由 AES::BLOCKSIZE 决定。对于 AES,这是 总是 16 个字节

AES 是一种分组密码,它适用于 16 字节(128 位)的分组。它不能处理小于或大于 16 字节的数据。较小的数据需要填充直到它们达到 16 字节,而较大的数据需要分成 16 字节的块。

还有一些算法可以帮助您实现这一目标(处理大于密码块大小的数据),它们被称为block cipher modes of operation。

看看这个How to encrypt more than 16 bytes using AES?

【讨论】:

    【解决方案2】:

    如果您的数据大小不大,您可以在加密数据时使用以下小技巧。

    plaintext = "some text"
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = encryptor.encrypt(plaintext*16)
    

    这将确保您的输入数据是 16 的倍数。当然,您希望在解密时取回原始数据。

    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypttext = cipher.decrypt(ciphertext)
    decrypttext = decrypttext[0:len(plaintext)]
    

    现在,decrpyttext 有了您的原始明文。

    【讨论】:

    • 或者,你也可以使用decrpyttext = decrpyttext[0: len(decrpyttext)//16]
    【解决方案3】:

    ValueError: 输入字符串的长度必须是 16 的倍数

    这是因为 AES 使用 128 位(16 个字符)的块。您可以考虑添加padding 来解决此问题。

    【讨论】:

    • 在代码中应该如何?文件大小 = infile.read(16) IV = infile.read(16) 解密器 = AES.new(key, AES.MODE_CBC, IV)
    • @Aron Imperial google 'pkcs7 padding' 或 'zero padding' 它们都很容易实现
    【解决方案4】:

    AES 适用于 16 个字符的块。这就是你如何添加额外的填充

    随机导入 导入字符串
    plaintext = "Encrypt me"
    encryptor = AES.new(key, AES.MODE_CBC, iv)
    
    while len(bytes(plaintext, encoding='utf-8')) % 16 != 0:
         plaintext = plaintext + random.choice(string.ascii_letters)
    
    ciphertext = encryptor.encrypt(plaintext)
    

    【讨论】:

    • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答添加解释并说明适用的限制和假设。
    猜你喜欢
    • 2019-03-24
    • 1970-01-01
    • 2019-01-04
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多