# HG changeset patch # User souliane # Date 1404674027 -7200 # Node ID 77cd312d32c430ceaa7e0a4800aa7cf6d8dd2cf1 # Parent dace0ede919c70dae21278cd542454e1d26f684b memory: fixes encoding issues during encryption diff -r dace0ede919c -r 77cd312d32c4 src/memory/crypto.py --- a/src/memory/crypto.py Fri Jun 27 20:05:31 2014 +0200 +++ b/src/memory/crypto.py Sun Jul 06 21:13:47 2014 +0200 @@ -42,17 +42,18 @@ Based on http://stackoverflow.com/a/12525165 - @param key (str): the encryption key - @param text (str): the text to encrypt + @param key (unicode): the encryption key + @param text (unicode): the text to encrypt @param leave_empty (bool): if True, empty text will be returned "as is" @return: Deferred: base-64 encoded str """ if leave_empty and text == '': return succeed(text) iv = BlockCipher.getRandomKey() + key = key.encode('utf-8') key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key) cipher = AES.new(key, AES.MODE_CFB, iv) - d = deferToThread(cipher.encrypt, BlockCipher.pad(text)) + d = deferToThread(cipher.encrypt, BlockCipher.pad(text.encode('utf-8'))) d.addCallback(lambda ciphertext: b64encode(iv + ciphertext)) return d @@ -62,7 +63,7 @@ Based on http://stackoverflow.com/a/12525165 - @param key (str): the decryption key + @param key (unicode): the decryption key @param ciphertext (base-64 encoded str): the text to decrypt @param leave_empty (bool): if True, empty ciphertext will be returned "as is" @return: Deferred: str or None if the password could not be decrypted @@ -71,6 +72,7 @@ return succeed('') ciphertext = b64decode(ciphertext) iv, ciphertext = ciphertext[:BlockCipher.IV_SIZE], ciphertext[BlockCipher.IV_SIZE:] + key = key.encode('utf-8') key = key[:BlockCipher.MAX_KEY_SIZE] if len(key) >= BlockCipher.MAX_KEY_SIZE else BlockCipher.pad(key) cipher = AES.new(key, AES.MODE_CFB, iv) d = deferToThread(cipher.decrypt, ciphertext) @@ -79,7 +81,7 @@ # a decrypted empty value and a decryption failure... both return # the empty value. Fortunately, we detect empty passwords beforehand # thanks to the "leave_empty" parameter which is used by default. - d.addCallback(lambda text: text if text else None) + d.addCallback(lambda text: text.decode('utf-8') if text else None) return d @classmethod diff -r dace0ede919c -r 77cd312d32c4 src/test/test_memory_crypto.py --- a/src/test/test_memory_crypto.py Fri Jun 27 20:05:31 2014 +0200 +++ b/src/test/test_memory_crypto.py Sun Jul 06 21:13:47 2014 +0200 @@ -23,10 +23,16 @@ from sat.test import helpers from sat.memory.crypto import BlockCipher, PasswordHasher -from os import urandom +import random +import string from twisted.internet import defer +def getRandomUnicode(len): + """Return a random unicode string""" + return u''.join(random.choice(string.letters + u"éáúóâêûôßüöä") for i in xrange(len)) + + class CryptoTest(helpers.SatTestCase): def setUp(self): @@ -42,9 +48,9 @@ d_list.append(d) for key_len in (0, 2, 8, 10, 16, 24, 30, 32, 40): - key = urandom(key_len) + key = getRandomUnicode(key_len) for message_len in (0, 2, 16, 24, 32, 100): - message = urandom(message_len) + message = getRandomUnicode(message_len) test(key, message) return defer.DeferredList(d_list) @@ -57,7 +63,7 @@ d1 = PasswordHasher.verify(password, hashed) d1.addCallback(lambda result: self.assertTrue(result)) d_list.append(d1) - attempt = urandom(10) + attempt = getRandomUnicode(10) d2 = PasswordHasher.verify(attempt, hashed) d2.addCallback(lambda result: self.assertFalse(result)) d_list.append(d2)