OpenSSL DH backend implementation [Second attempt] (#2914)
* Start of OpenSSL DH backend implementation
* Supporting DH in MultiBackend
* DHBackend has dh_parameters_supported method
* Removed DHParametersWithNumbers and DHPrivateKeyWithNumbers from documentation
* Removed ExchangeContext. exchange is a method of DHPrivateKeyWithSerialization
* PEP8 fixes
* Fixed TestDH.test_bad_tls_exchange
* Fixed generate_private_key reference in dh documentation
* test DH multibackend support
* testing DH coversion to serialized
* Validating that we receive serialized class in test_generate_dh
* Testing DH exchange symmetric key padding
* struct DH is now opaqued
* PEP8 fixes
* Testing load_dh_private_numbers throws ValueError when DH_check fails
* Using openssl_assert
* Passing keywords arguments in DH key exchange example
* test_dh::test_bad_tls_exchange now uses pre calculated parameters
* TestDH - Add test that the computed secret is equivalent to the definition by comparing with secret computed in pure python
* Add missing generator parameter to DHBackend interface docs.
* Include parameter type in DHBackend abc docs.
* Add docs for dh.generate_parameters function
* Remove the dh Numbers section, and move the DHNumbers class docs to where they are first used.
* Add note of big endian byte packing to DH exchange method.
* DH documentation updates.
Add single sentence overview with wikipedia link.
Add paragraph on assembling using Numbers objects.
Add link to backend interface docs.
First section was all indented, I think by mistake.
* Add exchange method to DHPrivateKey abstract base class.
* Small tweaks to DH documentation - remove Provider.
* Add endian to dictionary
* Use utils.int_from_bytes in test_tls_exchange_algorithm
* Removed duplicate line
* Change dh.rst exchange algorithm from doctest to code-block
The example in the Diffie-Hellman exhange algorithm is using
2048 bits key. Generating the parameters of 2048 takes long
time. This caused the automated tests to fail. In order to
pass the tests we change the example to code-block so it
will not run in the doc tests.
* Fix dh docs
* Document the generator in DHBackend relevant methods
* Fix dh tests
* use DHparams_dup
* Fix key type to unsigned char as expected by DH_compute_key
* Validate that DH generator is 2 or 5
* test dh exchange using botan vectors
* group all numbers classes
* Simplify _DHPrivateKey
* Rename test with serialized to numbers
* Move bad exchange params to external vector file
* update exchange versionadded to 1.7
* Make key_size bit accurate
* Change botan link
* Added CHANGELOG entry
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
index 49c5ac2..fb72240 100644
--- a/docs/development/test-vectors.rst
+++ b/docs/development/test-vectors.rst
@@ -91,6 +91,13 @@
* ``vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt`` contains
Diffie-Hellman examples from appendix A.1, A.2 and A.3 of :rfc:`5114`.
+* ``vectors/cryptography_vectors/asymmetric/DH/vec.txt`` contains
+ Diffie-Hellman examples from `botan`_.
+
+* ``vectors/cryptography_vectors/asymmetric/DH/bad_exchange.txt`` contains
+ Diffie-Hellman vector pairs that were generated using OpenSSL
+ DH_generate_parameters_ex and DH_generate_key.
+
X.509
~~~~~
@@ -463,3 +470,4 @@
.. _`Russian CA`: https://e-trust.gosuslugi.ru/MainCA
.. _`test/evptests.txt`: https://github.com/openssl/openssl/blob/2d0b44126763f989a4cbffbffe9d0c7518158bb7/test/evptests.txt
.. _`unknown signature OID`: https://bugzilla.mozilla.org/show_bug.cgi?id=405966
+.. _`botan`: https://github.com/randombit/botan/blob/57789bdfc55061002b2727d0b32587612829a37c/src/tests/data/pubkey/dh.vec
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 42e07d3..87fc6ab 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -600,7 +600,9 @@
A backend with methods for doing Diffie-Hellman key exchange.
- .. method:: generate_dh_parameters(key_size)
+ .. method:: generate_dh_parameters(generator, key_size)
+
+ :param int generator: The generator to use. Often 2 or 5.
:param int key_size: The bit length of the prime modulus to generate.
@@ -617,7 +619,9 @@
:return: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
- .. method:: generate_dh_private_key_and_parameters(self, key_size)
+ .. method:: generate_dh_private_key_and_parameters(generator, key_size)
+
+ :param int generator: The generator to use. Often 2 or 5.
:param int key_size: The bit length of the prime modulus to generate.
diff --git a/docs/hazmat/primitives/asymmetric/dh.rst b/docs/hazmat/primitives/asymmetric/dh.rst
index 8cb6828..463df90 100644
--- a/docs/hazmat/primitives/asymmetric/dh.rst
+++ b/docs/hazmat/primitives/asymmetric/dh.rst
@@ -6,9 +6,195 @@
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.dh
+`Diffie-Hellman key exchange`_ (D–H) is a method that allows two parties
+to jointly agree on a shared secret using an insecure channel.
+
+
+Exchange Algorithm
+~~~~~~~~~~~~~~~~~~
+
+For most applications the ``shared_key`` should be passed to a key
+derivation function.
+
+.. code-block:: pycon
+
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> from cryptography.hazmat.primitives.asymmetric import dh
+ >>> parameters = dh.generate_parameters(generator=2, key_size=2048,
+ ... backend=default_backend())
+ >>> private_key = parameters.generate_private_key()
+ >>> peer_public_key = parameters.generate_private_key().public_key()
+ >>> shared_key = private_key.exchange(peer_public_key)
+
+DHE (or EDH), the ephemeral form of this exchange, is **strongly
+preferred** over simple DH and provides `forward secrecy`_ when used.
+You must generate a new private key using :func:`~DHParameters.generate_private_key` for
+each :meth:`~DHPrivateKeyWithSerialization.exchange` when performing an DHE key
+exchange.
+
+To assemble a :class:`~DHParameters` and a :class:`~DHPublicKey` from
+primitive integers, you must first create the
+:class:`~DHParameterNumbers` and :class:`~DHPublicNumbers` objects. For
+example if **p**, **g**, and **y** are :class:`int` objects received from a
+peer::
+
+ pn = dh.DHParameterNumbers(p, g)
+ parameters = pn.parameters(default_backend())
+ peer_public_numbers = dh.DHPublicNumbers(y, pn)
+ peer_public_key = peer_public_numbers.public_key(default_backend())
+
+
+See also the :class:`~cryptography.hazmat.backends.interfaces.DHBackend`
+API for additional functionality.
+
+Group parameters
+~~~~~~~~~~~~~~~~
+
+.. function:: generate_parameters(generator, key_size, backend)
+
+ .. versionadded:: 0.9
+
+ Generate a new DH parameter group for use with ``backend``.
+
+ :param generator: The :class:`int` to use as a generator. Must be
+ 2 or 5.
+
+ :param key_size: The bit length of the prime modulus to generate.
+
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.DHBackend`
+ instance.
+
+ :returns: DH parameters as a new instance of
+ :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
+
+ :raises ValueError: If ``key_size`` is not at least 512.
+
+
+.. class:: DHParameters
+
+ .. versionadded:: 0.9
+
+
+ .. method:: generate_private_key()
+
+ .. versionadded:: 0.9
+
+ Generate a DH private key. This method can be used to generate many
+ new private keys from a single set of parameters.
+
+ :return: An instance of
+ :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
+
+
+.. class:: DHParametersWithSerialization
+
+ .. versionadded:: 0.9
+
+ Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
+
+ .. method:: parameter_numbers()
+
+ Return the numbers that make up this set of parameters.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`.
+
+
+Key interfaces
+~~~~~~~~~~~~~~
+
+.. class:: DHPrivateKey
+
+ .. versionadded:: 0.9
+
+ .. attribute:: key_size
+
+ The bit length of the prime modulus.
+
+ .. method:: public_key()
+
+ Return the public key associated with this private key.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
+
+ .. method:: parameters()
+
+ Return the parameters associated with this private key.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
+
+
+.. class:: DHPrivateKeyWithSerialization
+
+ .. versionadded:: 0.9
+
+ Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
+
+ .. method:: private_numbers()
+
+ Return the numbers that make up this private key.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`.
+
+ .. method:: exchange(peer_public_key)
+
+ .. versionadded:: 1.7
+
+ :param DHPublicKeyWithSerialization peer_public_key: The public key for the
+ peer.
+
+ :return bytes: The agreed key. The bytes are ordered in 'big' endian.
+
+
+.. class:: DHPublicKey
+
+ .. versionadded:: 0.9
+
+ .. attribute:: key_size
+
+ The bit length of the prime modulus.
+
+ .. method:: parameters()
+
+ Return the parameters associated with this private key.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
+
+
+.. class:: DHPublicKeyWithSerialization
+
+ .. versionadded:: 0.9
+
+ Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
+
+ .. method:: public_numbers()
+
+ Return the numbers that make up this public key.
+
+ :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`.
+
+
Numbers
~~~~~~~
+.. class:: DHParameterNumbers(p, g)
+
+ .. versionadded:: 0.8
+
+ The collection of integers that define a Diffie-Hellman group.
+
+ .. attribute:: p
+
+ :type: int
+
+ The prime modulus value.
+
+ .. attribute:: g
+
+ :type: int
+
+ The generator value. Must be 2 or 5.
+
.. class:: DHPrivateNumbers(x, public_numbers)
.. versionadded:: 0.8
@@ -48,114 +234,5 @@
The public value.
-.. class:: DHParameterNumbers(p, g)
-
- .. versionadded:: 0.8
-
- The collection of integers that define a Diffie-Hellman group.
-
- .. attribute:: p
-
- :type: int
-
- The prime modulus value.
-
- .. attribute:: g
-
- :type: int
-
- The generator value.
-
-
-Key interfaces
-~~~~~~~~~~~~~~
-
-.. class:: DHParameters
-
- .. versionadded:: 0.9
-
-
- .. method:: generate_private_key()
-
- .. versionadded:: 0.9
-
- Generate a DH private key. This method can be used to generate many
- new private keys from a single set of parameters.
-
- :return: An instance of
- :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
-
-
-.. class:: DHParametersWithSerialization
-
- .. versionadded:: 0.9
-
- Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
-
- .. method:: parameter_numbers()
-
- Return the numbers that make up this set of parameters.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`.
-
-
-.. class:: DHPrivateKey
-
- .. versionadded:: 0.9
-
- .. attribute:: key_size
-
- The bit length of the prime modulus.
-
- .. method:: public_key()
-
- Return the public key associated with this private key.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
-
- .. method:: parameters()
-
- Return the parameters associated with this private key.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
-
-
-.. class:: DHPrivateKeyWithSerialization
-
- .. versionadded:: 0.9
-
- Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
-
- .. method:: private_numbers()
-
- Return the numbers that make up this private key.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`.
-
-
-.. class:: DHPublicKey
-
- .. versionadded:: 0.9
-
- .. attribute:: key_size
-
- The bit length of the prime modulus.
-
- .. method:: parameters()
-
- Return the parameters associated with this private key.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
-
-
-.. class:: DHPublicKeyWithSerialization
-
- .. versionadded:: 0.9
-
- Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
-
- .. method:: public_numbers()
-
- Return the numbers that make up this public key.
-
- :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`.
+.. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
+.. _`forward secrecy`: https://en.wikipedia.org/wiki/Forward_secrecy
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index 5efbbdc..186b7ee 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -32,6 +32,7 @@
Docstrings
El
Encodings
+endian
Fernet
fernet
FIPS