【问题标题】:Python 2 encryption program when converted and run in python 3 returns errorPython 2 加密程序在转换并在 python 3 中运行时返回错误
【发布时间】:2018-07-16 13:01:28
【问题描述】:

这是this 问题的延续。请不要将此问题标记为重复问题,因为它有另一个我需要修复的错误。

TL;链接的DR:

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


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

我该如何解决这个问题,以便 IV 始终返回 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))

任何帮助将不胜感激。

【问题讨论】:

  • 我注意到的第一件事:if choice == "E" or 'e' 永远是真的。而是做if choice in ( "E", 'e')
  • 我们不需要查看您的整个程序,只需查看重现问题所需的最少数量。有很多可以删减。
  • 加密时不要使用os.random(),而是使用Crypto.Random()。检查this answer 以了解如何正确执行此操作,它还显示了 Python 2.x 和 3.x 之间的差异。

标签: python python-3.x encryption pycrypto


【解决方案1】:

好吧,让我们看看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' 模式下打开所有文件,该模式代表“读取二进制”,但尝试写入str 的实例,例如您的IV。这是行不通的,因为在这种模式下你只能读写bytes,而不是str。在我计算IV 的解决方案中,这个问题完全消失了。

【讨论】:

  • 那么我该如何解决下一个错误:chunk += ' ' * (16 - (len(chunk) % 16)) TypeError: can't concat bytes to str?如果我在它前面放一个b,加密文件说它有字节,但是当我在文本编辑器中打开它时,文件是空白的。
  • @TrooperZ,您应该阅读有关bytes 在 Python 3 中的用法以及它与 str 的不同之处。如果 text 编辑器显示的内容看起来很空,请不要相信它并在十六进制编辑器中打开您的文件。
  • 但是在python 2中,它显示奇怪的字符(这意味着它被加密了)
  • 新生成的加密文件大小是多少?如果它是零字节,那么它确实是空的。
  • 它要大得多(从 3.4 kb 到 6.8)
【解决方案2】:

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

您需要将您的IV 变量(可能还有其他变量,我尚未检查)转换为bytes 的实例。在 Python 3 中制作字节串也更容易一些。

random_byte_list = [random.randrange(256) for _ in range(16)]
IV = bytes(random_byte_list)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-07
    • 2013-01-05
    • 2023-02-17
    • 2018-01-24
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2017-10-01
    相关资源
    最近更新 更多