# -*- coding: utf8 -*- from Crypto.Cipher import AES from Crypto.Hash import SHA256 from os import urandom import base64 #**************************************************************************************** # Class providing AES-128 CBC with PKCS7 padding cryptographic operations #**************************************************************************************** class Crypto(object): #----------------------------------------------------------- @classmethod def createKey(cls, outputFormat = "raw"): if outputFormat == "raw": return urandom(16) # 128bits AES is an agreed trade off between security and performances else: return base64.b64encode(urandom(16)) #----------------------------------------------------------- @classmethod def encryptData(cls, clearText, key): """Encrypts data with the provided key. The returned byte array is as follow: :==============:==================================================: : IV (16bytes) : Encrypted (data + PKCS7 padding information) : :==============:==================================================: """ # Generate a crypto secure random Initialization Vector iv = urandom(AES.block_size) # Perform PKCS7 padding so that clearText is a multiple of the block size clearText = cls.pad(clearText) cipher = AES.new(key, AES.MODE_CBC, iv) return iv + cipher.encrypt(clearText) #----------------------------------------------------------- @classmethod def decryptData(cls, cipherText, key): """Decrypt data with the provided key""" # Initialization Vector is in the first 16 bytes iv = cipherText[:AES.block_size] cipher = AES.new(key, AES.MODE_CBC, iv) return cls.unpad(cipher.decrypt(cipherText[AES.block_size:])) #------------------------------------------------------------------------ @classmethod def xor(cls, data, key): l = len(key) keyAsInt = map(ord, key) return bytes(bytearray(( (data[i] ^ keyAsInt[i % l]) for i in range(0,len(data)) ))) #------------------------------------------------------------------------ @classmethod def convertKey(cls, key, outputFormat = "raw"): if outputFormat == "raw": return base64.b64decode(key) elif outputFormat == "sha256": return SHA256.new(key).hexdigest() else: return base64.b64encode(key) #------------------------------------------------------------------------ @classmethod def pad(cls, s): """PKCS7 padding""" return s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size) #------------------------------------------------------------------------ @classmethod def unpad(cls, s): """PKCS7 padding removal""" return s[:-ord(s[len(s)-1:])]