Skip to content

Commit 685dd58

Browse files
authored
Handle new libnacl exceptions (#34)
Fix handle libnacl.CryptError Add tests for basic libnacl crypto Require pytest-asyncio==0.5.0 for Python 3.4 builds Bump dependency versions
1 parent 22de059 commit 685dd58

3 files changed

Lines changed: 52 additions & 13 deletions

File tree

setup.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ def read(file):
3838
# Note: These are just tools that aren't required, so a version range
3939
# is not necessary here.
4040
tests_require = [
41-
'pytest>=2.8.4',
42-
'pytest-asyncio>=0.2.0',
43-
'pytest-cov>=2.4.0',
41+
'pytest>=3.1.3',
42+
'pytest-asyncio>=0.6.0',
43+
'pytest-cov>=2.5.1',
4444
'flake8>=3.3.0',
45-
'isort>=4.2.5',
45+
'isort>=4.2.15',
4646
'collective.checkdocs>=0.2',
4747
'Pygments>=2.2.0', # required by checkdocs
48-
'mypy==0.501',
48+
'mypy>=0.521',
4949
]
5050

5151
setup(
@@ -55,8 +55,8 @@ def read(file):
5555
namespace_packages=['threema'],
5656
install_requires=[
5757
'py_lru_cache>=0.1.4,<0.2',
58-
'logbook>=1,<2',
59-
'libnacl>=1.5,<2',
58+
'logbook>=1.1.0,<2',
59+
'libnacl>=1.5.2,<2',
6060
'click>=6.7,<7', # doesn't seem to follow semantic versioning
6161
'aiohttp>=1.3.5,<2',
6262
'wrapt>=1.10.10,<2',
@@ -65,9 +65,10 @@ def read(file):
6565
extras_require={
6666
':python_version<="3.4"': [
6767
'asyncio==3.4.3',
68+
'pytest-asyncio==0.5.0'
6869
],
6970
':python_version<="3.5"': [
70-
'typing>=3.6,<3.7',
71+
'typing>=3.6.1,<3.7',
7172
],
7273
'dev': tests_require,
7374
'uvloop': ['uvloop>=0.8.0,<2'],

tests/test_base.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import libnacl
2+
import pytest
3+
4+
from threema.gateway import (
5+
e2e,
6+
key,
7+
)
8+
9+
10+
class TestCrypto:
11+
def test_incorrect_nonce(self):
12+
key_pair = key.Key.generate_pair()
13+
data_in = b'meow'
14+
nonce = b'0' * 23
15+
with pytest.raises(ValueError) as exc_info:
16+
e2e._pk_encrypt(key_pair, data_in, nonce=nonce)
17+
assert 'Invalid nonce size' in str(exc_info.value)
18+
19+
def test_incorrect_ciphertext(self):
20+
key_pair = key.Key.generate_pair()
21+
data_in = b'meow'
22+
nonce = b'0' * 24
23+
with pytest.raises(libnacl.CryptError) as exc_info:
24+
_, data_encrypted = e2e._pk_encrypt(key_pair, data_in, nonce=nonce)
25+
e2e._pk_decrypt(key_pair, nonce, data_encrypted + b'0')
26+
assert 'decrypt' in str(exc_info.value)
27+
28+
def test_valid(self):
29+
key_pair = key.Key.generate_pair()
30+
data_in = b'meow'
31+
nonce = b'0' * 24
32+
_, data_encrypted = e2e._pk_encrypt(key_pair, data_in, nonce=nonce)
33+
data_out = e2e._pk_decrypt(key_pair, nonce, data_encrypted)
34+
assert data_in == data_out

threema/gateway/e2e.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
BLOB_ID_LENGTH = 16
5353

5454

55-
# TODO: Raises?
5655
def _pk_encrypt(key_pair: Tuple[Key, Key], data: bytes, nonce: bytes = None):
5756
"""
5857
Encrypt data by using public-key encryption.
@@ -63,6 +62,9 @@ def _pk_encrypt(key_pair: Tuple[Key, Key], data: bytes, nonce: bytes = None):
6362
- `data`: Raw data.
6463
- `nonce`: A predefined nonce.
6564
65+
Raises `libnacl.CryptError` in case the data could not be encrypted.
66+
Raises `ValueError` in other cases.
67+
6668
Return a tuple of bytes containing the nonce and the encrypted
6769
data.
6870
"""
@@ -72,7 +74,6 @@ def _pk_encrypt(key_pair: Tuple[Key, Key], data: bytes, nonce: bytes = None):
7274
return box.encrypt(data, nonce=nonce, pack_nonce=False)
7375

7476

75-
# TODO: Raises?
7677
def _pk_decrypt(key_pair: Tuple[Key, Key], nonce: bytes, data: bytes):
7778
"""
7879
Decrypt data by using public-key decryption.
@@ -83,6 +84,9 @@ def _pk_decrypt(key_pair: Tuple[Key, Key], nonce: bytes, data: bytes):
8384
- `nonce`: The nonce of the encrypted data.
8485
- `data`: Encrypted data.
8586
87+
Raises `libnacl.CryptError` in case the data could not be decrypted.
88+
Raises `ValueError` in other cases.
89+
8690
Return the decrypted data.
8791
"""
8892
# Decrypt payload
@@ -650,7 +654,7 @@ def encrypt(self, data, key_pair=None, nonce=None):
650654
# Encrypt
651655
try:
652656
return _pk_encrypt(key_pair, data, nonce=nonce)
653-
except ValueError as exc:
657+
except (ValueError, libnacl.CryptError) as exc:
654658
raise MessageError('Could not encrypt data') from exc
655659

656660
@classmethod
@@ -671,8 +675,8 @@ def decrypt(cls, nonce, data, key_pair):
671675
# Decrypt
672676
try:
673677
return _pk_decrypt(key_pair, nonce, data)
674-
except ValueError:
675-
raise MessageError('Could not decrypt data')
678+
except (ValueError, libnacl.CryptError) as exc:
679+
raise MessageError('Could not decrypt data') from exc
676680

677681

678682
# TODO: Update docstring (arguments)

0 commit comments

Comments
 (0)