Python PyCrypto 使用 AES 加密/解密文本文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20852664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python PyCrypto encrypt/decrypt text files with AES
提问by Zach King
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()函数中并使其工作,但是当我尝试使用我认为很方便的decrypt_file()函数时,它会引发错误。现在我知道 99.999% 确定我的encrypt()和decrypt()函数没问题,但是当我读取和编码抛出错误的文本文件时,字节和字符串转换有些问题;我只是找不到挂断电话。请帮忙!
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:
尝试时我的错误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 行时plaintext += ((str(bytes([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]
采纳答案by Keith
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"open(file_name, 'r')
" * (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"open(file_name, 'rb')
")
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)
回答by SquareRootOfTwentyThree
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.
在 Python 3(您显然正在使用)中,您打开的文件的默认模式是文本,而不是二进制。当您从文件中读取时,您将获得字符串而不是字节数组。这与加密不符。
In your code, you should replace:
在您的代码中,您应该替换:
plaintext = plaintext.encode('utf-8')
with:
和:
##代码##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:
例如,这可以消失:
##代码##
