Python的PyCrypto对带有AES的文本文件进行加密/解密。

时间:2022-08-02 18:28:31

I already have a working program, but the only thing that doesn't work is the decrypt_file() function I have. I can still copy the encrypted text from the file and put it in my decrypt() function and have it work, but when I try to use my supposed-to-be handy decrypt_file() function it throws an error. Now I know 99.999% sure that my encrypt() and decrypt() functions are fine, but there is something with the bytes and strings conversion when I read and encode the text file that throws an error; I just can't find the hangup. Please help!

我已经有了一个工作程序,但是唯一不起作用的是我拥有的decrypt_file()函数。我仍然可以从文件中复制加密的文本,并将其放入我的decrypt()函数中,并让它工作,但是当我试图使用我的supposed-to-be handy decrypt_file()函数时,它会抛出一个错误。现在我知道了99.999%,我的加密()和解密()函数都很好,但是当我读取和编码抛出一个错误的文本文件时,会有一些字节和字符串的转换;我就是找不到那个地方。请帮助!

My Program:

我的计划:

from Crypto import Random
from Crypto.Cipher import AES

def encrypt(message, key=None, key_size=256):
    def pad(s):
        x = AES.block_size - len(s) % AES.block_size
        return s + ((bytes([x])) * x)

    padded_message = pad(message)

    if key is None:
        key = Random.new().read(key_size // 8)

    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)

    return iv + cipher.encrypt(padded_message)

def decrypt(ciphertext, key):
    unpad = lambda s: s[:-s[-1]]
    iv = ciphertext[:AES.block_size]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = unpad(cipher.decrypt(ciphertext))[AES.block_size:]

    return plaintext

def encrypt_file(file_name, key):
    f = open(file_name, 'r')
    plaintext = f.read()
    plaintext = plaintext.encode('utf-8')
    enc = encrypt(plaintext, key)
    f.close()
    f = open(file_name, 'w')
    f.write(str(enc))
    f.close()

def decrypt_file(file_name, key):
    def pad(s):
        x = AES.block_size - len(s) % AES.block_size
        return s + ((str(bytes([x]))) * x)

    f = open(file_name, 'r')
    plaintext = f.read()
    x = AES.block_size - len(plaintext) % AES.block_size
    plaintext += ((bytes([x]))) * x
    dec = decrypt(plaintext, key)
    f.close()
    f = open(file_name, 'w')
    f.write(str(dec))
    f.close()



key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'

encrypt_file('to_enc.txt', key)

The text file I encrypted:

我加密的文本文件:

b';c\xb0\xe6Wv5!\xa3\xdd\xf0\xb1\xfd2\x90B\x10\xdf\x00\x82\x83\x9d\xbc2\x91\xa7i M\x13\xdc\xa7'

My error when attempting decrypt_file:

尝试解密文件时的错误:

    Traceback (most recent call last):
  File "C:\Python33\testing\test\crypto.py", line 56, in <module>
    decrypt_file('to_enc.txt', key)
  File "C:\Python33\testing\test\crypto.py", line 45, in decrypt_file
    plaintext += ((bytes([x]))) * x
TypeError: Can't convert 'bytes' object to str implicitly
[Finished in 1.5s]

When I replace line 45 with: plaintext += ((str(bytes([x])))) * x, this is the error I get:

当我替换第45行:纯文本+= ((str([x])) * x,这是我得到的错误:

Traceback (most recent call last):
  File "C:\Python33\testing\test\crypto.py", line 56, in <module>
    decrypt_file('to_enc.txt', key)
  File "C:\Python33\testing\test\crypto.py", line 46, in decrypt_file
    dec = decrypt(plaintext, key)
  File "C:\Python33\testing\test\crypto.py", line 23, in decrypt
    plaintext = unpad(cipher.decrypt(ciphertext))[AES.block_size:]
  File "C:\Python33\lib\site-packages\Crypto\Cipher\blockalgo.py", line 295, in decrypt
    return self._cipher.decrypt(ciphertext)
ValueError: Input strings must be a multiple of 16 in length
[Finished in 1.4s with exit code 1]

2 个解决方案

#1


26  

I took a closer look at your code, and saw that there were several problems with it. First one is that the crypto functions with with bytes, not text. So it's better to just keep the data as a byte string. This is done simply by putting a 'b' character in the mode. This way you can get rid of all the encoding and bytes conversion you were trying to do.

我仔细查看了您的代码,发现它有几个问题。首先是加密函数与字节,而不是文本。所以最好将数据保存为字节字符串。这仅仅通过在模式中放置一个“b”字符来完成。这样,您就可以消除您正在尝试的所有编码和字节转换。

I rewrote the whole code also using newer Python idioms. Here it is.

我重写了整个代码,并使用了新的Python语言。在这儿。

#!/usr/bin/python3

from Crypto import Random
from Crypto.Cipher import AES

def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encrypt(message, key, key_size=256):
    message = pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return iv + cipher.encrypt(message)

def decrypt(ciphertext, key):
    iv = ciphertext[:AES.block_size]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext[AES.block_size:])
    return plaintext.rstrip(b"\0")

def encrypt_file(file_name, key):
    with open(file_name, 'rb') as fo:
        plaintext = fo.read()
    enc = encrypt(plaintext, key)
    with open(file_name + ".enc", 'wb') as fo:
        fo.write(enc)

def decrypt_file(file_name, key):
    with open(file_name, 'rb') as fo:
        ciphertext = fo.read()
    dec = decrypt(ciphertext, key)
    with open(file_name[:-4], 'wb') as fo:
        fo.write(dec)


key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'

encrypt_file('to_enc.txt', key)
#decrypt_file('to_enc.txt.enc', key)

#2


3  

In Python 3 (which you are clearly using) the default mode for files you open is text, not binary. When you read from the file, you get strings rather than byte arrays. That does not go along with encryption.

在python3(你清楚地使用)中,你打开的文件的默认模式是文本,而不是二进制文件。当您从文件中读取时,会得到字符串而不是字节数组。这与加密不兼容。

In your code, you should replace:

在您的代码中,您应该替换:

open(file_name, 'r')

with:

:

open(file_name, 'rb')

The same for when you open the file for writing. At that point, you can get rid of all the various occurrences where you convert from string to binary and vice versa.

当你打开文件写作时也是如此。在这一点上,您可以摆脱所有的事件,您将从字符串转换为二进制,反之亦然。

For instance, this can go away:

例如,它可以消失:

plaintext = plaintext.encode('utf-8')

#1


26  

I took a closer look at your code, and saw that there were several problems with it. First one is that the crypto functions with with bytes, not text. So it's better to just keep the data as a byte string. This is done simply by putting a 'b' character in the mode. This way you can get rid of all the encoding and bytes conversion you were trying to do.

我仔细查看了您的代码,发现它有几个问题。首先是加密函数与字节,而不是文本。所以最好将数据保存为字节字符串。这仅仅通过在模式中放置一个“b”字符来完成。这样,您就可以消除您正在尝试的所有编码和字节转换。

I rewrote the whole code also using newer Python idioms. Here it is.

我重写了整个代码,并使用了新的Python语言。在这儿。

#!/usr/bin/python3

from Crypto import Random
from Crypto.Cipher import AES

def pad(s):
    return s + b"\0" * (AES.block_size - len(s) % AES.block_size)

def encrypt(message, key, key_size=256):
    message = pad(message)
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return iv + cipher.encrypt(message)

def decrypt(ciphertext, key):
    iv = ciphertext[:AES.block_size]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext[AES.block_size:])
    return plaintext.rstrip(b"\0")

def encrypt_file(file_name, key):
    with open(file_name, 'rb') as fo:
        plaintext = fo.read()
    enc = encrypt(plaintext, key)
    with open(file_name + ".enc", 'wb') as fo:
        fo.write(enc)

def decrypt_file(file_name, key):
    with open(file_name, 'rb') as fo:
        ciphertext = fo.read()
    dec = decrypt(ciphertext, key)
    with open(file_name[:-4], 'wb') as fo:
        fo.write(dec)


key = b'\xbf\xc0\x85)\x10nc\x94\x02)j\xdf\xcb\xc4\x94\x9d(\x9e[EX\xc8\xd5\xbfI{\xa2$\x05(\xd5\x18'

encrypt_file('to_enc.txt', key)
#decrypt_file('to_enc.txt.enc', key)

#2


3  

In Python 3 (which you are clearly using) the default mode for files you open is text, not binary. When you read from the file, you get strings rather than byte arrays. That does not go along with encryption.

在python3(你清楚地使用)中,你打开的文件的默认模式是文本,而不是二进制文件。当您从文件中读取时,会得到字符串而不是字节数组。这与加密不兼容。

In your code, you should replace:

在您的代码中,您应该替换:

open(file_name, 'r')

with:

:

open(file_name, 'rb')

The same for when you open the file for writing. At that point, you can get rid of all the various occurrences where you convert from string to binary and vice versa.

当你打开文件写作时也是如此。在这一点上,您可以摆脱所有的事件,您将从字符串转换为二进制,反之亦然。

For instance, this can go away:

例如,它可以消失:

plaintext = plaintext.encode('utf-8')