comparison src/memory/crypto.py @ 1098:77cd312d32c4

memory: fixes encoding issues during encryption
author souliane <souliane@mailoo.org>
date Sun, 06 Jul 2014 21:13:47 +0200
parents 127c96020022
children 069ad98b360d
comparison
equal deleted inserted replaced
1097:dace0ede919c 1098:77cd312d32c4
40 def encrypt(cls, key, text, leave_empty=True): 40 def encrypt(cls, key, text, leave_empty=True):
41 """Encrypt a message. 41 """Encrypt a message.
42 42
43 Based on http://stackoverflow.com/a/12525165 43 Based on http://stackoverflow.com/a/12525165
44 44
45 @param key (str): the encryption key 45 @param key (unicode): the encryption key
46 @param text (str): the text to encrypt 46 @param text (unicode): the text to encrypt
47 @param leave_empty (bool): if True, empty text will be returned "as is" 47 @param leave_empty (bool): if True, empty text will be returned "as is"
48 @return: Deferred: base-64 encoded str 48 @return: Deferred: base-64 encoded str
49 """ 49 """
50 if leave_empty and text == '': 50 if leave_empty and text == '':
51 return succeed(text) 51 return succeed(text)
52 iv = BlockCipher.getRandomKey() 52 iv = BlockCipher.getRandomKey()
53 key = key.encode('utf-8')
53 key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key) 54 key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key)
54 cipher = AES.new(key, AES.MODE_CFB, iv) 55 cipher = AES.new(key, AES.MODE_CFB, iv)
55 d = deferToThread(cipher.encrypt, BlockCipher.pad(text)) 56 d = deferToThread(cipher.encrypt, BlockCipher.pad(text.encode('utf-8')))
56 d.addCallback(lambda ciphertext: b64encode(iv + ciphertext)) 57 d.addCallback(lambda ciphertext: b64encode(iv + ciphertext))
57 return d 58 return d
58 59
59 @classmethod 60 @classmethod
60 def decrypt(cls, key, ciphertext, leave_empty=True): 61 def decrypt(cls, key, ciphertext, leave_empty=True):
61 """Decrypt a message. 62 """Decrypt a message.
62 63
63 Based on http://stackoverflow.com/a/12525165 64 Based on http://stackoverflow.com/a/12525165
64 65
65 @param key (str): the decryption key 66 @param key (unicode): the decryption key
66 @param ciphertext (base-64 encoded str): the text to decrypt 67 @param ciphertext (base-64 encoded str): the text to decrypt
67 @param leave_empty (bool): if True, empty ciphertext will be returned "as is" 68 @param leave_empty (bool): if True, empty ciphertext will be returned "as is"
68 @return: Deferred: str or None if the password could not be decrypted 69 @return: Deferred: str or None if the password could not be decrypted
69 """ 70 """
70 if leave_empty and ciphertext == '': 71 if leave_empty and ciphertext == '':
71 return succeed('') 72 return succeed('')
72 ciphertext = b64decode(ciphertext) 73 ciphertext = b64decode(ciphertext)
73 iv, ciphertext = ciphertext[:BlockCipher.IV_SIZE], ciphertext[BlockCipher.IV_SIZE:] 74 iv, ciphertext = ciphertext[:BlockCipher.IV_SIZE], ciphertext[BlockCipher.IV_SIZE:]
75 key = key.encode('utf-8')
74 key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key) 76 key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key)
75 cipher = AES.new(key, AES.MODE_CFB, iv) 77 cipher = AES.new(key, AES.MODE_CFB, iv)
76 d = deferToThread(cipher.decrypt, ciphertext) 78 d = deferToThread(cipher.decrypt, ciphertext)
77 d.addCallback(lambda text: BlockCipher.unpad(text)) 79 d.addCallback(lambda text: BlockCipher.unpad(text))
78 # XXX: cipher.decrypt gives no way to make the distinction between 80 # XXX: cipher.decrypt gives no way to make the distinction between
79 # a decrypted empty value and a decryption failure... both return 81 # a decrypted empty value and a decryption failure... both return
80 # the empty value. Fortunately, we detect empty passwords beforehand 82 # the empty value. Fortunately, we detect empty passwords beforehand
81 # thanks to the "leave_empty" parameter which is used by default. 83 # thanks to the "leave_empty" parameter which is used by default.
82 d.addCallback(lambda text: text if text else None) 84 d.addCallback(lambda text: text.decode('utf-8') if text else None)
83 return d 85 return d
84 86
85 @classmethod 87 @classmethod
86 def getRandomKey(cls, size=None, base64=False): 88 def getRandomKey(cls, size=None, base64=False):
87 """Return a random key suitable for block cipher encryption. 89 """Return a random key suitable for block cipher encryption.