root / snfcycladesapp / synnefo / db / aes_encrypt.py @ 4911365b
History  View  Annotate  Download (2 kB)
1 
from binascii import b2a_base64, a2b_base64 

2 
from Crypto.Cipher import AES 
3 
from Crypto import Random 
4 
from random import choice 
5 
from string import letters, digits 
6 
from synnefo.settings import SECRET_ENCRYPTION_KEY 
7  
8  
9 
DB_ENCRYPTED_FIELD_PREFIX = 'encrypted'

10 
SALT_LEN = 8

11  
12  
13 
def _pad_secret(secret, blocksize=32, padding='}'): 
14 
len_secret = len(secret)

15 
if len_secret > 32: 
16 
raise ValueError('Encryption key must be smaller than 32 bytes') 
17 
if not len_secret in (16, 24, 32): 
18 
return secret + (blocksize  len(secret)) * padding 
19 
return secret

20  
21  
22 
def encrypt(s, iv): 
23 
obj = AES.new(_pad_secret(SECRET_ENCRYPTION_KEY), AES.MODE_CFB, iv) 
24 
return obj.encrypt(s)

25  
26  
27 
def decrypt(s, iv): 
28 
obj = AES.new(_pad_secret(SECRET_ENCRYPTION_KEY), AES.MODE_CFB, iv) 
29 
return obj.decrypt(s)

30  
31  
32 
def encrypt_db_charfield(plaintext): 
33 
if not plaintext: 
34 
return plaintext

35 
salt = "".join([choice(letters + digits) for i in xrange(SALT_LEN)]) 
36  
37 
iv = Random.get_random_bytes(16)

38 
plaintext = "%s%s" % (salt, plaintext)

39 
# Encrypt and convert to binary

40 
ciphertext = b2a_base64(encrypt(plaintext, iv)) 
41 
iv = b2a_base64(iv) 
42 
# Append prefix,salt and return encoded value

43 
final = '%s:%s:%s$%s' % (DB_ENCRYPTED_FIELD_PREFIX, iv, salt, ciphertext)

44 
return final.encode('utf8') 
45  
46  
47 
def decrypt_db_charfield(ciphertext): 
48 
if not ciphertext: 
49 
return ciphertext

50 
has_prefix = ciphertext.startswith(DB_ENCRYPTED_FIELD_PREFIX + ':')

51 
if not has_prefix: # Nonencoded value 
52 
return ciphertext

53 
else:

54 
_, iv, ciphertext = ciphertext.split(':')

55  
56 
pure_salt, encrypted = ciphertext.split('$')

57 
iv = a2b_base64(iv) 
58  
59 
plaintext = decrypt(a2b_base64(encrypted), iv) 
60  
61 
salt = plaintext[:SALT_LEN] 
62 
plaintext = plaintext[SALT_LEN:] 
63  
64 
if salt != pure_salt:

65 
# Can not decrtypt password

66 
raise CorruptedPassword("Can not decrypt password. Check the key") 
67 
else:

68 
return plaintext

69  
70  
71 
class CorruptedPassword(Exception): 
72 
pass
