summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Shyba <victor1984@riseup.net>2016-11-25 19:55:36 -0300
committerdrebs <drebs@leap.se>2016-12-12 09:17:51 -0200
commit1c8e3359734831562fca76b529c0b1f95af565d5 (patch)
tree99915b72d1c0dad267448fed5bffa42941e36c8a
parent8b091951e8adebadc4be4dc5b2fb4f8b63c6900e (diff)
[refactor] Hide IV, simplify some calls
IV was being set during tests and this required some defensive coding to avoid IV being set in production. This commits makes the test use the generated IV and "hides" it using a read-only property to let it clear this should never happen. Also refactored out some parameters that are generated automatically to reduce some lines of code and enhance readability.
-rw-r--r--client/src/leap/soledad/client/_crypto.py45
-rw-r--r--testing/tests/client/test_crypto.py32
2 files changed, 29 insertions, 48 deletions
diff --git a/client/src/leap/soledad/client/_crypto.py b/client/src/leap/soledad/client/_crypto.py
index 4a59159c..109cf299 100644
--- a/client/src/leap/soledad/client/_crypto.py
+++ b/client/src/leap/soledad/client/_crypto.py
@@ -146,12 +146,11 @@ def encrypt_sym(data, key):
encoded as base64.
:rtype: (str, str)
"""
- iv = os.urandom(16)
- encryptor = AESEncryptor(key, iv)
+ encryptor = AESEncryptor(key)
encryptor.write(data)
encryptor.end()
ciphertext = encryptor.fd.getvalue()
- return base64.b64encode(iv), ciphertext
+ return base64.b64encode(encryptor.iv), ciphertext
def decrypt_sym(data, key, iv):
@@ -188,13 +187,7 @@ class BlobEncryptor(object):
Both the production input and output are file descriptors, so they can be
applied to a stream of data.
"""
- def __init__(self, doc_info, content_fd, result=None, secret=None,
- iv=None):
- if iv is None:
- iv = os.urandom(16)
- else:
- log.warn('Using a fixed IV. Use only for testing!')
- self.iv = iv
+ def __init__(self, doc_info, content_fd, result=None, secret=None):
if not secret:
raise EncryptionDecryptionError('no secret given')
@@ -206,20 +199,22 @@ class BlobEncryptor(object):
self._content_fd = content_fd
self._preamble = BytesIO()
- if result is None:
- result = BytesIO()
- self.result = result
+ self.result = result or BytesIO()
sym_key = _get_sym_key_for_doc(doc_info.doc_id, secret)
mac_key = _get_mac_key_for_doc(doc_info.doc_id, secret)
self._aes_fd = BytesIO()
- self._aes = AESEncryptor(sym_key, self.iv, self._aes_fd)
+ self._aes = AESEncryptor(sym_key, self._aes_fd)
self._hmac = HMACWriter(mac_key)
self._write_preamble()
self._crypter = VerifiedEncrypter(self._aes, self._hmac)
+ @property
+ def iv(self):
+ return self._aes.iv
+
def encrypt(self):
"""
Starts producing encrypted data from the cleartext data.
@@ -298,9 +293,7 @@ class BlobDecryptor(object):
self.sym_key = _get_sym_key_for_doc(doc_info.doc_id, secret)
self.mac_key = _get_mac_key_for_doc(doc_info.doc_id, secret)
- if result is None:
- result = BytesIO()
- self.result = result
+ self.result = result or BytesIO()
def decrypt(self):
try:
@@ -360,18 +353,15 @@ class AESEncryptor(object):
"""
implements(interfaces.IConsumer)
- def __init__(self, key, iv, fd=None):
+ def __init__(self, key, fd=None):
if len(key) != 32:
raise EncryptionDecryptionError('key is not 256 bits')
- if len(iv) != 16:
- raise EncryptionDecryptionError('iv is not 128 bits')
+ self.iv = os.urandom(16)
- cipher = _get_aes_ctr_cipher(key, iv)
+ cipher = _get_aes_ctr_cipher(key, self.iv)
self.encryptor = cipher.encryptor()
- if fd is None:
- fd = BytesIO()
- self.fd = fd
+ self.fd = fd or BytesIO()
self.done = False
@@ -429,8 +419,7 @@ class AESDecryptor(object):
implements(interfaces.IConsumer)
def __init__(self, key, iv, fd=None):
- if iv is None:
- iv = os.urandom(16)
+ iv = iv or os.urandom(16)
if len(key) != 32:
raise EncryptionDecryptionError('key is not 256 bits')
if len(iv) != 16:
@@ -439,9 +428,7 @@ class AESDecryptor(object):
cipher = _get_aes_ctr_cipher(key, iv)
self.decryptor = cipher.decryptor()
- if fd is None:
- fd = BytesIO()
- self.fd = fd
+ self.fd = fd or BytesIO()
self.done = False
self.deferred = defer.Deferred()
diff --git a/testing/tests/client/test_crypto.py b/testing/tests/client/test_crypto.py
index 483c7803..6d896604 100644
--- a/testing/tests/client/test_crypto.py
+++ b/testing/tests/client/test_crypto.py
@@ -51,10 +51,10 @@ class AESTest(unittest.TestCase):
def test_chunked_encryption(self):
key = 'A' * 32
- iv = 'A' * 16
fd = BytesIO()
- aes = _crypto.AESEncryptor(key, iv, fd)
+ aes = _crypto.AESEncryptor(key, fd)
+ iv = aes.iv
data = snowden1
block = 16
@@ -99,14 +99,11 @@ class BlobTestCase(unittest.TestCase):
@defer.inlineCallbacks
def test_blob_encryptor(self):
- inf = BytesIO()
- inf.write(snowden1)
- inf.seek(0)
- outf = BytesIO()
+ inf = BytesIO(snowden1)
blob = _crypto.BlobEncryptor(
- self.doc_info, inf, result=outf,
- secret='A' * 96, iv='B' * 16)
+ self.doc_info, inf,
+ secret='A' * 96)
encrypted = yield blob.encrypt()
data = base64.urlsafe_b64decode(encrypted.getvalue())
@@ -117,7 +114,7 @@ class BlobTestCase(unittest.TestCase):
assert sch == 1
assert meth == 1
iv = data[11:27]
- assert iv == 'B' * 16
+ assert iv == blob.iv
doc_id = data[27:37]
assert doc_id == 'D-deadbeef'
@@ -127,26 +124,23 @@ class BlobTestCase(unittest.TestCase):
ciphertext = data[71:-64]
aes_key = _crypto._get_sym_key_for_doc(
self.doc_info.doc_id, 'A' * 96)
- assert ciphertext == _aes_encrypt(aes_key, 'B' * 16, snowden1)
+ assert ciphertext == _aes_encrypt(aes_key, blob.iv, snowden1)
- decrypted = _aes_decrypt(aes_key, 'B' * 16, ciphertext)
+ decrypted = _aes_decrypt(aes_key, blob.iv, ciphertext)
assert str(decrypted) == snowden1
@defer.inlineCallbacks
def test_blob_decryptor(self):
- inf = BytesIO()
- inf.write(snowden1)
- inf.seek(0)
- outf = BytesIO()
+ inf = BytesIO(snowden1)
blob = _crypto.BlobEncryptor(
- self.doc_info, inf, result=outf,
- secret='A' * 96, iv='B' * 16)
- yield blob.encrypt()
+ self.doc_info, inf,
+ secret='A' * 96)
+ ciphertext = yield blob.encrypt()
decryptor = _crypto.BlobDecryptor(
- self.doc_info, outf,
+ self.doc_info, ciphertext,
secret='A' * 96)
decrypted = yield decryptor.decrypt()
assert decrypted.getvalue() == snowden1