412 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
			
		
		
	
	
			412 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
.. 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
 |