public
Last active

AES-CBC shared-key crypto with hmac signing

  • Download Gist
magiccrypt.py
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
# -*- coding: utf-8 -*-
 
"""Part of an answer to http://stackoverflow.com/questions/7296535/easy-to-use-python-encryption-library-wrapper/7296656#7296656"""
 
import hashlib
import hmac
import os
import random
from Crypto.Cipher import AES
 
 
class AuthenticationError(Exception):
pass
 
 
class MagicCrypt(object):
AES_BLOCK_SIZE = 32
SIG_SIZE = hashlib.sha256().digest_size
def __init__(self, key):
self.key = self._hash_key(key)
def _hash_key(self, key):
"""Return a key suitable for use with the cipher"""
return hashlib.sha256(key).digest()
def _initialisation_vector(self):
"""get a random initialisation vector"""
return os.urandom(16)
def _cipher(self, key, iv):
"""Return a cipher. An object that implements .encrypt() and
.decrypt()
"""
return AES.new(key, AES.MODE_CBC, iv)
def encrypt(self, data):
iv = self._initialisation_vector()
cipher = self._cipher(self.key, iv)
## get the required padding length
pad = self.AES_BLOCK_SIZE - len(data) % self.AES_BLOCK_SIZE
## pad the data by appending repeate char
data = data + pad * chr(pad)
## encrypt and prepend the initialisation vector
data = iv + cipher.encrypt(data)
## hash the encrypted data
sig = hmac.new(self.key, data, hashlib.sha256).digest()
## append the hash to the data
return data + sig
def decrypt(self, data):
## extract the hash
sig = data[-self.SIG_SIZE:]
data = data[:-self.SIG_SIZE]
## check the encrypted data is valid using the hmac hash
if hmac.new(self.key, data, hashlib.sha256).digest() != sig:
raise AuthenticationError("message authentication failed")
## extract the initialisation vector
iv = data[:16]
data = data[16:]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
## decrypt
data = cipher.decrypt(data)
## remove the padding
return data[:-ord(data[-1])]
 
 
 
if __name__ == '__main__':
s = 'This is a secret'
crypt = MagicCrypt('mypassword')
encrypted = crypt.encrypt(s)
decrypted = crypt.decrypt(encrypted)
print decrypted == s

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.