Python2加密程序转换时运行在python3returns错误

Python 2 encryption program when converted and run in python 3 returns error

This is a continuation of question. Please do not mark this question as a duplicate for it has a different error I need to fix.

TL;link 的 DR:

所以我问我的加密程序 python 中的 Unicode 错误,有人告诉我只需将密码编码为 utf-8 就可以了。


现在我有第二个问题,它说 IV 不是 16 字节,所以我通过在 IV 之后放置 print(len(IV)) 并在 运行 3 测试之后检查它 returns 16一次,在打印字符的中间,结束字符大于16(如:37、35、28等)。

如何解决这个问题,使 IV 总是 returns 16 字节?

完整错误:

Traceback (most recent call last):
  File "/home/pi/Desktop/Projects/FyleCript/Dev Files/encryption.py", line 77, in <module>
    encrypt(SHA256.new(password.encode('utf-8')).digest(), str(Tfiles))
  File "/home/pi/Desktop/Projects/FyleCript/Dev Files/encryption.py", line 17, in encrypt
    encryptor = AES.new(key, AES.MODE_CBC, IV)
  File "/usr/lib/python3/dist-packages/Crypto/Cipher/AES.py", line 94, in new
    return AESCipher(key, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/Crypto/Cipher/AES.py", line 59, in __init__
    blockalgo.BlockAlgo.__init__(self, _AES, key, *args, **kwargs)
  File "/usr/lib/python3/dist-packages/Crypto/Cipher/blockalgo.py", line 141, in __init__
    self._cipher = factory.new(key, *args, **kwargs)
ValueError: IV must be 16 bytes long

代码:

def encrypt(key, filename):
        chunksize = 64 * 1024
        outFile = os.path.join(os.path.dirname(filename), "(encrypted)"+os.path.basename(filename))
        filesize = str(os.path.getsize(filename)).zfill(16)
        IV = ''

        for i in range(16):
                IV += chr(random.randint(0, 0xFF))

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

        with open(filename, "rb") as infile:
                with open(outFile, "wb") as outfile:
                        outfile.write(filesize)
                        outfile.write(IV)
                        while True:
                                chunk = infile.read(chunksize)

                                if len(chunk) == 0:
                                        break

                                elif len(chunk) % 16 !=0:
                                        chunk += ' ' *  (16 - (len(chunk) % 16))

                                outfile.write(encryptor.encrypt(chunk))


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))

如有任何帮助,我们将不胜感激。

好吧,让我们来看看 IV 可能由什么组成:

IV = ''

for i in range(16):
    IV += chr(random.randint(0, 0xFF))

让我们看看 range(0, 0xff) 中的一个字符消耗了多少字节:

>>> [len(chr(i).encode()) for i in range(0, 0xff)]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

这就是问题的根源:您假设每个字符都是 一个 字节长,但事实并非如此。

您可以使用以下代码生成 N 字节的随机 IV:

import os

N = 16
IV = os.urandom(N)

您的代码中的另一个问题是您在 'rb' 模式下打开所有文件,它代表 "read binary",但试图写入 str 的实例,喜欢你的 IV。这是行不通的,因为在这种模式下,您只能读取和写入 bytes,而不能读取和写入 str。在我计算 IV 的解决方案中,这个问题完全消失了。

您还没有将 IV 字符串转换为字节字符串。在Python 3中str不是字节串,而是字符串。 str 是从字符如何表示为字节的概念中抽象出来的。

您需要将 IV 变量(也许还​​有其他变量,我还没有检查过)转换为 bytes 的实例。在 Python 3.

中制作字节串也更容易一些
random_byte_list = [random.randrange(256) for _ in range(16)]
IV = bytes(random_byte_list)