ValueError:AES密钥必须为16、24或32个字节长PyCrypto 2.7a1

Tuk*_*oid -1 python cryptography pycrypto python-3.x

我正在为我的学校项目编程,上面有一个问题。这是我的代码:

def aes():
    #aes
    os.system('cls')
    print('1. Encrypt')
    print('2. Decrypt')

    c = input('Your choice:')

    if int(c) == 1:
        #cipher
        os.system('cls')
        print("Let's encrypt, alright")
        print('Input a text to be encrypted')
        text = input()

        f = open('plaintext.txt', 'w')
        f.write(text)
        f.close()

        BLOCK_SIZE = 32
        PADDING = '{'
        pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
        EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
        secret = os.urandom(BLOCK_SIZE)

        f = open('aeskey.txt', 'w')
        f.write(str(secret))
        f.close()

        f = open('plaintext.txt', 'r')
        privateInfo = f.read()
        f.close()

        cipher = AES.new(secret)

        encoded = EncodeAES(cipher, privateInfo)

        f = open('plaintext.txt', 'w')
        f.write(str(encoded))
        f.close()
        print(str(encoded))

    if int(c) == 2:
        os.system('cls')
        print("Let's decrypt, alright")

        f = open('plaintext.txt','r')
        encryptedString = f.read()
        f.close()

        PADDING = '{'
        DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
        encryption = encryptedString

        f = open('aeskey.txt', 'r')
        key = f.read()
        f.close()

        cipher = AES.new(key)
        decoded = DecodeAES(cipher, encryption)

        f = open('plaintext.txt', 'w')
        f.write(decoded)
        f.close()

        print(decoded)
Run Code Online (Sandbox Code Playgroud)

完整的错误文字:

Traceback (most recent call last): File "C:/Users/vital/Desktop/Prog/Python/Enc_dec/Enc_dec.py", line 341, in aes() 
File "C:/Users/vital/Desktop/Prog/Python/Enc_dec/Enc_dec.py", line 180, in aes cipher = AES.new(key) 
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\AES.py", line 179, in new return AESCipher(key, *args, **kwargs) 
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\AES.py", line 114, in init blockalgo.BlockAlgo.init(self, _AES, key, *args, **kwargs) 
File "C:\Users\vital\AppData\Local\Programs\Python\Python35-32\lib\site-packages\Crypto\Cipher\blockalgo.py", line 401, in init self._cipher = factory.new(key, *args, **kwargs)
ValueError: AES key must be either 16, 24, or 32 bytes long

Process finished with exit code 1
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Ant*_*ala 5

错误非常明显。密钥必须恰好具有该大小。os.urandom将为您返回正确的密钥。但是,此键是一个字节(二进制字符串值)。此外,通过使用str(secret),将的值repr(secret)写入文件而不是secret

更令人困惑的是,它AES.new允许您将密钥作为Unicode传递!但是,假设键是ASCII字节1234123412341234。现在,

f.write(str(secret))
Run Code Online (Sandbox Code Playgroud)

将写入b'1234123412341234'文本文件!现在,它不再是16个字节,而是包含这16个字节+ b,和两个'引号字符;总共19个字节。

或者,如果您从中获取随机的二进制字符串os.urandom

>>> os.urandom(16)
b'\xd7\x82K^\x7fe[\x9e\x96\xcb9\xbf\xa0\xd9s\xcb'
Run Code Online (Sandbox Code Playgroud)

现在,它不再写入16个字节D782...等,而是将该字符串写入文件。并由于解密尝试使用而发生错误

"b'\\xd7\\x82K^\\x7fe[\\x9e\\x96\\xcb9\\xbf\\xa0\\xd9s\\xcb'"
Run Code Online (Sandbox Code Playgroud)

作为解密密钥,将其编码为UTF-8时会导致

b"b'\\xd7\\x82K^\\x7fe[\\x9e\\x96\\xcb9\\xbf\\xa0\\xd9s\\xcb'"
Run Code Online (Sandbox Code Playgroud)

这是一个49字节长的bytes值。


您有2个不错的选择。您要么继续将密钥写入文本文件,然后将其转换为十六进制,要么将密钥写入二进制文件;那么文件应该恰好是密钥长度(以字节为单位)。我要在这里为后者:

因此,为了存储密钥,使用

    with open('aeskey.bin', 'wb') as keyfile:
        keyfile.write(secret)
Run Code Online (Sandbox Code Playgroud)

    with open('aeskey.bin', 'rb') as keyfile:
        key = keyfile.read()
Run Code Online (Sandbox Code Playgroud)

密码文本(即加密的二进制文件)自然也是如此,您必须在二进制文件中进行读写操作:

    with open('ciphertext.bin', 'wb') as f:
        f.write(encoded)
Run Code Online (Sandbox Code Playgroud)

    with open('ciphertext.bin', 'rb') as f:
        encryptedString = f.read()
Run Code Online (Sandbox Code Playgroud)

如果你想为base64编码,这样做需要注意的是base64.b64encode/decodebytes-in /bytes退房手续。

顺便说一句,纯文本是原始的未加密文本。加密的文本称为密文。AES是一种密码,可以将纯文本加密为密文,并使用密钥将密文解密为纯文本。

尽管这些被称为“ -text”,但Python本身都不是文本数据,但是它们是二进制数据,应表示为bytes