私はすでに動作するプログラムを持っていますが、動作しないのは私が持っているdecrypt_file()
関数だけです。暗号化されたテキストをファイルからコピーしてdecrypt()
関数に入れて機能させることはできますが、便利なdecrypt_file()
関数を使用しようとすると、エラーをスローします。私の99.999%は、自分のencrypt()
関数とdecrypt()
関数が問題ないことを確信していますが、エラーをスローするテキストファイルを読み取ってエンコードすると、バイトと文字列の変換に問題があります。ハングアップが見つかりません。助けてください!
私のプログラム:
_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)
_
暗号化したテキストファイル:
_b';c\xb0\xe6Wv5!\xa3\xdd\xf0\xb1\xfd2\x90B\x10\xdf\x00\x82\x83\x9d\xbc2\x91\xa7i M\x13\xdc\xa7'
_
_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]
_
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]
_
私はあなたのコードを詳しく調べたところ、いくつかの問題があることがわかりました。 1つ目は、暗号がテキストではなくバイトで機能することです。したがって、データをバイト文字列として保持することをお勧めします。これは、モードに「b」文字を置くだけで実行できます。このようにして、実行しようとしていたすべてのエンコーディングとバイト変換を取り除くことができます。
新しい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)
Python 3(これを明確に使用しています)では、開くファイルのデフォルトモードはバイナリではなくテキストです。ファイルから読み取ると、バイト配列ではなく文字列が取得されます。暗号化と一緒に行きます。
コードでは、次のものを置き換える必要があります。
open(file_name, 'r')
と:
open(file_name, 'rb')
書き込み用にファイルを開いたときも同じです。その時点で、文字列からバイナリに、またはその逆に変換するさまざまな発生をすべて取り除くことができます。
たとえば、これはなくなる可能性があります:
plaintext = plaintext.encode('utf-8')