Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / db / aes_encrypt.py @ 91884d63

History | View | Annotate | Download (3.5 kB)

1
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

    
30
from binascii import b2a_base64, a2b_base64
31
from Crypto.Cipher import AES
32
from Crypto import Random
33
from random import choice
34
from string import letters, digits
35
from synnefo.settings import SECRET_ENCRYPTION_KEY
36

    
37

    
38
DB_ENCRYPTED_FIELD_PREFIX = 'encrypted'
39
SALT_LEN = 8
40

    
41

    
42
def _pad_secret(secret, blocksize=32, padding='}'):
43
    len_secret = len(secret)
44
    if len_secret > 32:
45
        raise ValueError('Encryption key must be smaller than 32 bytes')
46
    if not len_secret in (16, 24, 32):
47
        return secret + (blocksize - len(secret)) * padding
48
    return secret
49

    
50

    
51
def encrypt(s, iv):
52
    obj = AES.new(_pad_secret(SECRET_ENCRYPTION_KEY), AES.MODE_CFB, iv)
53
    return obj.encrypt(s)
54

    
55

    
56
def decrypt(s, iv):
57
    obj = AES.new(_pad_secret(SECRET_ENCRYPTION_KEY), AES.MODE_CFB, iv)
58
    return obj.decrypt(s)
59

    
60

    
61
def encrypt_db_charfield(plaintext):
62
    if not plaintext:
63
        return plaintext
64
    salt = "".join([choice(letters + digits) for i in xrange(SALT_LEN)])
65

    
66
    iv = Random.get_random_bytes(16)
67
    plaintext = "%s%s" % (salt, plaintext)
68
    # Encrypt and convert to binary
69
    ciphertext = b2a_base64(encrypt(plaintext, iv))
70
    iv = b2a_base64(iv)
71
    # Append prefix,salt and return encoded value
72
    final = '%s:%s:%s$%s' % (DB_ENCRYPTED_FIELD_PREFIX, iv, salt, ciphertext)
73
    return final.encode('utf8')
74

    
75

    
76
def decrypt_db_charfield(ciphertext):
77
    if not ciphertext:
78
        return ciphertext
79
    has_prefix = ciphertext.startswith(DB_ENCRYPTED_FIELD_PREFIX + ':')
80
    if not has_prefix:  # Non-encoded value
81
        return ciphertext
82
    else:
83
        _, iv, ciphertext = ciphertext.split(':')
84

    
85
    pure_salt, encrypted = ciphertext.split('$')
86
    iv = a2b_base64(iv)
87

    
88
    plaintext = decrypt(a2b_base64(encrypted), iv)
89

    
90
    salt = plaintext[:SALT_LEN]
91
    plaintext = plaintext[SALT_LEN:]
92

    
93
    if salt != pure_salt:
94
        # Cannot decrtypt password
95
        raise CorruptedPassword("Cannot decrypt password. Check the key")
96
    else:
97
        return plaintext
98

    
99

    
100
class CorruptedPassword(Exception):
101
    pass