Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / db / aes_encrypt.py @ 0224049a

History | View | Annotate | Download (1.8 kB)

1
from binascii import b2a_base64, a2b_base64
2
from Crypto.Cipher import AES
3
from random import choice
4
from string import letters, digits
5
from synnefo.settings import SECRET_ENCRYPTION_KEY
6

    
7

    
8
DB_ENCRYPTED_FIELD_PREFIX = 'encrypted'
9
SALT_LEN = 8
10

    
11

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

    
20

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

    
25

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

    
30

    
31
def encrypt_db_charfield(plaintext):
32
    if plaintext == None:
33
        return plaintext
34
    salt = "".join([choice(letters + digits) for i in xrange(SALT_LEN)])
35

    
36
    plaintext = "%s%s" % (salt, plaintext)
37
    # Encrypt and convert to binary
38
    ciphertext = b2a_base64(encrypt(plaintext))
39
    # Append prefix,salt and return encoded value
40
    final = '%s:%s$%s' % (DB_ENCRYPTED_FIELD_PREFIX, salt, ciphertext)
41
    return final.encode('utf8')
42

    
43

    
44
def decrypt_db_charfield(ciphertext):
45
    if ciphertext == None:
46
        return ciphertext
47
    has_prefix = ciphertext.startswith(DB_ENCRYPTED_FIELD_PREFIX + ':')
48
    if not has_prefix:  # Non-encoded value
49
        return ciphertext
50
    else:
51
        _, ciphertext = ciphertext.split(':')
52

    
53
    pure_salt, encrypted = ciphertext.split('$')
54

    
55
    plaintext = decrypt(a2b_base64(encrypted))
56

    
57
    salt = plaintext[:SALT_LEN]
58
    plaintext = plaintext[SALT_LEN:]
59

    
60
    if salt != pure_salt:
61
        # Can not decrtypt password
62
        raise CorruptedPassword("Can not decrypt password. Check the key")
63
    else:
64
        return plaintext
65

    
66

    
67
class CorruptedPassword(Exception):
68
    pass