The password is not the key. Openssl uses EVP_BytesToKey
to create an appropriate key (& IV, if necessary) from the password and the salt.
As James K Polk mentions in a comment, you can use the -P (or -p) option to tell Openssl to print the key (in hex ), which you can then pass to Crypto.Cipher. Alternatively, you can implement EVP_BytesToKey
in Python, as shown below. This is a simplified version of EVP_BytesToKey
that uses no salt, and the default value of 1 for the count
arg.
As the EVP_BytesToKey
docs state, this is a rather weak password derivation function. As the hashlib docs mention, modern password derivation normally performs hundreds of thousands of hashes to make password hashing attacks very slow.
We also need a function to remove the PKCS7 padding from the decrypted data bytes. The unpad
function below simply assumes that the padding data is valid. In real software the unpad
function must verify that the padded data is valid to prevent padding-based attacks. My unpad
function also assumes the data has been encoded as UTF-8 bytes and decodes the unpadded data to text.
from __future__ import print_function
from Crypto.Cipher import AES
from base64 import b64decode
from hashlib import md5
def evp_simple(data):
out = ''
while len(out) < 32:
out += md5(out + data).digest()
return out[:32]
def unpad(s):
offset = ord(s[-1])
return s[:-offset].decode('utf-8')
iv = 'a2a8a78be66075c94ca5be53c8865251'.decode('hex')
passwd = '00112233445566778899aabbccddeeff'
key = evp_simple(passwd)
print('key', key.encode('hex'))
aes = AES.new(key, AES.MODE_CBC, IV=iv)
data = b64decode('pt7DqtAwtTjPbTlzVApucQ==')
raw = aes.decrypt(data)
print(repr(raw), len(raw))
plain = unpad(raw)
print(repr(plain), len(plain))
output
key b4377f7babf2991b7d6983c4d3e19cd4dd37e31af1c9c689ca22e90e365be18b
'hello world\n\x04\x04\x04\x04' 16
u'hello world\n' 12
That code will not run on Python 3, so here's a Python 3 version.
from Crypto.Cipher import AES
from base64 import b64decode
from hashlib import md5
def evp_simple(data):
out = b''
while len(out) < 32:
out += md5(out + data).digest()
return out[:32]
def unpad(s):
offset = s[-1]
return s[:-offset].decode('utf-8')
iv = bytes.fromhex('a2a8a78be66075c94ca5be53c8865251')
passwd = b'00112233445566778899aabbccddeeff'
key = evp_simple(passwd)
aes = AES.new(key, AES.MODE_CBC, IV=iv)
data = b64decode('pt7DqtAwtTjPbTlzVApucQ==')
raw = aes.decrypt(data)
print(repr(raw), len(raw))
plain = unpad(raw)
print(repr(plain), len(plain))
output
b'hello world\n\x04\x04\x04\x04' 16
'hello world\n' 12