diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2017-06-09 02:31:30 -1000 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2017-06-09 08:31:30 -0400 |
commit | 3e357f704008f38261aee011a9fe674dc43cc0ae (patch) | |
tree | f50094dd94873a50e709608da3e74cb6b459cc03 /tests | |
parent | 7e53d911577881d87ce30291cef68e24f3c1b763 (diff) | |
download | cryptography-3e357f704008f38261aee011a9fe674dc43cc0ae.tar.gz cryptography-3e357f704008f38261aee011a9fe674dc43cc0ae.tar.bz2 cryptography-3e357f704008f38261aee011a9fe674dc43cc0ae.zip |
X25519 Support (#3686)
* early days
* sort of working
* more things
* remove private_bytes
* public bytes, interface fix
* load public keys
* x25519 support basically done now
* private_bytes is gone
* some reminders
* doctest this too
* remove a thing that doesn't matter
* x25519 supported checks
* libressl has the NID, but a different API, so check for OpenSSL
* pep8
* add missing coverage
* update to use reasons
* expand test a little
* add changelog entry
* review feedback
Diffstat (limited to 'tests')
-rw-r--r-- | tests/hazmat/primitives/test_x25519.py | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tests/hazmat/primitives/test_x25519.py b/tests/hazmat/primitives/test_x25519.py new file mode 100644 index 00000000..22a0ae66 --- /dev/null +++ b/tests/hazmat/primitives/test_x25519.py @@ -0,0 +1,120 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.exceptions import _Reasons +from cryptography.hazmat.backends.interfaces import DHBackend +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, X25519PublicKey +) + +from ...utils import ( + load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm +) + + +@pytest.mark.supported( + only_if=lambda backend: not backend.x25519_supported(), + skip_message="Requires OpenSSL without X25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +def test_x25519_unsupported(backend): + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM): + X25519PublicKey.from_public_bytes(b"0" * 32) + + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM): + X25519PrivateKey.generate() + + +@pytest.mark.supported( + only_if=lambda backend: backend.x25519_supported(), + skip_message="Requires OpenSSL with X25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +class TestX25519Exchange(object): + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "X25519", "rfc7748.txt"), + load_nist_vectors + ) + ) + def test_rfc7748(self, vector, backend): + private = binascii.unhexlify(vector["input_scalar"]) + public = binascii.unhexlify(vector["input_u"]) + shared_key = binascii.unhexlify(vector["output_u"]) + private_key = X25519PrivateKey._from_private_bytes(private) + public_key = X25519PublicKey.from_public_bytes(public) + computed_shared_key = private_key.exchange(public_key) + assert computed_shared_key == shared_key + + def test_rfc7748_1000_iteration(self, backend): + old_private = private = public = binascii.unhexlify( + b"090000000000000000000000000000000000000000000000000000000000" + b"0000" + ) + shared_key = binascii.unhexlify( + b"684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d9953" + b"2c51" + ) + private_key = X25519PrivateKey._from_private_bytes(private) + public_key = X25519PublicKey.from_public_bytes(public) + for _ in range(1000): + computed_shared_key = private_key.exchange(public_key) + private_key = X25519PrivateKey._from_private_bytes( + computed_shared_key + ) + public_key = X25519PublicKey.from_public_bytes(old_private) + old_private = computed_shared_key + + assert computed_shared_key == shared_key + + # These vectors are also from RFC 7748 + # https://tools.ietf.org/html/rfc7748#section-6.1 + @pytest.mark.parametrize( + ("private_bytes", "public_bytes"), + [ + ( + binascii.unhexlify( + b"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba" + b"51db92c2a" + ), + binascii.unhexlify( + b"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98" + b"eaa9b4e6a" + ) + ), + ( + binascii.unhexlify( + b"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b2" + b"7ff88e0eb" + ), + binascii.unhexlify( + b"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e1" + b"46f882b4f" + ) + ) + ] + ) + def test_public_bytes(self, private_bytes, public_bytes, backend): + private_key = X25519PrivateKey._from_private_bytes(private_bytes) + assert private_key.public_key().public_bytes() == public_bytes + public_key = X25519PublicKey.from_public_bytes(public_bytes) + assert public_key.public_bytes() == public_bytes + + def test_generate(self, backend): + key = X25519PrivateKey.generate() + assert key + assert key.public_key() + + def test_invalid_type_exchange(self, backend): + key = X25519PrivateKey.generate() + with pytest.raises(TypeError): + key.exchange(object()) |