I am new to cryptology. There is a file.aes
that is encrypted using AES with 128-bit key and ECB. I have no clue what format the original file is. I am given a set of keys that I was told one of them will decrypt it correctly. So I wrote a python script with PyCryptodome as below:
from Crypto.Cipher import AES
keys = [some 32 character keys]
file_in = open("file.aes", "rb")
ciphertext = file_in.read()
for key in keys:
print (key)
cipher = AES.new(str.encode(key), AES.MODE_ECB)
data = cipher.decrypt(ciphertext)
print(data)
For all keys the decryption returns bytes data that is not comprehensible like this:
b'\xdd\xc1\xd4\x80\xd5\xe6\x92\xe7\xf3/\n\xa4\x90\x0b\x98(\x8a\xb8\xdf\xd1K\n\xeagW\xe9f\x80\xef9\x8e\xd5...'
I tried to decode it with ascii
, utf-8
, utf-16
, utf-32
hoping to see plaintext and they all return UnicodeDecodeError
:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa7 in position 0: ordinal not in range(128)
How do I find the right encoding for the data?
I also start wondering if the original file was also just a incomprehensible binary file. How do I know which decryption was successful and correct when I can't identify it by just reading it?
Edit:
As suggested I tried encrypt and decrypt a utf-8 encoded plain file as below. Decrypted with no issue.
from Crypto.Cipher import AES
key = b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{'
cipher = AES.new(key, AES.MODE_ECB)
file_in = open("file", "rb")
data = file_in.read()
length = 16 - (len(data) % 16)
data += bytes([length]) * length
ciphertext = cipher.encrypt(data)
print(ciphertext)
plaintext = cipher.decrypt(ciphertext)
print(plaintext.decode())
Update: New thoughts. Since I am testing on a bunch of keys that are mostly not valid, it is probably normal that the decrypted data is decodable and return error. I should use try and except. I should also try all codecs that python listed in the documentation.
from Crypto.Cipher import AES
keys = [some 32 character keys]
codecs = [all codecs]
file_in = open("file.aes", "rb")
ciphertext = file_in.read()
for key in keys:
print (key)
cipher = AES.new(str.encode(key), AES.MODE_ECB)
data = cipher.decrypt(ciphertext)
for codec in codecs:
try :
print(data.decode(codec))
except:
pass
After adding decode and try-except on the print statement, trying all encoding, I found none of keys would print anything.
I found a way to successfully decrypt it with OpenSSL instead.
Write a script that calls OpenSSL with the set of keys, python bash or bat doesn't matter. It will create a output file no matter the key is right or wrong, the file can be overwritten but we do not care about that. If the key is wrong it prints bad decrypt error and exit with code 1. Find the key where it prints nothing or exit with code 0. Than take the key to decrypt separately. In my case I have found 8 keys and only one of them turns out to be readable.
Here's python implementation of the idea:
keys = [a list of all possible keys]
for key in keys:
# out.txt will be repeatedly overwritten
command = "openssl enc -d -aes-128-ecb -in file.aes -out out.txt -K " + key
output = os.system(command)
# If OpenSSL exited with code 0
if (output == 0):
# Generates a separate file for that key
command = "openssl enc -d -aes-128-ecb -in file.aes -out " + key + ".txt -K " + key
output = os.system(command)