| .. hazmat:: |
| |
| Diffie-Hellman key exchange |
| =========================== |
| |
| .. currentmodule:: cryptography.hazmat.primitives.asymmetric.dh |
| |
| .. note:: |
| For security and performance reasons we suggest using |
| :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDH` instead of DH |
| where possible. |
| |
| |
| `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. This allows mixing of additional information into the |
| key, derivation of multiple keys, and destroys any structure that may be |
| present. |
| |
| .. warning:: |
| |
| This example does not give `forward secrecy`_ and is only provided as a |
| demonstration of the basic Diffie-Hellman construction. For real world |
| applications always use the ephemeral form described after this example. |
| |
| .. code-block:: pycon |
| |
| >>> from cryptography.hazmat.primitives import hashes |
| >>> from cryptography.hazmat.primitives.asymmetric import dh |
| >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF |
| >>> # Generate some parameters. These can be reused. |
| >>> parameters = dh.generate_parameters(generator=2, key_size=2048) |
| >>> # Generate a private key for use in the exchange. |
| >>> server_private_key = parameters.generate_private_key() |
| >>> # In a real handshake the peer is a remote client. For this |
| >>> # example we'll generate another local private key though. Note that in |
| >>> # a DH handshake both peers must agree on a common set of parameters. |
| >>> peer_private_key = parameters.generate_private_key() |
| >>> shared_key = server_private_key.exchange(peer_private_key.public_key()) |
| >>> # Perform key derivation. |
| >>> derived_key = HKDF( |
| ... algorithm=hashes.SHA256(), |
| ... length=32, |
| ... salt=None, |
| ... info=b'handshake data', |
| ... ).derive(shared_key) |
| >>> # And now we can demonstrate that the handshake performed in the |
| >>> # opposite direction gives the same final value |
| >>> same_shared_key = peer_private_key.exchange( |
| ... server_private_key.public_key() |
| ... ) |
| >>> same_derived_key = HKDF( |
| ... algorithm=hashes.SHA256(), |
| ... length=32, |
| ... salt=None, |
| ... info=b'handshake data', |
| ... ).derive(same_shared_key) |
| >>> derived_key == same_derived_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:`~DHPrivateKey.exchange` when performing an DHE key exchange. An |
| example of the ephemeral form: |
| |
| .. code-block:: pycon |
| |
| >>> from cryptography.hazmat.primitives import hashes |
| >>> from cryptography.hazmat.primitives.asymmetric import dh |
| >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF |
| >>> # Generate some parameters. These can be reused. |
| >>> parameters = dh.generate_parameters(generator=2, key_size=2048) |
| >>> # Generate a private key for use in the exchange. |
| >>> private_key = parameters.generate_private_key() |
| >>> # In a real handshake the peer_public_key will be received from the |
| >>> # other party. For this example we'll generate another private key and |
| >>> # get a public key from that. Note that in a DH handshake both peers |
| >>> # must agree on a common set of parameters. |
| >>> peer_public_key = parameters.generate_private_key().public_key() |
| >>> shared_key = private_key.exchange(peer_public_key) |
| >>> # Perform key derivation. |
| >>> derived_key = HKDF( |
| ... algorithm=hashes.SHA256(), |
| ... length=32, |
| ... salt=None, |
| ... info=b'handshake data', |
| ... ).derive(shared_key) |
| >>> # For the next handshake we MUST generate another private key, but |
| >>> # we can reuse the parameters. |
| >>> private_key_2 = parameters.generate_private_key() |
| >>> peer_public_key_2 = parameters.generate_private_key().public_key() |
| >>> shared_key_2 = private_key_2.exchange(peer_public_key_2) |
| >>> derived_key_2 = HKDF( |
| ... algorithm=hashes.SHA256(), |
| ... length=32, |
| ... salt=None, |
| ... info=b'handshake data', |
| ... ).derive(shared_key_2) |
| |
| 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() |
| peer_public_numbers = dh.DHPublicNumbers(y, pn) |
| peer_public_key = peer_public_numbers.public_key() |
| |
| |
| See also the :class:`~cryptography.hazmat.backends.interfaces.DHBackend` |
| API for additional functionality. |
| |
| Group parameters |
| ~~~~~~~~~~~~~~~~ |
| |
| .. function:: generate_parameters(generator, key_size, backend=None) |
| |
| .. versionadded:: 1.7 |
| |
| 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: An optional |
| :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:: 1.7 |
| |
| |
| .. method:: generate_private_key() |
| |
| 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`. |
| |
| .. method:: parameter_numbers() |
| |
| Return the numbers that make up this set of parameters. |
| |
| :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`. |
| |
| .. method:: parameter_bytes(encoding, format) |
| |
| .. versionadded:: 2.0 |
| |
| Allows serialization of the parameters to bytes. Encoding ( |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and |
| format ( |
| :attr:`~cryptography.hazmat.primitives.serialization.ParameterFormat.PKCS3`) |
| are chosen to define the exact serialization. |
| |
| :param encoding: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. |
| |
| :param format: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.ParameterFormat` |
| enum. At the moment only ``PKCS3`` is supported. |
| |
| :return bytes: Serialized parameters. |
| |
| .. class:: DHParametersWithSerialization |
| |
| .. versionadded:: 1.7 |
| |
| Alias for :class:`DHParameters`. |
| |
| |
| Key interfaces |
| ~~~~~~~~~~~~~~ |
| |
| .. class:: DHPrivateKey |
| |
| .. versionadded:: 1.7 |
| |
| A DH private key that is not an :term:`opaque key` also implements |
| :class:`DHPrivateKeyWithSerialization` to provide serialization methods. |
| |
| .. 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`. |
| |
| .. method:: exchange(peer_public_key) |
| |
| .. versionadded:: 1.7 |
| |
| :param DHPublicKey peer_public_key: The public key for |
| the peer. |
| |
| :return bytes: The agreed key. The bytes are ordered in 'big' endian. |
| |
| |
| .. class:: DHPrivateKeyWithSerialization |
| |
| .. versionadded:: 1.7 |
| |
| This interface contains additional methods relating to serialization. |
| Any object with this interface also has all the methods from |
| :class:`DHPrivateKey`. |
| |
| .. method:: private_numbers() |
| |
| Return the numbers that make up this private key. |
| |
| :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`. |
| |
| .. method:: private_bytes(encoding, format, encryption_algorithm) |
| |
| .. versionadded:: 1.8 |
| |
| Allows serialization of the key to bytes. Encoding ( |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`), |
| format ( |
| :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`) |
| and encryption algorithm (such as |
| :class:`~cryptography.hazmat.primitives.serialization.BestAvailableEncryption` |
| or :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`) |
| are chosen to define the exact serialization. |
| |
| :param encoding: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. |
| |
| :param format: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` |
| enum. |
| |
| :param encryption_algorithm: An instance of an object conforming to the |
| :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` |
| interface. |
| |
| :return bytes: Serialized key. |
| |
| |
| .. class:: DHPublicKey |
| |
| .. versionadded:: 1.7 |
| |
| .. 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`. |
| |
| .. method:: public_numbers() |
| |
| Return the numbers that make up this public key. |
| |
| :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`. |
| |
| .. method:: public_bytes(encoding, format) |
| |
| .. versionadded:: 1.8 |
| |
| Allows serialization of the key to bytes. Encoding ( |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or |
| :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and |
| format ( |
| :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`) |
| are chosen to define the exact serialization. |
| |
| :param encoding: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. |
| |
| :param format: A value from the |
| :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum. |
| |
| :return bytes: Serialized key. |
| |
| .. class:: DHPublicKeyWithSerialization |
| |
| .. versionadded:: 1.7 |
| |
| Alias for :class:`DHPublicKey`. |
| |
| |
| Numbers |
| ~~~~~~~ |
| |
| .. class:: DHParameterNumbers(p, g, q=None) |
| |
| .. 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 greater. |
| |
| .. attribute:: q |
| |
| .. versionadded:: 1.8 |
| |
| :type: int |
| |
| p subgroup order value. |
| |
| .. method:: parameters(backend=None) |
| |
| .. versionadded:: 1.7 |
| |
| :param backend: An optional instance of |
| :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. |
| |
| :returns: A new instance of :class:`DHParameters`. |
| |
| .. class:: DHPrivateNumbers(x, public_numbers) |
| |
| .. versionadded:: 0.8 |
| |
| The collection of integers that make up a Diffie-Hellman private key. |
| |
| .. attribute:: public_numbers |
| |
| :type: :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers` |
| |
| The :class:`DHPublicNumbers` which makes up the DH public |
| key associated with this DH private key. |
| |
| .. attribute:: x |
| |
| :type: int |
| |
| The private value. |
| |
| .. method:: private_key(backend=None) |
| |
| .. versionadded:: 1.7 |
| |
| :param backend: An optional instance of |
| :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. |
| |
| :returns: A new instance of :class:`DHPrivateKey`. |
| |
| |
| .. class:: DHPublicNumbers(y, parameter_numbers) |
| |
| .. versionadded:: 0.8 |
| |
| The collection of integers that make up a Diffie-Hellman public key. |
| |
| .. attribute:: parameter_numbers |
| |
| :type: :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers` |
| |
| The parameters for this DH group. |
| |
| .. attribute:: y |
| |
| :type: int |
| |
| The public value. |
| |
| .. method:: public_key(backend=None) |
| |
| .. versionadded:: 1.7 |
| |
| :param backend: An optional instance of |
| :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. |
| |
| :returns: A new instance of :class:`DHPublicKey`. |
| |
| |
| .. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange |
| .. _`forward secrecy`: https://en.wikipedia.org/wiki/Forward_secrecy |