Various small fixes and cleanups

tests/vectors/*:
- removed noise-c-basic.txt test vectors

tests/test_vectors.py:
- removed workarounds related to noise-c test vectors

noise/builder.py:
- added some more type hinting

noise/state.py:
- CipherState is now consistent in raising NoiseMaxNonceError
and using MAX_NONCE constant for encrypt and decrypt methods

noise/functions.py:
- Keypair constructors now guarded from invalid length of given
public/private bytes
- _25519_generate_keypair now returns proper class instance

requirements.txt:
- specified versions of packages that are compatible with currently used source code
This commit is contained in:
Piotr Lizonczyk
2017-09-12 00:27:39 +02:00
parent a60def7614
commit 2fa2f03d90
7 changed files with 20 additions and 19696 deletions

View File

@@ -125,12 +125,12 @@ class NoiseBuilder(object):
self.handshake_finished = True
return buffer
def encrypt(self, data: bytes):
def encrypt(self, data: bytes) -> bytes:
if not isinstance(data, bytes) or len(data) > MAX_MESSAGE_LEN:
raise NoiseInvalidMessage('Data must be bytes and less or equal {} bytes in length'.format(MAX_MESSAGE_LEN))
return self.noise_protocol.cipher_state_encrypt.encrypt_with_ad(None, data)
def decrypt(self, data: bytes):
def decrypt(self, data: bytes) -> bytes:
if not isinstance(data, bytes) or len(data) > MAX_MESSAGE_LEN:
raise NoiseInvalidMessage('Data must be bytes and less or equal {} bytes in length'.format(MAX_MESSAGE_LEN))
try:

View File

@@ -11,6 +11,7 @@ from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives.ciphers.aead import AESGCM, ChaCha20Poly1305
# from cryptography.hazmat.primitives.hmac import HMAC # Turn back on when Cryptography gets fixed
from noise.constants import MAX_NONCE
from noise.exceptions import NoiseValueError
from .crypto import X448
backend = default_backend()
@@ -36,15 +37,19 @@ class DH(object):
def _25519_generate_keypair(self) -> '_KeyPair':
private_key = x25519.X25519PrivateKey.generate()
public_key = private_key.public_key()
return _KeyPair(private_key, public_key, public_key.public_bytes())
return KeyPair25519(private_key, public_key, public_key.public_bytes())
def _25519_dh(self, private_key: 'x25519.X25519PrivateKey', public_key: 'x25519.X25519PublicKey') -> bytes:
if not isinstance(private_key, x25519.X25519PrivateKey) or not isinstance(public_key, x25519.X25519PublicKey):
raise NoiseValueError('Invalid keys! Must be x25519.X25519PrivateKey and x25519.X25519PublicKey instances')
return private_key.exchange(public_key)
def _448_generate_keypair(self) -> '_KeyPair':
return KeyPair448.new()
def _448_dh(self, private_key: bytes, public_key: bytes) -> bytes:
if len(private_key) != self.dhlen or len(public_key) != self.dhlen:
raise NoiseValueError('Invalid length of keys! Should be {}'.format(self.dhlen))
return X448.mul(private_key, public_key)
@@ -176,12 +181,16 @@ class _KeyPair(object):
class KeyPair25519(_KeyPair):
@classmethod
def from_private_bytes(cls, private_bytes):
if len(private_bytes) != 32:
raise NoiseValueError('Invalid length of private_bytes! Should be 32')
private = x25519.X25519PrivateKey._from_private_bytes(private_bytes)
public = private.public_key()
return cls(private=private, public=public, public_bytes=public.public_bytes())
@classmethod
def from_public_bytes(cls, public_bytes):
if len(public_bytes) != 32:
raise NoiseValueError('Invalid length of public_bytes! Should be 32')
public = x25519.X25519PublicKey.from_public_bytes(public_bytes)
return cls(public=public, public_bytes=public.public_bytes())
@@ -193,12 +202,16 @@ class KeyPair448(_KeyPair):
@classmethod
def from_private_bytes(cls, private_bytes):
if len(private_bytes) != 56:
raise NoiseValueError('Invalid length of private_bytes! Should be 56')
private = private_bytes
public = X448.mul_5(private)
return cls(private=private, public=public, public_bytes=public)
@classmethod
def from_public_bytes(cls, public_bytes):
if len(public_bytes) != 56:
raise NoiseValueError('Invalid length of private_bytes! Should be 56')
return cls(public=public_bytes, public_bytes=public_bytes)
@classmethod

View File

@@ -36,7 +36,7 @@ class CipherState(object):
:return: ciphertext bytes sequence
"""
if self.n == MAX_NONCE:
raise Exception('Nonce has depleted!')
raise NoiseMaxNonceError('Nonce has depleted!')
if not self.has_key():
return plaintext
@@ -53,7 +53,7 @@ class CipherState(object):
:param ciphertext: bytes sequence
:return: plaintext bytes sequence
"""
if self.n == 2**64 - 1:
if self.n == MAX_NONCE:
raise NoiseMaxNonceError('Nonce has depleted!')
if not self.has_key():

View File

@@ -1,2 +1,2 @@
pytest
cryptography
pytest>=3.2.2
cryptography==2.0.3

View File

@@ -1,11 +1,9 @@
import io
import json
import logging
import os
import pytest
from noise.state import CipherState
from noise.builder import NoiseBuilder, Keypair
logger = logging.getLogger(__name__)
@@ -32,10 +30,6 @@ def _prepare_test_vectors():
vectors_list = json.load(fd)
for vector in vectors_list:
if 'name' in vector and not 'protocol_name' in vector: # noise-c-* workaround
vector['protocol_name'] = vector['name']
if 'PSK' in vector['protocol_name']: # no old NoisePSK tests
continue # TODO REMOVE WHEN rev30 SUPPORT IS IMPLEMENTED/FIXED
for key, value in vector.copy().items():
if key in byte_fields:
vector[key] = value.encode()

View File

@@ -1,4 +1,3 @@
Test vectors:
- cacophony.txt from https://github.com/centromere/cacophony/blob/master/vectors/cacophony.txt, stripped from outer dict (so that it is just a list of json objects)
- noise-c-basic.txt from https://github.com/rweather/noise-c/blob/master/tests/vector/noise-c-basic.txt, stripped from outer dict (so that it is just a list of json objects)
- snow-multipsk.txt from https://github.com/mcginty/snow/blob/master/tests/vectors/snow-multipsk.txt, stripped from outer dict (so that it is just a list of json objects)

File diff suppressed because it is too large Load Diff