Skip to content

Instantly share code, notes, and snippets.

@gsakkis

gsakkis/aes.py

Last active Jan 23, 2020
Embed
What would you like to do?
Porting AES from M2Crypto to Crypto
from binascii import hexlify, unhexlify
from hashlib import md5
from Crypto.Cipher import AES
try:
from M2Crypto import EVP
except ImportError:
EVP = None
def m2_encrypt(plaintext, key, iv, key_as_bytes=False, padding=True):
cipher = EVP.Cipher(alg="aes_256_cbc", key=key, iv=iv,
key_as_bytes=key_as_bytes, padding=padding, op=1)
return cipher.update(plaintext) + cipher.final()
def m2_decrypt(ciphertext, key, iv, key_as_bytes=False, padding=True):
cipher = EVP.Cipher(alg="aes_256_cbc", key=key, iv=iv,
key_as_bytes=key_as_bytes, padding=padding, op=0)
return cipher.update(ciphertext) + cipher.final()
def py_encrypt(plaintext, key, iv, key_as_bytes=False, padding=True):
if key_as_bytes:
key = bytes_to_key(key)
cipher = AES.new(key, AES.MODE_CBC, iv)
if padding:
plaintext = pkcs7_encode(plaintext)
return cipher.encrypt(plaintext)
def py_decrypt(ciphertext, key, iv, key_as_bytes=False, padding=True):
if key_as_bytes:
key = bytes_to_key(key)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
if padding:
plaintext = pkcs7_decode(plaintext)
return plaintext
def pkcs7_encode(text, k=16):
n = k - (len(text) % k)
return text + unhexlify(n * ("%02x" % n))
def pkcs7_decode(text, k=16):
n = int(hexlify(text[-1]), 16)
if n > k:
raise ValueError("Input is not padded or padding is corrupt")
return text[:-n]
def bytes_to_key(data, salt="12345678"):
# Simplified version of M2Crypto.m2.bytes_to_key(). Based on:
# https://github.com/ajmirsky/M2Crypto/blob/master/M2Crypto/EVP.py#L105
# http://stackoverflow.com/questions/8008253/c-sharp-version-of-openssl-evp-bytestokey-method
assert len(salt) == 8, len(salt)
data += salt
key = md5(data).digest()
key += md5(key + data).digest()
return key
def test_pycrypto(plaintext, key, iv, key_as_bytes, padding):
ciphertext = py_encrypt(plaintext, key, iv, key_as_bytes, padding)
assert py_decrypt(ciphertext, key, iv, key_as_bytes, padding) == plaintext
return ciphertext
def test_m2crypto(plaintext, key, iv, key_as_bytes, padding):
ciphertext = m2_encrypt(plaintext, key, iv, key_as_bytes, padding)
assert m2_decrypt(ciphertext, key, iv, key_as_bytes, padding) == plaintext
return ciphertext
if EVP:
def test(*args):
py_ciphertext = test_pycrypto(*args)
m2_ciphertext = test_m2crypto(*args)
assert py_ciphertext == m2_ciphertext
else:
test = test_pycrypto
def gen_test_inputs():
from os import urandom
from itertools import product
keys = [urandom(32) for _ in xrange(2)]
ivs = [urandom(16) for _ in xrange(2)]
key_as_bytes = [False, True]
# padding=False
plaintexts = [urandom(16 * n) for n in xrange(1025)]
for combo in product(plaintexts, keys, ivs, key_as_bytes, [False]):
yield combo
# padding=True
plaintexts = [urandom(n) for n in xrange(1025)]
for combo in product(plaintexts, keys, ivs, key_as_bytes, [True]):
yield combo
def benchmark(test_func):
from time import time
t = time()
for combo in gen_test_inputs():
test_func(*combo)
return time() - t
if __name__ == "__main__":
for combo in gen_test_inputs():
test(*combo)
print "pycrypto: %.2fs" % benchmark(test_pycrypto)
if EVP:
print "M2Crypto: %.2fs" % benchmark(test_m2crypto)
@diyan

This comment has been minimized.

Copy link

@diyan diyan commented Feb 4, 2013

Could you please share benchmark results between PyCrypto and M2Crypto?

@diyan

This comment has been minimized.

Copy link

@diyan diyan commented Jan 6, 2014

I've got following results on Ubuntu 13.10 64 bit, Intel i5 650 @ 3.20GHz

$ seq 1 3 | xargs -Iz python aes.py
pycrypto: 2.05s
M2Crypto: 0.92s
pycrypto: 2.04s
M2Crypto: 0.92s
pycrypto: 2.03s
M2Crypto: 0.90s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment