File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/lib/util_crypto.py
import base64
import hashlib
import binascii
from Crypto import Random
from Crypto.Cipher import AES
from flask import current_app as app
from sqlalchemy import String
from sqlalchemy import TypeDecorator
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s: s[0:-s[-1]].decode()
class AESCipher:
def __init__(self, key):
self.key = key.encode('utf8')
def encrypt(self, raw):
raw = pad(raw)
iv = Random.new().read(AES.block_size)
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw.encode('utf8'))).decode()
def decrypt(self, enc):
enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return unpad(cipher.decrypt(enc[16:]))
# This class is being created to accommodate Symmetric Encryption Client Side where encryption is handled
# through a TypeDecorator for database field encryption. Read more;
# https://github.com/sqlalchemy/sqlalchemy/wiki/SymmetricEncryptionClientSide#example-two---use-typedecorator
class SymEncryption:
def __init__(self, key, nonce):
self.key = key.encode('utf8')
self.nonce = nonce.encode('utf8')
def sym_encrypt(self, data):
cipher = AES.new(self.key, AES.MODE_EAX, nonce=self.nonce)
data = data + (" " * (16 - (len(data) % 16)))
return cipher.encrypt(data.encode("utf-8")).hex()
def sym_decrypt(self, data):
cipher = AES.new(self.key, AES.MODE_EAX, nonce=self.nonce)
data = data.encode('utf-8')
return cipher.decrypt(binascii.unhexlify(data)).decode("utf-8").rstrip()
class EncryptedValue(TypeDecorator):
impl = String
def process_bind_param(self, value, dialect):
if type(value) == list:
return value
ec_key = app.config['SYM_CRYPTO_SECRET_KEY']
ec_nonce = app.config['SYM_CRYPTO_NONCE']
sym = SymEncryption(ec_key, ec_nonce)
return sym.sym_encrypt(value)
def process_result_value(self, value, dialect):
if value:
if len(value) < 32:
return value
else:
try:
ec_key = app.config['SYM_CRYPTO_SECRET_KEY']
ec_nonce = app.config['SYM_CRYPTO_NONCE']
sym = SymEncryption(ec_key, ec_nonce)
return sym.sym_decrypt(value)
except:
return value
else:
return ''
class SHA:
@staticmethod
def encrypt(hash_string):
sha_signature = hashlib.sha256(hash_string.encode()).hexdigest()
return sha_signature