Skip to content

Instantly share code, notes, and snippets.

@tmarthal
Last active December 18, 2018 09:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tmarthal/cf5a610c5c5ab1e661a6351c96200706 to your computer and use it in GitHub Desktop.
Save tmarthal/cf5a610c5c5ab1e661a6351c96200706 to your computer and use it in GitHub Desktop.
PyCrypto AES256 Encoding with Initialization Vectors Matching Spring Security
class AesCrypt256:
#Based on https://gist.github.com/pfote/5099161
BLOCK_SIZE = 16
# To use the null/x00 byte array for the IV
default_initialization_vector = False
def __init__(self, default_initialization_vector=False):
self.default_initialization_vector = default_initialization_vector
def pkcs5_pad(self,s):
return s + (self.BLOCK_SIZE - len(s) % self.BLOCK_SIZE) * chr(self.BLOCK_SIZE - len(s) % self.BLOCK_SIZE)
def pkcs5_unpad(self, s):
# from https://jhafranco.com/2012/01/16/aes-implementation-in-python/
return "".join(chr(e) for e in s[:-s[-1]])
def _encrypt(self, key, value, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
crypted = cipher.encrypt(self.pkcs5_pad(value).encode('utf-8'))
# check if empty/null initialization vector, and do not prepend if null
if all(v == 0 for v in iv):
return crypted
else:
# prepend the initialization vector
return iv+crypted
def _decrypt(self, key, value, iv):
cipher = AES.new(key, AES.MODE_CBC, iv)
# unpad the bytes, throw away garbage at end
return self.pkcs5_unpad(cipher.decrypt(value))
def encrypt(self, key, value):
if self.default_initialization_vector:
return self._encrypt(key, value, bytes(bytearray(16)))
else:
iv = Random.get_random_bytes(16)
return self._encrypt(key, value, iv)
def decrypt(self, key, value):
if self.default_initialization_vector:
# we do not have an IV present
default_iv = bytes(bytearray(16))
return self._decrypt(key, value, default_iv)
else:
iv = value[:16]
crypted = value[16:]
return self._decrypt(key, crypted, iv)
def encryptHex(self, key, value):
return binascii.hexlify(self.encrypt(key, value))
def decryptHex(self, key, value):
return self.decrypt(key, binascii.unhexlify(value))
>>> encryptor = AesCrypt256(default_initialization_vector=False)
>>> encryptor.decryptHex(key,'98937740c652f6a17febce5013d7d13aed67a8867365e5a89374e658ad74f742')
'foo'
>>> encryptor.decryptHex(key,'e3673e05560e1d24f26b4a6ed300a298c17cb9d7be9a52f11d9358421a79c015')
'foo'
>>> encryptor = AesCrypt256(default_initialization_vector=True)
>>> encryptor.decryptHex(key,'a070fa1b40dafa6d7c55ee697c4cb448')
'foo'
b'a070fa1b40dafa6d7c55ee697c4cb448'
b'a070fa1b40dafa6d7c55ee697c4cb448'
b'a070fa1b40dafa6d7c55ee697c4cb448'
encryptor = AesCrypt256(default_initialization_vector=True)
for _ in range(3):
print(encryptor.encryptHex(key, 'foo'))
b'41605549007b8d29038777dfd57a1d346fa6a3a34508c311ff5492be281fb269'
b'4c11d16fc12d8456bb636851943aebb2e94c39e8c7e5242cf01b736f0fae4df1'
b'054f1938a77f98985a6dd920694d3e5cd70f9e2a95fbf285df743d6f9e648b36'
# Random symmetric test
password = 'password'
salt = binascii.unhexlify('5c0744940b5c369b')
iterations = 1024
# AES uses 256 bit encryption, 32 bytes
key = PBKDF2(password=password, salt=salt, dkLen=32, count=iterations)
encryptor = AesCrypt256(default_initialization_vector=False)
for _ in range(3):
print(encryptor.encryptHex(key, 'foo'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment