summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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