AES Cipher with Python 3.x

11-05-2015 11:10 by depado

AES Cipher

Note that you'll need the pycrypto library to use this. This is an example on how to write an AES Cipher that works with Python 3.x.
It is actually easier to work with cryptographic operations using Python 2.x because the string representation is bytes. That's why there is an extra method in this cipher to ensure that the data type is respected and will work in any case.

import base64
import hashlib

from Crypto import Random
from Crypto.Cipher import AES

class AESCipher(object):
    A classical AES Cipher. Can use any size of data and any size of password thanks to padding.
    Also ensure the coherence and the type of the data with a unicode to byte converter.
    def __init__(self, key):
        self.bs = 32
        self.key = hashlib.sha256(AESCipher.str_to_bytes(key)).digest()

    def str_to_bytes(data):
        u_type = type(b''.decode('utf8'))
        if isinstance(data, u_type):
            return data.encode('utf8')
        return data

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * AESCipher.str_to_bytes(chr(self.bs - len(s) % self.bs))

    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

    def encrypt(self, raw):
        raw = self._pad(AESCipher.str_to_bytes(raw))
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw)).decode('utf-8')

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
>>> cipher = AESCipher(key='mykey')
>>> encrypted = cipher.encrypt("Hello World")
>>> print(encrypted)
>>> new_cipher = AESCipher(key='mykey')
>>> decrypted = new_cipher.decrypt('/pgzr3fby2MD6hOvkzjAz6xRdkzzhOHG+iI0ZaPS7QWUGFppkgBybKY0RXzBaXAS')
>>> print(decrypted)
'Hello World'