From ce0d421e41cfb75a3957541d6c88fcd7b26e8cd6 Mon Sep 17 00:00:00 2001 From: drebs Date: Fri, 28 Nov 2014 11:50:15 -0200 Subject: Add encryption scheme, method and iv to symmetrically encrypted document MAC (#6400). --- .../feature_6400_include-iv-in-document-mac | 1 + client/src/leap/soledad/client/crypto.py | 174 ++++++++++++--------- client/src/leap/soledad/client/secrets.py | 79 ++++------ common/src/leap/soledad/common/crypto.py | 8 +- common/src/leap/soledad/common/tests/__init__.py | 2 +- .../src/leap/soledad/common/tests/test_crypto.py | 52 +++--- .../src/leap/soledad/common/tests/test_soledad.py | 62 ++++---- 7 files changed, 195 insertions(+), 183 deletions(-) create mode 100644 client/changes/feature_6400_include-iv-in-document-mac diff --git a/client/changes/feature_6400_include-iv-in-document-mac b/client/changes/feature_6400_include-iv-in-document-mac new file mode 100644 index 00000000..d8c9c9cc --- /dev/null +++ b/client/changes/feature_6400_include-iv-in-document-mac @@ -0,0 +1 @@ + o Include the IV in the encrypted document MAC (#6400). diff --git a/client/src/leap/soledad/client/crypto.py b/client/src/leap/soledad/client/crypto.py index 681bf4f7..d6d9a618 100644 --- a/client/src/leap/soledad/client/crypto.py +++ b/client/src/leap/soledad/client/crypto.py @@ -32,18 +32,8 @@ from zope.proxy import sameProxiedObjects from leap.soledad.common import soledad_assert from leap.soledad.common import soledad_assert_type +from leap.soledad.common import crypto from leap.soledad.common.document import SoledadDocument -from leap.soledad.common.crypto import EncryptionSchemes -from leap.soledad.common.crypto import EncryptionMethods -from leap.soledad.common.crypto import MacMethods -from leap.soledad.common.crypto import UnknownMacMethod -from leap.soledad.common.crypto import WrongMac -from leap.soledad.common.crypto import ENC_JSON_KEY -from leap.soledad.common.crypto import ENC_SCHEME_KEY -from leap.soledad.common.crypto import ENC_METHOD_KEY -from leap.soledad.common.crypto import ENC_IV_KEY -from leap.soledad.common.crypto import MAC_KEY -from leap.soledad.common.crypto import MAC_METHOD_KEY logger = logging.getLogger(__name__) @@ -59,13 +49,16 @@ def _assert_known_encryption_method(method): :param method: The encryption method to assert. :type method: str - :raise AssertionError: Raised if C{method} is unknown. + :raise UnknownEncryptionMethodError: Raised when C{method} is unknown. """ valid_methods = [ - EncryptionMethods.AES_256_CTR, - EncryptionMethods.XSALSA20, + crypto.EncryptionMethods.AES_256_CTR, + crypto.EncryptionMethods.XSALSA20, ] - soledad_assert(method in valid_methods) + try: + soledad_assert(method in valid_methods) + except AssertionError: + raise crypto.UnknownEncryptionMethodError def encrypt_sym(data, key, method): @@ -96,11 +89,11 @@ def encrypt_sym(data, key, method): iv = None # AES-256 in CTR mode - if method == EncryptionMethods.AES_256_CTR: + if method == crypto.EncryptionMethods.AES_256_CTR: iv = os.urandom(16) ciphertext = AES(key=key, iv=iv).process(data) # XSalsa20 - elif method == EncryptionMethods.XSALSA20: + elif method == crypto.EncryptionMethods.XSALSA20: iv = os.urandom(24) ciphertext = XSalsa20(key=key, iv=iv).process(data) @@ -125,7 +118,7 @@ def decrypt_sym(data, key, method, **kwargs): :return: The decrypted data. :rtype: str - :raise AssertionError: Raised if C{method} is unknown. + :raise UnknownEncryptionMethodError: Raised when C{method} is unknown. """ soledad_assert_type(key, str) # assert params @@ -137,10 +130,10 @@ def decrypt_sym(data, key, method, **kwargs): '%s needs an initial value.' % method) _assert_known_encryption_method(method) # AES-256 in CTR mode - if method == EncryptionMethods.AES_256_CTR: + if method == crypto.EncryptionMethods.AES_256_CTR: return AES( key=key, iv=binascii.a2b_base64(kwargs['iv'])).process(data) - elif method == EncryptionMethods.XSALSA20: + elif method == crypto.EncryptionMethods.XSALSA20: return XSalsa20( key=key, iv=binascii.a2b_base64(kwargs['iv'])).process(data) @@ -185,11 +178,11 @@ class SoledadCrypto(object): self._soledad = soledad def encrypt_sym(self, data, key, - method=EncryptionMethods.AES_256_CTR): + method=crypto.EncryptionMethods.AES_256_CTR): return encrypt_sym(data, key, method) def decrypt_sym(self, data, key, - method=EncryptionMethods.AES_256_CTR, **kwargs): + method=crypto.EncryptionMethods.AES_256_CTR, **kwargs): return decrypt_sym(data, key, method, **kwargs) def doc_mac_key(self, doc_id, secret): @@ -233,7 +226,8 @@ class SoledadCrypto(object): # Crypto utilities for a SoledadDocument. # -def mac_doc(doc_id, doc_rev, ciphertext, mac_method, secret): +def mac_doc(doc_id, doc_rev, ciphertext, enc_scheme, enc_method, enc_iv, + mac_method, secret): """ Calculate a MAC for C{doc} using C{ciphertext}. @@ -249,6 +243,12 @@ def mac_doc(doc_id, doc_rev, ciphertext, mac_method, secret): :type doc_rev: str :param ciphertext: The content of the document. :type ciphertext: str + :param enc_scheme: The encryption scheme. + :type enc_scheme: str + :param enc_method: The encryption method. + :type enc_method: str + :param enc_iv: The encryption initialization vector. + :type enc_iv: str :param mac_method: The MAC method to use. :type mac_method: str :param secret: The Soledad storage secret @@ -257,15 +257,20 @@ def mac_doc(doc_id, doc_rev, ciphertext, mac_method, secret): :return: The calculated MAC. :rtype: str - :raise UnknownMacMethod: Raised when C{mac_method} is unknown. + :raise crypto.UnknownMacMethodError: Raised when C{mac_method} is unknown. """ try: - soledad_assert(mac_method == MacMethods.HMAC) + soledad_assert(mac_method == crypto.MacMethods.HMAC) except AssertionError: - raise UnknownMacMethod - content = str(doc_id) \ - + str(doc_rev) \ - + ciphertext + raise crypto.UnknownMacMethodError + template = "{doc_id}{doc_rev}{ciphertext}{enc_scheme}{enc_method}{enc_iv}" + content = template.format( + doc_id=doc_id, + doc_rev=doc_rev, + ciphertext=ciphertext, + enc_scheme=enc_scheme, + enc_method=enc_method, + enc_iv=enc_iv) return hmac.new( doc_mac_key(doc_id, secret), content, @@ -297,12 +302,12 @@ def encrypt_docstr(docstr, doc_id, doc_rev, key, secret): string representing the following: { - ENC_JSON_KEY: '', - ENC_SCHEME_KEY: 'symkey', - ENC_METHOD_KEY: EncryptionMethods.AES_256_CTR, - ENC_IV_KEY: '', + crypto.ENC_JSON_KEY: '', + crypto.ENC_SCHEME_KEY: 'symkey', + crypto.ENC_METHOD_KEY: crypto.EncryptionMethods.AES_256_CTR, + crypto.ENC_IV_KEY: '', MAC_KEY: '' - MAC_METHOD_KEY: 'hmac' + crypto.MAC_METHOD_KEY: 'hmac' } :param docstr: A representation of the document to be encrypted. @@ -324,10 +329,10 @@ def encrypt_docstr(docstr, doc_id, doc_rev, key, secret): content. :rtype: str """ - enc_scheme = EncryptionSchemes.SYMKEY - enc_method = EncryptionMethods.AES_256_CTR - mac_method = MacMethods.HMAC - iv, ciphertext = encrypt_sym( + enc_scheme = crypto.EncryptionSchemes.SYMKEY + enc_method = crypto.EncryptionMethods.AES_256_CTR + mac_method = crypto.MacMethods.HMAC + enc_iv, ciphertext = encrypt_sym( str(docstr), # encryption/decryption routines expect str key, method=enc_method) mac = binascii.b2a_hex( # store the mac as hex. @@ -335,6 +340,9 @@ def encrypt_docstr(docstr, doc_id, doc_rev, key, secret): doc_id, doc_rev, ciphertext, + enc_scheme, + enc_method, + enc_iv, mac_method, secret)) # Return a representation for the encrypted content. In the following, we @@ -342,12 +350,12 @@ def encrypt_docstr(docstr, doc_id, doc_rev, key, secret): # serialization does not complain about what it tries to serialize. hex_ciphertext = binascii.b2a_hex(ciphertext) return json.dumps({ - ENC_JSON_KEY: hex_ciphertext, - ENC_SCHEME_KEY: enc_scheme, - ENC_METHOD_KEY: enc_method, - ENC_IV_KEY: iv, - MAC_KEY: mac, - MAC_METHOD_KEY: mac_method, + crypto.ENC_JSON_KEY: hex_ciphertext, + crypto.ENC_SCHEME_KEY: enc_scheme, + crypto.ENC_METHOD_KEY: enc_method, + crypto.ENC_IV_KEY: enc_iv, + crypto.MAC_KEY: mac, + crypto.MAC_METHOD_KEY: mac_method, }) @@ -369,7 +377,8 @@ def decrypt_doc(crypto, doc): return decrypt_doc_dict(doc.content, doc.doc_id, doc.rev, key, secret) -def _verify_doc_mac(doc_id, doc_rev, ciphertext, mac_method, secret, doc_mac): +def _verify_doc_mac(doc_id, doc_rev, ciphertext, enc_scheme, enc_method, + enc_iv, mac_method, secret, doc_mac): """ Verify that C{doc_mac} is a correct MAC for the given document. @@ -379,6 +388,12 @@ def _verify_doc_mac(doc_id, doc_rev, ciphertext, mac_method, secret, doc_mac): :type doc_rev: str :param ciphertext: The content of the document. :type ciphertext: str + :param enc_scheme: The encryption scheme. + :type enc_scheme: str + :param enc_method: The encryption method. + :type enc_method: str + :param enc_iv: The encryption initialization vector. + :type enc_iv: str :param mac_method: The MAC method to use. :type mac_method: str :param secret: The Soledad storage secret @@ -386,12 +401,16 @@ def _verify_doc_mac(doc_id, doc_rev, ciphertext, mac_method, secret, doc_mac): :param doc_mac: The MAC to be verified against. :type doc_mac: str - :raise UnknownMacMethod: Raised when C{mac_method} is unknown. + :raise crypto.UnknownMacMethodError: Raised when C{mac_method} is unknown. + :raise crypto.WrongMacError: Raised when MAC could not be verified. """ calculated_mac = mac_doc( doc_id, doc_rev, ciphertext, + enc_scheme, + enc_method, + enc_iv, mac_method, secret) # we compare mac's hashes to avoid possible timing attacks that might @@ -404,7 +423,8 @@ def _verify_doc_mac(doc_id, doc_rev, ciphertext, mac_method, secret, doc_mac): if doc_mac_hash != calculated_mac_hash: logger.warning("Wrong MAC while decrypting doc...") - raise WrongMac('Could not authenticate document\'s contents.') + raise crypto.WrongMacError("Could not authenticate document's " + "contents.") def decrypt_doc_dict(doc_dict, doc_id, doc_rev, key, secret): @@ -416,18 +436,18 @@ def decrypt_doc_dict(doc_dict, doc_id, doc_rev, key, secret): The passed doc_dict argument should have the following structure: { - ENC_JSON_KEY: '', - ENC_SCHEME_KEY: '', - ENC_METHOD_KEY: '', - ENC_IV_KEY: '', # (optional) + crypto.ENC_JSON_KEY: '', + crypto.ENC_SCHEME_KEY: '', + crypto.ENC_METHOD_KEY: '', + crypto.ENC_IV_KEY: '', # (optional) MAC_KEY: '' - MAC_METHOD_KEY: 'hmac' + crypto.MAC_METHOD_KEY: 'hmac' } C{enc_blob} is the encryption of the JSON serialization of the document's content. For now Soledad just deals with documents whose C{enc_scheme} is - EncryptionSchemes.SYMKEY and C{enc_method} is - EncryptionMethods.AES_256_CTR. + crypto.EncryptionSchemes.SYMKEY and C{enc_method} is + crypto.EncryptionMethods.AES_256_CTR. :param doc_dict: The content of the document to be decrypted. :type doc_dict: dict @@ -447,27 +467,32 @@ def decrypt_doc_dict(doc_dict, doc_id, doc_rev, key, secret): :return: The JSON serialization of the decrypted content. :rtype: str - :raise UnknownEncryptionMethod: Raised when trying to decrypt from an + :raise UnknownEncryptionMethodError: Raised when trying to decrypt from an unknown encryption method. """ # assert document dictionary structure - soledad_assert(ENC_JSON_KEY in doc_dict) - soledad_assert(ENC_SCHEME_KEY in doc_dict) - soledad_assert(ENC_METHOD_KEY in doc_dict) - soledad_assert(ENC_IV_KEY in doc_dict) - soledad_assert(MAC_KEY in doc_dict) - soledad_assert(MAC_METHOD_KEY in doc_dict) - - ciphertext = binascii.a2b_hex(doc_dict[ENC_JSON_KEY]) - enc_scheme = doc_dict[ENC_SCHEME_KEY] - enc_method = doc_dict[ENC_METHOD_KEY] - enc_iv = doc_dict[ENC_IV_KEY] - doc_mac = doc_dict[MAC_KEY] - mac_method = doc_dict[MAC_METHOD_KEY] - - soledad_assert(enc_scheme == EncryptionSchemes.SYMKEY) - - _verify_doc_mac(doc_id, doc_rev, ciphertext, mac_method, secret, doc_mac) + expected_keys = set([ + crypto.ENC_JSON_KEY, + crypto.ENC_SCHEME_KEY, + crypto.ENC_METHOD_KEY, + crypto.ENC_IV_KEY, + crypto.MAC_KEY, + crypto.MAC_METHOD_KEY, + ]) + soledad_assert(expected_keys.issubset(set(doc_dict.keys()))) + + ciphertext = binascii.a2b_hex(doc_dict[crypto.ENC_JSON_KEY]) + enc_scheme = doc_dict[crypto.ENC_SCHEME_KEY] + enc_method = doc_dict[crypto.ENC_METHOD_KEY] + enc_iv = doc_dict[crypto.ENC_IV_KEY] + doc_mac = doc_dict[crypto.MAC_KEY] + mac_method = doc_dict[crypto.MAC_METHOD_KEY] + + soledad_assert(enc_scheme == crypto.EncryptionSchemes.SYMKEY) + + _verify_doc_mac( + doc_id, doc_rev, ciphertext, enc_scheme, enc_method, + enc_iv, mac_method, secret, doc_mac) return decrypt_sym(ciphertext, key, method=enc_method, iv=enc_iv) @@ -481,8 +506,9 @@ def is_symmetrically_encrypted(doc): :rtype: bool """ - if doc.content and ENC_SCHEME_KEY in doc.content: - if doc.content[ENC_SCHEME_KEY] == EncryptionSchemes.SYMKEY: + if doc.content and crypto.ENC_SCHEME_KEY in doc.content: + if doc.content[crypto.ENC_SCHEME_KEY] \ + == crypto.EncryptionSchemes.SYMKEY: return True return False diff --git a/client/src/leap/soledad/client/secrets.py b/client/src/leap/soledad/client/secrets.py index b1c22371..970ac82f 100644 --- a/client/src/leap/soledad/client/secrets.py +++ b/client/src/leap/soledad/client/secrets.py @@ -33,33 +33,12 @@ from hashlib import sha256 import simplejson as json -from leap.soledad.common import ( - soledad_assert, - soledad_assert_type -) -from leap.soledad.common.document import SoledadDocument -from leap.soledad.common.crypto import ( - MacMethods, - UnknownMacMethod, - WrongMac, - MAC_KEY, - MAC_METHOD_KEY, -) -from leap.soledad.common.errors import ( - InvalidTokenError, - NotLockedError, - AlreadyLockedError, - LockTimedOutError, -) -from leap.soledad.client.events import ( - SOLEDAD_CREATING_KEYS, - SOLEDAD_DONE_CREATING_KEYS, - SOLEDAD_DOWNLOADING_KEYS, - SOLEDAD_DONE_DOWNLOADING_KEYS, - SOLEDAD_UPLOADING_KEYS, - SOLEDAD_DONE_UPLOADING_KEYS, - signal, -) +from leap.soledad.common import soledad_assert +from leap.soledad.common import soledad_assert_type +from leap.soledad.common import document +from leap.soledad.common import errors +from leap.soledad.common import crypto +from leap.soledad.client import events logger = logging.getLogger(name=__name__) @@ -227,9 +206,9 @@ class SoledadSecrets(object): token = timeout = None try: token, timeout = self._shared_db.lock() - except AlreadyLockedError: + except errors.AlreadyLockedError: raise BootstrapSequenceError('Database is already locked.') - except LockTimedOutError: + except errors.LockTimedOutError: raise BootstrapSequenceError('Lock operation timed out.') self._get_or_gen_crypto_secrets() @@ -238,12 +217,12 @@ class SoledadSecrets(object): try: self._shared_db.unlock(token) self._shared_db.close() - except NotLockedError: + except errors.NotLockedError: # for some reason the lock expired. Despite that, secret # loading or generation/storage must have been executed # successfully, so we pass. pass - except InvalidTokenError: + except errors.InvalidTokenError: # here, our lock has not only expired but also some other # client application has obtained a new lock and is currently # doing its thing in the shared database. Using the same @@ -403,8 +382,8 @@ class SoledadSecrets(object): self.KDF_KEY: self.KDF_SCRYPT, self.KDF_SALT_KEY: binascii.b2a_base64(salt), self.KDF_LENGTH_KEY: len(key), - MAC_METHOD_KEY: MacMethods.HMAC, - MAC_KEY: hmac.new( + crypto.MAC_METHOD_KEY: crypto.MacMethods.HMAC, + crypto.MAC_KEY: hmac.new( key, json.dumps(encrypted_secrets), sha256).hexdigest(), @@ -429,13 +408,13 @@ class SoledadSecrets(object): soledad_assert(self.STORAGE_SECRETS_KEY in data) # check mac of the recovery document mac = None - if MAC_KEY in data: - soledad_assert(data[MAC_KEY] is not None) - soledad_assert(MAC_METHOD_KEY in data) + if crypto.MAC_KEY in data: + soledad_assert(data[crypto.MAC_KEY] is not None) + soledad_assert(crypto.MAC_METHOD_KEY in data) soledad_assert(self.KDF_KEY in data) soledad_assert(self.KDF_SALT_KEY in data) soledad_assert(self.KDF_LENGTH_KEY in data) - if data[MAC_METHOD_KEY] == MacMethods.HMAC: + if data[crypto.MAC_METHOD_KEY] == crypto.MacMethods.HMAC: key = scrypt.hash( self._passphrase_as_string(), binascii.a2b_base64(data[self.KDF_SALT_KEY]), @@ -445,10 +424,10 @@ class SoledadSecrets(object): json.dumps(data[self.STORAGE_SECRETS_KEY]), sha256).hexdigest() else: - raise UnknownMacMethod('Unknown MAC method: %s.' % - data[MAC_METHOD_KEY]) - if mac != data[MAC_KEY]: - raise WrongMac('Could not authenticate recovery document\'s ' + raise crypto.UnknownMacMethodError('Unknown MAC method: %s.' % + data[crypto.MAC_METHOD_KEY]) + if mac != data[crypto.MAC_KEY]: + raise crypto.WrongMacError('Could not authenticate recovery document\'s ' 'contents.') # include secrets in the secret pool. secret_count = 0 @@ -469,15 +448,15 @@ class SoledadSecrets(object): database. :return: a document with encrypted key material in its contents - :rtype: SoledadDocument + :rtype: document.SoledadDocument """ - signal(SOLEDAD_DOWNLOADING_KEYS, self._uuid) + events.signal(events.SOLEDAD_DOWNLOADING_KEYS, self._uuid) db = self._shared_db if not db: logger.warning('No shared db found') return doc = db.get_doc(self._shared_db_doc_id()) - signal(SOLEDAD_DONE_DOWNLOADING_KEYS, self._uuid) + events.signal(events.SOLEDAD_DONE_DOWNLOADING_KEYS, self._uuid) return doc def _put_secrets_in_shared_db(self): @@ -495,18 +474,18 @@ class SoledadSecrets(object): # try to get secrets doc from server, otherwise create it doc = self._get_secrets_from_shared_db() if doc is None: - doc = SoledadDocument( + doc = document.SoledadDocument( doc_id=self._shared_db_doc_id()) # fill doc with encrypted secrets doc.content = self._export_recovery_document() # upload secrets to server - signal(SOLEDAD_UPLOADING_KEYS, self._uuid) + events.signal(events.SOLEDAD_UPLOADING_KEYS, self._uuid) db = self._shared_db if not db: logger.warning('No shared db found') return db.put_doc(doc) - signal(SOLEDAD_DONE_UPLOADING_KEYS, self._uuid) + events.signal(events.SOLEDAD_DONE_UPLOADING_KEYS, self._uuid) # # Management of secret for symmetric encryption. @@ -618,7 +597,7 @@ class SoledadSecrets(object): Generate a secret for symmetric encryption and store in a local encrypted file. - This method emits the following signals: + This method emits the following events.signals: * SOLEDAD_CREATING_KEYS * SOLEDAD_DONE_CREATING_KEYS @@ -626,13 +605,13 @@ class SoledadSecrets(object): :return: The id of the generated secret. :rtype: str """ - signal(SOLEDAD_CREATING_KEYS, self._uuid) + events.signal(events.SOLEDAD_CREATING_KEYS, self._uuid) # generate random secret secret = os.urandom(self.GEN_SECRET_LENGTH) secret_id = sha256(secret).hexdigest() self._secrets[secret_id] = secret self._store_secrets() - signal(SOLEDAD_DONE_CREATING_KEYS, self._uuid) + events.signal(events.SOLEDAD_DONE_CREATING_KEYS, self._uuid) return secret_id def _store_secrets(self): diff --git a/common/src/leap/soledad/common/crypto.py b/common/src/leap/soledad/common/crypto.py index ab05999b..b4f3234f 100644 --- a/common/src/leap/soledad/common/crypto.py +++ b/common/src/leap/soledad/common/crypto.py @@ -35,7 +35,7 @@ class EncryptionSchemes(object): PUBKEY = 'pubkey' -class UnknownEncryptionScheme(Exception): +class UnknownEncryptionSchemeError(Exception): """ Raised when trying to decrypt from unknown encryption schemes. """ @@ -51,7 +51,7 @@ class EncryptionMethods(object): XSALSA20 = 'xsalsa20' -class UnknownEncryptionMethod(Exception): +class UnknownEncryptionMethodError(Exception): """ Raised when trying to encrypt/decrypt with unknown method. """ @@ -66,7 +66,7 @@ class MacMethods(object): HMAC = 'hmac' -class UnknownMacMethod(Exception): +class UnknownMacMethodError(Exception): """ Raised when trying to authenticate document's content with unknown MAC mehtod. @@ -74,7 +74,7 @@ class UnknownMacMethod(Exception): pass -class WrongMac(Exception): +class WrongMacError(Exception): """ Raised when failing to authenticate document's contents based on MAC. """ diff --git a/common/src/leap/soledad/common/tests/__init__.py b/common/src/leap/soledad/common/tests/__init__.py index 3081683b..0ab159fd 100644 --- a/common/src/leap/soledad/common/tests/__init__.py +++ b/common/src/leap/soledad/common/tests/__init__.py @@ -27,9 +27,9 @@ from mock import Mock from leap.soledad.common.document import SoledadDocument +from leap.soledad.common.crypto import ENC_SCHEME_KEY from leap.soledad.client import Soledad from leap.soledad.client.crypto import decrypt_doc_dict -from leap.soledad.client.crypto import ENC_SCHEME_KEY from leap.common.testing.basetest import BaseLeapTest diff --git a/common/src/leap/soledad/common/tests/test_crypto.py b/common/src/leap/soledad/common/tests/test_crypto.py index 0302a268..f5fb4b7a 100644 --- a/common/src/leap/soledad/common/tests/test_crypto.py +++ b/common/src/leap/soledad/common/tests/test_crypto.py @@ -24,7 +24,13 @@ import binascii from leap.soledad.client import crypto from leap.soledad.common.document import SoledadDocument from leap.soledad.common.tests import BaseSoledadTest -from leap.soledad.common.crypto import WrongMac, UnknownMacMethod +from leap.soledad.common.crypto import WrongMacError +from leap.soledad.common.crypto import UnknownMacMethodError +from leap.soledad.common.crypto import EncryptionMethods +from leap.soledad.common.crypto import ENC_JSON_KEY +from leap.soledad.common.crypto import ENC_SCHEME_KEY +from leap.soledad.common.crypto import MAC_KEY +from leap.soledad.common.crypto import MAC_METHOD_KEY class EncryptedSyncTestCase(BaseSoledadTest): @@ -46,8 +52,8 @@ class EncryptedSyncTestCase(BaseSoledadTest): self.assertNotEqual( simpledoc, doc1.content, 'incorrect document encryption') - self.assertTrue(crypto.ENC_JSON_KEY in doc1.content) - self.assertTrue(crypto.ENC_SCHEME_KEY in doc1.content) + self.assertTrue(ENC_JSON_KEY in doc1.content) + self.assertTrue(ENC_SCHEME_KEY in doc1.content) # decrypt doc doc1.set_json(crypto.decrypt_doc(self._soledad._crypto, doc1)) self.assertEqual( @@ -149,13 +155,13 @@ class MacAuthTestCase(BaseSoledadTest): doc.content = simpledoc # encrypt doc doc.set_json(crypto.encrypt_doc(self._soledad._crypto, doc)) - self.assertTrue(crypto.MAC_KEY in doc.content) - self.assertTrue(crypto.MAC_METHOD_KEY in doc.content) + self.assertTrue(MAC_KEY in doc.content) + self.assertTrue(MAC_METHOD_KEY in doc.content) # mess with MAC - doc.content[crypto.MAC_KEY] = '1234567890ABCDEF' + doc.content[MAC_KEY] = '1234567890ABCDEF' # try to decrypt doc self.assertRaises( - WrongMac, + WrongMacError, crypto.decrypt_doc, self._soledad._crypto, doc) def test_decrypt_with_unknown_mac_method_raises(self): @@ -167,13 +173,13 @@ class MacAuthTestCase(BaseSoledadTest): doc.content = simpledoc # encrypt doc doc.set_json(crypto.encrypt_doc(self._soledad._crypto, doc)) - self.assertTrue(crypto.MAC_KEY in doc.content) - self.assertTrue(crypto.MAC_METHOD_KEY in doc.content) + self.assertTrue(MAC_KEY in doc.content) + self.assertTrue(MAC_METHOD_KEY in doc.content) # mess with MAC method - doc.content[crypto.MAC_METHOD_KEY] = 'mymac' + doc.content[MAC_METHOD_KEY] = 'mymac' # try to decrypt doc self.assertRaises( - UnknownMacMethod, + UnknownMacMethodError, crypto.decrypt_doc, self._soledad._crypto, doc) @@ -184,20 +190,20 @@ class SoledadCryptoAESTestCase(BaseSoledadTest): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') plaintext = self._soledad._crypto.decrypt_sym( cyphertext, key, iv=iv, - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertEqual('data', plaintext) def test_decrypt_with_wrong_iv_fails(self): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') @@ -208,14 +214,14 @@ class SoledadCryptoAESTestCase(BaseSoledadTest): wrongiv = os.urandom(1) + rawiv[1:] plaintext = self._soledad._crypto.decrypt_sym( cyphertext, key, iv=binascii.b2a_base64(wrongiv), - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertNotEqual('data', plaintext) def test_decrypt_with_wrong_key_fails(self): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') @@ -225,7 +231,7 @@ class SoledadCryptoAESTestCase(BaseSoledadTest): wrongkey = os.urandom(32) plaintext = self._soledad._crypto.decrypt_sym( cyphertext, wrongkey, iv=iv, - method=crypto.EncryptionMethods.AES_256_CTR) + method=EncryptionMethods.AES_256_CTR) self.assertNotEqual('data', plaintext) @@ -236,20 +242,20 @@ class SoledadCryptoXSalsa20TestCase(BaseSoledadTest): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') plaintext = self._soledad._crypto.decrypt_sym( cyphertext, key, iv=iv, - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertEqual('data', plaintext) def test_decrypt_with_wrong_iv_fails(self): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') @@ -260,14 +266,14 @@ class SoledadCryptoXSalsa20TestCase(BaseSoledadTest): wrongiv = os.urandom(1) + rawiv[1:] plaintext = self._soledad._crypto.decrypt_sym( cyphertext, key, iv=binascii.b2a_base64(wrongiv), - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertNotEqual('data', plaintext) def test_decrypt_with_wrong_key_fails(self): key = os.urandom(32) iv, cyphertext = self._soledad._crypto.encrypt_sym( 'data', key, - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertTrue(cyphertext is not None) self.assertTrue(cyphertext != '') self.assertTrue(cyphertext != 'data') @@ -277,5 +283,5 @@ class SoledadCryptoXSalsa20TestCase(BaseSoledadTest): wrongkey = os.urandom(32) plaintext = self._soledad._crypto.decrypt_sym( cyphertext, wrongkey, iv=iv, - method=crypto.EncryptionMethods.XSALSA20) + method=EncryptionMethods.XSALSA20) self.assertNotEqual('data', plaintext) diff --git a/common/src/leap/soledad/common/tests/test_soledad.py b/common/src/leap/soledad/common/tests/test_soledad.py index 12bfbc3e..31c02fc4 100644 --- a/common/src/leap/soledad/common/tests/test_soledad.py +++ b/common/src/leap/soledad/common/tests/test_soledad.py @@ -28,7 +28,7 @@ from leap.soledad.common.tests import ( ) from leap import soledad from leap.soledad.common.document import SoledadDocument -from leap.soledad.common.crypto import WrongMac +from leap.soledad.common.crypto import WrongMacError from leap.soledad.client import Soledad from leap.soledad.client.sqlcipher import SQLCipherDatabase from leap.soledad.client.secrets import PassphraseTooShort @@ -117,7 +117,7 @@ class AuxMethodsTestCase(BaseSoledadTest): sol.close() self.assertRaises( - WrongMac, + WrongMacError, self._soledad_instance, 'leap@leap.se', passphrase=u'123', prefix=self.rand_prefix) @@ -208,7 +208,7 @@ class SoledadSignalingTestCase(BaseSoledadTest): def setUp(self): # mock signaling soledad.client.signal = Mock() - soledad.client.secrets.signal = Mock() + soledad.client.secrets.events.signal = Mock() # run parent's setUp BaseSoledadTest.setUp(self) @@ -230,57 +230,57 @@ class SoledadSignalingTestCase(BaseSoledadTest): - downloading keys / done downloading keys. - uploading keys / done uploading keys. """ - soledad.client.secrets.signal.reset_mock() + soledad.client.secrets.events.signal.reset_mock() # get a fresh instance so it emits all bootstrap signals sol = self._soledad_instance( secrets_path='alternative_stage3.json', local_db_path='alternative_stage3.u1db') # reverse call order so we can verify in the order the signals were # expected - soledad.client.secrets.signal.mock_calls.reverse() - soledad.client.secrets.signal.call_args = \ - soledad.client.secrets.signal.call_args_list[0] - soledad.client.secrets.signal.call_args_list.reverse() + soledad.client.secrets.events.signal.mock_calls.reverse() + soledad.client.secrets.events.signal.call_args = \ + soledad.client.secrets.events.signal.call_args_list[0] + soledad.client.secrets.events.signal.call_args_list.reverse() # downloading keys signals - soledad.client.secrets.signal.assert_called_with( + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DOWNLOADING_KEYS, ADDRESS, ) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DONE_DOWNLOADING_KEYS, ADDRESS, ) # creating keys signals - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_CREATING_KEYS, ADDRESS, ) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DONE_CREATING_KEYS, ADDRESS, ) # downloading once more (inside _put_keys_in_shared_db) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DOWNLOADING_KEYS, ADDRESS, ) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DONE_DOWNLOADING_KEYS, ADDRESS, ) # uploading keys signals - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_UPLOADING_KEYS, ADDRESS, ) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DONE_UPLOADING_KEYS, ADDRESS, ) @@ -312,7 +312,7 @@ class SoledadSignalingTestCase(BaseSoledadTest): sol.close() # reset mock - soledad.client.secrets.signal.reset_mock() + soledad.client.secrets.events.signal.reset_mock() # get a fresh instance so it emits all bootstrap signals sol = self._soledad_instance( secrets_path='alternative_stage2.json', @@ -320,17 +320,17 @@ class SoledadSignalingTestCase(BaseSoledadTest): shared_db_class=Stage2MockSharedDB) # reverse call order so we can verify in the order the signals were # expected - soledad.client.secrets.signal.mock_calls.reverse() - soledad.client.secrets.signal.call_args = \ - soledad.client.secrets.signal.call_args_list[0] - soledad.client.secrets.signal.call_args_list.reverse() + soledad.client.secrets.events.signal.mock_calls.reverse() + soledad.client.secrets.events.signal.call_args = \ + soledad.client.secrets.events.signal.call_args_list[0] + soledad.client.secrets.events.signal.call_args_list.reverse() # assert download keys signals - soledad.client.secrets.signal.assert_called_with( + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DOWNLOADING_KEYS, ADDRESS, ) - self._pop_mock_call(soledad.client.secrets.signal) - soledad.client.secrets.signal.assert_called_with( + self._pop_mock_call(soledad.client.secrets.events.signal) + soledad.client.secrets.events.signal.assert_called_with( proto.SOLEDAD_DONE_DOWNLOADING_KEYS, ADDRESS, ) -- cgit v1.2.3