diff options
Diffstat (limited to 'docs/hazmat/primitives/asymmetric')
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/dh.rst | 403 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/dsa.rst | 264 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/ec.rst | 767 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/ed25519.rst | 166 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/ed448.rst | 131 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/index.rst | 10 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/interfaces.rst | 32 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/rsa.rst | 307 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/serialization.rst | 328 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/utils.rst | 70 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/x25519.rst | 184 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/x448.rst | 179 |
12 files changed, 2303 insertions, 538 deletions
diff --git a/docs/hazmat/primitives/asymmetric/dh.rst b/docs/hazmat/primitives/asymmetric/dh.rst index dde18cf7..edfe6143 100644 --- a/docs/hazmat/primitives/asymmetric/dh.rst +++ b/docs/hazmat/primitives/asymmetric/dh.rst @@ -5,114 +5,282 @@ 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.backends import default_backend + >>> 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, + ... backend=default_backend()) + >>> # 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', + ... backend=default_backend() + ... ).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', + ... backend=default_backend() + ... ).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.backends import default_backend + >>> 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, + ... backend=default_backend()) + >>> # 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', + ... backend=default_backend() + ... ).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', + ... backend=default_backend() + ... ).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(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:: 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: 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. -Numbers -~~~~~~~ -.. class:: DHPrivateNumbers(x, public_numbers) +.. class:: DHParameters - .. versionadded:: 0.8 + .. versionadded:: 1.7 - The collection of integers that make up a Diffie-Hellman private key. - .. attribute:: public_numbers + .. method:: generate_private_key() - :type: :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers` + Generate a DH private key. This method can be used to generate many + new private keys from a single set of parameters. - The :class:`DHPublicNumbers` which makes up the DH public - key associated with this DH private key. + :return: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`. - .. attribute:: x + .. method:: parameter_numbers() - :type: int + Return the numbers that make up this set of parameters. - The private value. + :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`. + .. method:: parameter_bytes(encoding, format) -.. class:: DHPublicNumbers(parameters, y) + .. versionadded:: 2.0 - .. versionadded:: 0.8 + 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. - The collection of integers that make up a Diffie-Hellman public key. + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. - .. attribute:: parameter_numbers + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.ParameterFormat` + enum. At the moment only ``PKCS3`` is supported. - :type: :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers` + :return bytes: Serialized parameters. - The parameters for this DH group. +.. class:: DHParametersWithSerialization - .. attribute:: y + .. versionadded:: 1.7 - :type: int + Alias for :class:`DHParameters`. - The public value. +Key interfaces +~~~~~~~~~~~~~~ -.. class:: DHParameterNumbers(p, g) +.. class:: DHPrivateKey - .. versionadded:: 0.8 + .. versionadded:: 1.7 - The collection of integers that define a Diffie-Hellman group. + A DH private key that is not an :term:`opaque key` also implements + :class:`DHPrivateKeyWithSerialization` to provide serialization methods. - .. attribute:: p + .. attribute:: key_size - :type: int + The bit length of the prime modulus. - The prime modulus value. + .. method:: public_key() - .. attribute:: g + Return the public key associated with this private key. - :type: int + :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`. - The generator value. + .. method:: parameters() + Return the parameters associated with this private key. -Key interfaces -~~~~~~~~~~~~~~ + :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. -.. class:: DHParameters + .. method:: exchange(peer_public_key) - .. versionadded:: 0.9 + .. versionadded:: 1.7 + :param DHPublicKey peer_public_key: The public key for + the peer. - .. method:: generate_private_key() + :return bytes: The agreed key. The bytes are ordered in 'big' endian. - .. 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. +.. class:: DHPrivateKeyWithSerialization - :return: A - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey` - provider. + .. versionadded:: 1.7 + This interface contains additional methods relating to serialization. + Any object with this interface also has all the methods from + :class:`DHPrivateKey`. -.. class:: DHParametersWithSerialization + .. method:: private_numbers() - .. versionadded:: 0.9 + Return the numbers that make up this private key. - Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. + :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`. - .. method:: parameter_numbers() + .. method:: private_bytes(encoding, format, encryption_algorithm) - Return the numbers that make up this set of parameters. + .. versionadded:: 1.8 - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`. + 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. -.. class:: DHPrivateKey + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. - .. versionadded:: 0.9 + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. - .. attribute:: key_size + :return bytes: Serialized key. - The bit length of the prime modulus. - .. method:: public_key() +.. class:: DHPublicKey - Return the public key associated with this private key. + .. versionadded:: 1.7 - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`. + .. attribute:: key_size + + The bit length of the prime modulus. .. method:: parameters() @@ -120,43 +288,132 @@ Key interfaces :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. + .. method:: public_numbers() -.. class:: DHPrivateKeyWithSerialization + Return the numbers that make up this public key. - .. versionadded:: 0.9 + :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`. - Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`. + .. method:: public_bytes(encoding, format) - .. method:: private_numbers() + .. versionadded:: 1.8 - Return the numbers that make up this private key. + 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. - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`. + :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. -.. class:: DHPublicKey + :return bytes: Serialized key. - .. versionadded:: 0.9 +.. class:: DHPublicKeyWithSerialization - .. attribute:: key_size + .. versionadded:: 1.7 - The bit length of the prime modulus. + Alias for :class:`DHPublicKey`. - .. method:: parameters() - Return the parameters associated with this private key. +Numbers +~~~~~~~ - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. +.. class:: DHParameterNumbers(p, g, q=None) + .. versionadded:: 0.8 -.. class:: DHPublicKeyWithSerialization + The collection of integers that define a Diffie-Hellman group. - .. versionadded:: 0.9 + .. attribute:: p - Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`. + :type: int - .. method:: public_numbers() + The prime modulus value. - Return the numbers that make up this public key. + .. attribute:: g - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`. + :type: int + + The generator value. Must be 2 or greater. + + .. attribute:: q + + .. versionadded:: 1.8 + + :type: int + + p subgroup order value. + + .. method:: parameters(backend) + + .. versionadded:: 1.7 + + :param backend: An 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) + + .. versionadded:: 1.7 + + :param backend: An 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) + + .. versionadded:: 1.7 + + :param backend: An 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 diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index 179bb8d1..7b059869 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -17,19 +17,18 @@ Generation Generate a DSA private key from the given key size. This function will generate a new set of parameters and key in one step. - :param int key_size: The length of the modulus in bits. It should be - either 1024, 2048 or 3072. For keys generated in 2015 this should + :param int key_size: The length of the modulus in :term:`bits`. It should + be either 1024, 2048 or 3072. For keys generated in 2015 this should be `at least 2048`_ (See page 41). Note that some applications (such as SSH) have not yet gained support for larger key sizes specified in FIPS 186-3 and are still restricted to only the 1024-bit keys specified in FIPS 186-2. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` - provider. + :return: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -41,19 +40,18 @@ Generation Generate DSA parameters using the provided ``backend``. - :param int key_size: The length of the modulus in bits. It should be - either 1024, 2048 or 3072. For keys generated in 2015 this should - be `at least 2048`_ (See page 41). Note that some applications + :param int key_size: The length of :attr:`~DSAParameterNumbers.q`. It + should be either 1024, 2048 or 3072. For keys generated in 2015 this + should be `at least 2048`_ (See page 41). Note that some applications (such as SSH) have not yet gained support for larger key sizes specified in FIPS 186-3 and are still restricted to only the 1024-bit keys specified in FIPS 186-2. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. - :return: A :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters` - provider. + :return: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -63,7 +61,7 @@ Signing ~~~~~~~ Using a :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` -provider. +instance. .. doctest:: @@ -74,34 +72,77 @@ provider. ... key_size=1024, ... backend=default_backend() ... ) - >>> signer = private_key.signer(hashes.SHA256()) >>> data = b"this is some data I'd like to sign" - >>> signer.update(data) - >>> signature = signer.finalize() + >>> signature = private_key.sign( + ... data, + ... hashes.SHA256() + ... ) The ``signature`` is a ``bytes`` object, whose contents is DER encoded as -described in :rfc:`6979`. This can be decoded using -:func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_rfc6979_signature`. +described in :rfc:`3279`. This can be decoded using +:func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`. + +If your data is too large to be passed in a single call, you can hash it +separately and pass that value using +:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import utils + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> sig = private_key.sign( + ... digest, + ... utils.Prehashed(chosen_hash) + ... ) Verification ~~~~~~~~~~~~ -Using a :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` -provider. +Verification is performed using a +:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` instance. +You can get a public key object with +:func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`, +:func:`~cryptography.hazmat.primitives.serialization.load_der_public_key`, +:meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers.public_key` +, or +:meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey.public_key`. .. doctest:: >>> public_key = private_key.public_key() - >>> verifier = public_key.verifier(signature, hashes.SHA256()) - >>> verifier.update(data) - >>> verifier.verify() + >>> public_key.verify( + ... signature, + ... data, + ... hashes.SHA256() + ... ) -``verifier()`` takes the signature in the same format as is returned by -``signer.finalize()``. +``verify()`` takes the signature in the same format as is returned by +``sign()``. ``verify()`` will raise an :class:`~cryptography.exceptions.InvalidSignature` exception if the signature isn't valid. +If your data is too large to be passed in a single call, you can hash it +separately and pass that value using +:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + +.. doctest:: + + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> public_key.verify( + ... sig, + ... digest, + ... utils.Prehashed(chosen_hash) + ... ) + Numbers ~~~~~~~ @@ -131,13 +172,11 @@ Numbers .. method:: parameters(backend) - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. - :returns: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters` - provider. + :returns: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`. .. class:: DSAPublicNumbers(y, parameter_numbers) @@ -160,13 +199,11 @@ Numbers .. method:: public_key(backend) - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. - :returns: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` - provider. + :returns: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`. .. class:: DSAPrivateNumbers(x, public_numbers) @@ -194,13 +231,11 @@ Numbers .. method:: private_key(backend) - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. - :returns: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` - provider. + :returns: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. Key interfaces ~~~~~~~~~~~~~~ @@ -218,9 +253,8 @@ Key interfaces Generate a DSA private key. This method can be used to generate many new private keys from a single set of parameters. - :return: A - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` - provider. + :return: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. .. class:: DSAParametersWithNumbers @@ -244,7 +278,9 @@ Key interfaces .. versionadded:: 0.3 - A `DSA`_ private key. + A `DSA`_ private key. A DSA private key that is not an + :term:`opaque key` also implements :class:`DSAPrivateKeyWithSerialization` + to provide serialization methods. .. method:: public_key() @@ -258,54 +294,39 @@ Key interfaces The DSAParameters object associated with this private key. - .. method:: signer(algorithm, backend) - - .. versionadded:: 0.4 - - Sign data which can be verified later by others using the public key. - The signature is formatted as DER-encoded bytes, as specified in - :rfc:`6979`. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. - - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext` - .. attribute:: key_size :type: int - The bit length of the modulus. + The bit length of :attr:`~DSAParameterNumbers.q`. + .. method:: sign(data, algorithm) -.. class:: DSAPrivateKeyWithNumbers + .. versionadded:: 1.5 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. - .. versionadded:: 0.5 + Sign one block of data which can be verified later by others using the + public key. - Extends :class:`DSAPrivateKey`. + :param bytes data: The message string to sign. - .. method:: private_numbers() + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to sign has already been hashed. - Create a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers` - object. - - :returns: A - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers` - instance. + :return bytes: Signature. .. class:: DSAPrivateKeyWithSerialization .. versionadded:: 0.8 - Extends :class:`DSAPrivateKey`. + This interface contains additional methods relating to serialization. + Any object with this interface also has all the methods from + :class:`DSAPrivateKey`. .. method:: private_numbers() @@ -355,7 +376,7 @@ Key interfaces :type: int - The bit length of the modulus. + The bit length of :attr:`~DSAParameterNumbers.q`. .. method:: parameters() @@ -363,50 +384,6 @@ Key interfaces The DSAParameters object associated with this public key. - .. method:: verifier(signature, algorithm, backend) - - .. versionadded:: 0.4 - - Verify data was signed by the private key associated with this public - key. - - :param bytes signature: The signature to verify. DER encoded as - specified in :rfc:`6979`. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. - - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext` - - -.. class:: DSAPublicKeyWithNumbers - - .. versionadded:: 0.5 - - Extends :class:`DSAPublicKey`. - - .. method:: public_numbers() - - Create a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` - object. - - :returns: A - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` - instance. - -.. class:: DSAPublicKeyWithSerialization - - .. versionadded:: 0.8 - - Extends :class:`DSAPublicKey`. - .. method:: public_numbers() Create a @@ -434,8 +411,37 @@ Key interfaces :return bytes: Serialized key. + .. method:: verify(signature, data, algorithm) + + .. versionadded:: 1.5 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. + + Verify one block of data was signed by the private key + associated with this public key. + + :param bytes signature: The signature to verify. + + :param bytes data: The message string that was signed. + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to sign has already been hashed. + + :raises cryptography.exceptions.InvalidSignature: If the signature does + not validate. + + +.. class:: DSAPublicKeyWithSerialization + + .. versionadded:: 0.8 + + Alias for :class:`DSAPublicKey`. + .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography -.. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf -.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf +.. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final +.. _`at least 2048`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst index 71f6e6fd..bd52aeee 100644 --- a/docs/hazmat/primitives/asymmetric/ec.rst +++ b/docs/hazmat/primitives/asymmetric/ec.rst @@ -12,13 +12,29 @@ Elliptic curve cryptography Generate a new private key on ``curve`` for use with ``backend``. - :param backend: A :class:`EllipticCurve` provider. + :param curve: An instance of :class:`EllipticCurve`. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. - :returns: A new instance of a :class:`EllipticCurvePrivateKey` provider. + :returns: A new instance of :class:`EllipticCurvePrivateKey`. + + +.. function:: derive_private_key(private_value, curve, backend) + + .. versionadded:: 1.6 + + Derive a private key from ``private_value`` on ``curve`` for use with + ``backend``. + + :param int private_value: The secret scalar value. + + :param curve: An instance of :class:`EllipticCurve`. + + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. + + :returns: A new instance of :class:`EllipticCurvePrivateKey`. Elliptic Curve Signature Algorithms @@ -31,9 +47,8 @@ Elliptic Curve Signature Algorithms The ECDSA signature algorithm first standardized in NIST publication `FIPS 186-3`_, and later in `FIPS 186-4`_. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. .. doctest:: @@ -43,15 +58,71 @@ Elliptic Curve Signature Algorithms >>> private_key = ec.generate_private_key( ... ec.SECP384R1(), default_backend() ... ) - >>> signer = private_key.signer(ec.ECDSA(hashes.SHA256())) - >>> signer.update(b"this is some data I'd like") - >>> signer.update(b" to sign") - >>> signature = signer.finalize() + >>> data = b"this is some data I'd like to sign" + >>> signature = private_key.sign( + ... data, + ... ec.ECDSA(hashes.SHA256()) + ... ) + + The ``signature`` is a ``bytes`` object, whose contents are DER encoded as + described in :rfc:`3279`. This can be decoded using + :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`. + + If your data is too large to be passed in a single call, you can hash it + separately and pass that value using + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import utils + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> sig = private_key.sign( + ... digest, + ... ec.ECDSA(utils.Prehashed(chosen_hash)) + ... ) + + + Verification requires the public key, the DER-encoded signature itself, the + signed data, and knowledge of the hashing algorithm that was used when + producing the signature: - The ``signature`` is a ``bytes`` object, whose contents is DER encoded as - described in :rfc:`6979`. This can be decoded using - :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_rfc6979_signature`. + >>> public_key = private_key.public_key() + >>> public_key.verify(signature, data, ec.ECDSA(hashes.SHA256())) + As above, the ``signature`` is a ``bytes`` object whose contents are DER + encoded as described in :rfc:`3279`. It can be created from a raw ``(r,s)`` + pair by using + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature`. + + If the signature is not valid, an + :class:`~cryptography.exceptions.InvalidSignature` exception will be raised. + + If your data is too large to be passed in a single call, you can hash it + separately and pass that value using + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + + .. doctest:: + + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> public_key.verify( + ... sig, + ... digest, + ... ec.ECDSA(utils.Prehashed(chosen_hash)) + ... ) + + .. note:: + Although in this case the public key was derived from the private one, + in a typical setting you will not possess the private key. The + `Key loading`_ section explains how to load the public key from other + sources. .. class:: EllipticCurvePrivateNumbers(private_value, public_numbers) @@ -78,16 +149,21 @@ Elliptic Curve Signature Algorithms Convert a collection of numbers into a private key suitable for doing actual cryptographic operations. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. - :returns: A new instance of a :class:`EllipticCurvePrivateKey` - provider. + :returns: A new instance of :class:`EllipticCurvePrivateKey`. .. class:: EllipticCurvePublicNumbers(x, y, curve) + .. warning:: + The point represented by this object is not validated in any way until + :meth:`EllipticCurvePublicNumbers.public_key` is called and may not + represent a valid point on the curve. You should not attempt to perform + any computations using the values from this class until you have either + validated it yourself or called ``public_key()`` successfully. + .. versionadded:: 0.5 The collection of integers that make up an EC public key. @@ -115,148 +191,330 @@ Elliptic Curve Signature Algorithms Convert a collection of numbers into a public key suitable for doing actual cryptographic operations. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. + + :raises ValueError: Raised if the point is invalid for the curve. + :returns: A new instance of :class:`EllipticCurvePublicKey`. + + .. method:: encode_point() + + .. warning:: + + This method is deprecated as of version 2.5. Callers should migrate + to using + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.public_bytes`. + + .. versionadded:: 1.1 + + Encodes an elliptic curve point to a byte string as described in + `SEC 1 v2.0`_ section 2.3.3. This method only supports uncompressed + points. + + :return bytes: The encoded point. + + .. classmethod:: from_encoded_point(curve, data) + + .. versionadded:: 1.1 - :returns: A new instance of a :class:`EllipticCurvePublicKey` - provider. + .. note:: + + This has been deprecated in favor of + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.from_encoded_point` + + Decodes a byte string as described in `SEC 1 v2.0`_ section 2.3.3 and + returns an :class:`EllipticCurvePublicNumbers`. This method only + supports uncompressed points. + + :param curve: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` + instance. + + :param bytes data: The serialized point byte string. + + :returns: An :class:`EllipticCurvePublicNumbers` instance. + + :raises ValueError: Raised on invalid point type or data length. + + :raises TypeError: Raised when curve is not an + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. + +Elliptic Curve Key Exchange algorithm +------------------------------------- + +.. class:: ECDH() + + .. versionadded:: 1.1 + + The Elliptic Curve Diffie-Hellman Key Exchange algorithm first standardized + in NIST publication `800-56A`_, and later in `800-56Ar2`_. + + 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. + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric import ec + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> server_private_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> # In a real handshake the peer is a remote client. For this + >>> # example we'll generate another local private key though. + >>> peer_private_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> shared_key = server_private_key.exchange( + ... ec.ECDH(), peer_private_key.public_key()) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).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( + ... ec.ECDH(), server_private_key.public_key()) + >>> # Perform key derivation. + >>> same_derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(same_shared_key) + >>> derived_key == same_derived_key + True + + ECDHE (or EECDH), the ephemeral form of this exchange, is **strongly + preferred** over simple ECDH and provides `forward secrecy`_ when used. + You must generate a new private key using :func:`generate_private_key` for + each :meth:`~EllipticCurvePrivateKey.exchange` when performing an ECDHE key + exchange. An example of the ephemeral form: + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric import ec + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> private_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> # 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. + >>> peer_public_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ).public_key() + >>> shared_key = private_key.exchange(ec.ECDH(), peer_public_key) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # For the next handshake we MUST generate another private key. + >>> private_key_2 = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> peer_public_key_2 = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ).public_key() + >>> shared_key_2 = private_key_2.exchange(ec.ECDH(), peer_public_key_2) + >>> derived_key_2 = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key_2) Elliptic Curves --------------- Elliptic curves provide equivalent security at much smaller key sizes than -asymmetric cryptography systems such as RSA or DSA. For some operations they -can also provide higher performance at every security level. According to NIST -they can have as much as a `64x lower computational cost than DH`_. +other asymmetric cryptography systems such as RSA or DSA. For many operations +elliptic curves are also significantly faster; `elliptic curve diffie-hellman +is faster than diffie-hellman`_. .. note:: Curves with a size of `less than 224 bits`_ should not be used. You should - strongly consider using curves of at least 224 bits. + strongly consider using curves of at least 224 :term:`bits`. Generally the NIST prime field ("P") curves are significantly faster than the other types suggested by NIST at both signing and verifying with ECDSA. Prime fields also `minimize the number of security concerns for elliptic-curve -cryptography`_. However there is `some concern`_ that both the prime field and +cryptography`_. However, there is `some concern`_ that both the prime field and binary field ("B") NIST curves may have been weakened during their generation. Currently `cryptography` only supports NIST curves, none of which are considered "safe" by the `SafeCurves`_ project run by Daniel J. Bernstein and Tanja Lange. -All named curves are providers of :class:`EllipticCurve`. +All named curves are instances of :class:`EllipticCurve`. -.. class:: SECT571K1 +.. class:: SECP256R1 .. versionadded:: 0.5 - SECG curve ``sect571k1``. Also called NIST K-571. + SECG curve ``secp256r1``. Also called NIST P-256. -.. class:: SECT409K1 +.. class:: SECP384R1 .. versionadded:: 0.5 - SECG curve ``sect409k1``. Also called NIST K-409. + SECG curve ``secp384r1``. Also called NIST P-384. -.. class:: SECT283K1 +.. class:: SECP521R1 .. versionadded:: 0.5 - SECG curve ``sect283k1``. Also called NIST K-283. + SECG curve ``secp521r1``. Also called NIST P-521. -.. class:: SECT233K1 +.. class:: SECP224R1 .. versionadded:: 0.5 - SECG curve ``sect233k1``. Also called NIST K-233. + SECG curve ``secp224r1``. Also called NIST P-224. -.. class:: SECT163K1 +.. class:: SECP192R1 .. versionadded:: 0.5 - SECG curve ``sect163k1``. Also called NIST K-163. + SECG curve ``secp192r1``. Also called NIST P-192. -.. class:: SECT571R1 +.. class:: SECP256K1 - .. versionadded:: 0.5 + .. versionadded:: 0.9 - SECG curve ``sect571r1``. Also called NIST B-571. + SECG curve ``secp256k1``. -.. class:: SECT409R1 +.. class:: BrainpoolP256R1 + + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: BrainpoolP384R1 + + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: BrainpoolP512R1 + + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: SECT571K1 .. versionadded:: 0.5 - SECG curve ``sect409r1``. Also called NIST B-409. + SECG curve ``sect571k1``. Also called NIST K-571. These binary curves are + discouraged for new systems. -.. class:: SECT283R1 +.. class:: SECT409K1 .. versionadded:: 0.5 - SECG curve ``sect283r1``. Also called NIST B-283. + SECG curve ``sect409k1``. Also called NIST K-409. These binary curves are + discouraged for new systems. -.. class:: SECT233R1 +.. class:: SECT283K1 .. versionadded:: 0.5 - SECG curve ``sect233r1``. Also called NIST B-233. + SECG curve ``sect283k1``. Also called NIST K-283. These binary curves are + discouraged for new systems. -.. class:: SECT163R2 +.. class:: SECT233K1 .. versionadded:: 0.5 - SECG curve ``sect163r2``. Also called NIST B-163. + SECG curve ``sect233k1``. Also called NIST K-233. These binary curves are + discouraged for new systems. -.. class:: SECP521R1 +.. class:: SECT163K1 .. versionadded:: 0.5 - SECG curve ``secp521r1``. Also called NIST P-521. + SECG curve ``sect163k1``. Also called NIST K-163. These binary curves are + discouraged for new systems. -.. class:: SECP384R1 +.. class:: SECT571R1 .. versionadded:: 0.5 - SECG curve ``secp384r1``. Also called NIST P-384. + SECG curve ``sect571r1``. Also called NIST B-571. These binary curves are + discouraged for new systems. -.. class:: SECP256R1 +.. class:: SECT409R1 .. versionadded:: 0.5 - SECG curve ``secp256r1``. Also called NIST P-256. + SECG curve ``sect409r1``. Also called NIST B-409. These binary curves are + discouraged for new systems. -.. class:: SECT224R1 +.. class:: SECT283R1 .. versionadded:: 0.5 - SECG curve ``secp224r1``. Also called NIST P-224. + SECG curve ``sect283r1``. Also called NIST B-283. These binary curves are + discouraged for new systems. -.. class:: SECP192R1 +.. class:: SECT233R1 .. versionadded:: 0.5 - SECG curve ``secp192r1``. Also called NIST P-192. + SECG curve ``sect233r1``. Also called NIST B-233. These binary curves are + discouraged for new systems. -.. class:: SECP256K1 +.. class:: SECT163R2 + + .. versionadded:: 0.5 + + SECG curve ``sect163r2``. Also called NIST B-163. These binary curves are + discouraged for new systems. - .. versionadded:: 0.9 - SECG curve ``secp256k1``. Key Interfaces @@ -270,7 +528,7 @@ Key Interfaces .. attribute:: name - :type: string + :type: str The name of the curve. Usually the name used for the ASN.1 OID such as ``secp256k1``. @@ -279,18 +537,23 @@ Key Interfaces :type: int - The bit length of the curve's base point. + Size (in :term:`bits`) of a secret scalar for the curve (as generated + by :func:`generate_private_key`). .. class:: EllipticCurveSignatureAlgorithm .. versionadded:: 0.5 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. A signature algorithm for use with elliptic curve keys. .. attribute:: algorithm - :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` The digest algorithm to be used with the signature scheme. @@ -300,19 +563,30 @@ Key Interfaces .. versionadded:: 0.5 An elliptic curve private key for use with an algorithm such as `ECDSA`_ or - `EdDSA`_. + `EdDSA`_. An elliptic curve private key that is not an + :term:`opaque key` also implements + :class:`EllipticCurvePrivateKeyWithSerialization` to provide serialization + methods. + + .. method:: exchange(algorithm, peer_public_key) - .. method:: signer(signature_algorithm) + .. versionadded:: 1.1 - Sign data which can be verified later by others using the public key. - The signature is formatted as DER-encoded bytes, as specified in - :rfc:`6979`. + Performs a key exchange operation using the provided algorithm with + the peer's public key. - :param signature_algorithm: An instance of a - :class:`EllipticCurveSignatureAlgorithm` provider. + 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. - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext` + :param algorithm: The key exchange algorithm, currently only + :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDH` is + supported. + :param EllipticCurvePublicKey peer_public_key: The public key for the + peer. + + :returns bytes: A shared key. .. method:: public_key() @@ -320,25 +594,46 @@ Key Interfaces The EllipticCurvePublicKey object for this private key. + .. method:: sign(data, signature_algorithm) -.. class:: EllipticCurvePrivateKeyWithNumbers + .. versionadded:: 1.5 - .. versionadded:: 0.6 + Sign one block of data which can be verified later by others using the + public key. - Extends :class:`EllipticCurvePrivateKey`. + :param bytes data: The message string to sign. - .. method:: private_numbers() + :param signature_algorithm: An instance of + :class:`EllipticCurveSignatureAlgorithm`, such as :class:`ECDSA`. - Create a :class:`EllipticCurvePrivateNumbers` object. + :return bytes: The signature as a ``bytes`` object, whose contents are + DER encoded as described in :rfc:`3279`. This can be decoded using + :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`, + which returns the decoded tuple ``(r, s)``. - :returns: An :class:`EllipticCurvePrivateNumbers` instance. + .. attribute:: curve + + :type: :class:`EllipticCurve` + + The EllipticCurve that this key is on. + + .. attribute:: key_size + + .. versionadded:: 1.9 + + :type: int + + Size (in :term:`bits`) of a secret scalar for the curve (as generated + by :func:`generate_private_key`). .. class:: EllipticCurvePrivateKeyWithSerialization .. versionadded:: 0.8 - Extends :class:`EllipticCurvePrivateKey`. + This interface contains additional methods relating to serialization. + Any object with this interface also has all the methods from + :class:`EllipticCurvePrivateKey`. .. method:: private_numbers() @@ -379,76 +674,300 @@ Key Interfaces An elliptic curve public key. - .. method:: verifier(signature, signature_algorithm) + .. attribute:: curve - Verify data was signed by the private key associated with this public - key. + :type: :class:`EllipticCurve` - :param bytes signature: The signature to verify. DER encoded as - specified in :rfc:`6979`. + The elliptic curve for this key. - :param signature_algorithm: An instance of a - :class:`EllipticCurveSignatureAlgorithm` provider. + .. method:: public_numbers() - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext` + Create a :class:`EllipticCurvePublicNumbers` object. - .. attribute:: curve + :returns: An :class:`EllipticCurvePublicNumbers` instance. - :type: :class:`EllipticCurve` + .. method:: public_bytes(encoding, format) - The elliptic curve for this key. + Allows serialization of the key data to bytes. When encoding the public + key the encodings ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`) + are chosen to define the exact serialization. When encoding the point + the encoding + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.X962` + should be used with the formats ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.UncompressedPoint` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.CompressedPoint` + ). + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. -.. class:: EllipticCurvePublicKeyWithNumbers + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum. - .. versionadded:: 0.6 + :return bytes: Serialized data. - Extends :class:`EllipticCurvePublicKey`. + .. method:: verify(signature, data, signature_algorithm) - .. method:: public_numbers() + .. versionadded:: 1.5 - Create a :class:`EllipticCurvePublicNumbers` object. + Verify one block of data was signed by the private key associated + with this public key. - :returns: An :class:`EllipticCurvePublicNumbers` instance. + :param bytes signature: The DER-encoded signature to verify. + A raw signature may be DER-encoded by splitting it into the ``r`` + and ``s`` components and passing them into + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature`. + + :param bytes data: The message string that was signed. + + :param signature_algorithm: An instance of + :class:`EllipticCurveSignatureAlgorithm`. + + :raises cryptography.exceptions.InvalidSignature: If the signature does + not validate. + + .. attribute:: key_size + + .. versionadded:: 1.9 + + :type: int + + Size (in :term:`bits`) of a secret scalar for the curve (as generated + by :func:`generate_private_key`). + + .. classmethod:: from_encoded_point(curve, data) + + .. versionadded:: 2.5 + + Decodes a byte string as described in `SEC 1 v2.0`_ section 2.3.3 and + returns an :class:`EllipticCurvePublicKey`. This class method supports + compressed points. + + :param curve: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` + instance. + + :param bytes data: The serialized point byte string. + + :returns: An :class:`EllipticCurvePublicKey` instance. + + :raises ValueError: Raised when an invalid point is supplied. + + :raises TypeError: Raised when curve is not an + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. .. class:: EllipticCurvePublicKeyWithSerialization .. versionadded:: 0.6 - Extends :class:`EllipticCurvePublicKey`. + Alias for :class:`EllipticCurvePublicKey`. - .. method:: public_numbers() - Create a :class:`EllipticCurvePublicNumbers` object. - :returns: An :class:`EllipticCurvePublicNumbers` instance. +Serialization +~~~~~~~~~~~~~ - .. method:: public_bytes(encoding, format) +This sample demonstrates how to generate a private key and serialize it. - 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. +.. doctest:: - :param format: A value from the - :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum. + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ec - :return bytes: Serialized key. + >>> private_key = ec.generate_private_key(ec.SECP384R1(), default_backend()) + + >>> serialized_private = private_key.private_bytes( + ... encoding=serialization.Encoding.PEM, + ... format=serialization.PrivateFormat.PKCS8, + ... encryption_algorithm=serialization.BestAvailableEncryption(b'testpassword') + ... ) + >>> serialized_private.splitlines()[0] + b'-----BEGIN ENCRYPTED PRIVATE KEY-----' + +You can also serialize the key without a password, by relying on +:class:`~cryptography.hazmat.primitives.serialization.NoEncryption`. + +The public key is serialized as follows: + + +.. doctest:: + + >>> public_key = private_key.public_key() + >>> serialized_public = public_key.public_bytes( + ... encoding=serialization.Encoding.PEM, + ... format=serialization.PublicFormat.SubjectPublicKeyInfo + ... ) + >>> serialized_public.splitlines()[0] + b'-----BEGIN PUBLIC KEY-----' + +This is the part that you would normally share with the rest of the world. + + +Key loading +~~~~~~~~~~~ + +This extends the sample in the previous section, assuming that the variables +``serialized_private`` and ``serialized_public`` contain the respective keys +in PEM format. + +.. doctest:: + + >>> loaded_public_key = serialization.load_pem_public_key( + ... serialized_public, + ... backend=default_backend() + ... ) + + >>> loaded_private_key = serialization.load_pem_private_key( + ... serialized_private, + ... # or password=None, if in plain text + ... password=b'testpassword', + ... backend=default_backend() + ... ) + + +Elliptic Curve Object Identifiers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: EllipticCurveOID + + .. versionadded:: 2.4 + + .. attribute:: SECP192R1 + + Corresponds to the dotted string ``"1.2.840.10045.3.1.1"``. + + .. attribute:: SECP224R1 + + Corresponds to the dotted string ``"1.3.132.0.33"``. + + .. attribute:: SECP256K1 + + Corresponds to the dotted string ``"1.3.132.0.10"``. + + .. attribute:: SECP256R1 + + Corresponds to the dotted string ``"1.2.840.10045.3.1.7"``. + + .. attribute:: SECP384R1 + + Corresponds to the dotted string ``"1.3.132.0.34"``. + + .. attribute:: SECP521R1 + + Corresponds to the dotted string ``"1.3.132.0.35"``. + + .. attribute:: BRAINPOOLP256R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.7"``. + + .. attribute:: BRAINPOOLP384R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.11"``. + + .. attribute:: BRAINPOOLP512R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.13"``. + + .. attribute:: SECT163K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.1"``. + + .. attribute:: SECT163R2 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.15"``. + + .. attribute:: SECT233K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.26"``. + + .. attribute:: SECT233R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.27"``. + + .. attribute:: SECT283K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.16"``. + + .. attribute:: SECT283R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.17"``. + + .. attribute:: SECT409K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.36"``. + + .. attribute:: SECT409R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.37"``. + + .. attribute:: SECT571K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.38"``. + + .. attribute:: SECT571R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.39"``. + +.. function:: get_curve_for_oid(oid) + + .. versionadded:: 2.6 + + A function that takes an :class:`~cryptography.x509.ObjectIdentifier` + and returns the associated elliptic curve class. + + :param oid: An instance of + :class:`~cryptography.x509.ObjectIdentifier`. + + :returns: The matching elliptic curve class. The returned class conforms + to the :class:`EllipticCurve` interface. + :raises LookupError: Raised if no elliptic curve is found that matches + the provided object identifier. -.. _`FIPS 186-3`: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf -.. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +.. _`FIPS 186-3`: https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf +.. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final +.. _`800-56A`: https://csrc.nist.gov/publications/detail/sp/800-56a/revised/archive/2007-03-14 +.. _`800-56Ar2`: https://csrc.nist.gov/publications/detail/sp/800-56a/rev-2/final .. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters -.. _`less than 224 bits`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf -.. _`64x lower computational cost than DH`: https://www.nsa.gov/business/programs/elliptic_curve.shtml -.. _`minimize the number of security concerns for elliptic-curve cryptography`: http://cr.yp.to/ecdh/curve25519-20060209.pdf -.. _`SafeCurves`: http://safecurves.cr.yp.to/ +.. _`less than 224 bits`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf +.. _`elliptic curve diffie-hellman is faster than diffie-hellman`: https://digitalcommons.unl.edu/cgi/viewcontent.cgi?article=1100&context=cseconfwork +.. _`minimize the number of security concerns for elliptic-curve cryptography`: https://cr.yp.to/ecdh/curve25519-20060209.pdf +.. _`SafeCurves`: https://safecurves.cr.yp.to/ .. _`ECDSA`: https://en.wikipedia.org/wiki/ECDSA .. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA +.. _`forward secrecy`: https://en.wikipedia.org/wiki/Forward_secrecy +.. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf diff --git a/docs/hazmat/primitives/asymmetric/ed25519.rst b/docs/hazmat/primitives/asymmetric/ed25519.rst new file mode 100644 index 00000000..f9e007c5 --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/ed25519.rst @@ -0,0 +1,166 @@ +.. hazmat:: + +Ed25519 signing +=============== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed25519 + + +Ed25519 is an elliptic curve signing algorithm using `EdDSA`_ and +`Curve25519`_. If you do not have legacy interoperability concerns then you +should strongly consider using this signature algorithm. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey + >>> private_key = Ed25519PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed25519PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed25519 private key. + + :returns: :class:`Ed25519PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 32 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed25519PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes) + + + .. method:: public_key() + + :returns: :class:`Ed25519PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 64 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed25519PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 32 byte public key. + + :returns: :class:`Ed25519PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = ed25519.Ed25519PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.OpenSSH`, + or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`, + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.OpenSSH` + , or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw`. + If ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.OpenSSH` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.OpenSSH`. + In all other cases ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA +.. _`Curve25519`: https://en.wikipedia.org/wiki/Curve25519 diff --git a/docs/hazmat/primitives/asymmetric/ed448.rst b/docs/hazmat/primitives/asymmetric/ed448.rst new file mode 100644 index 00000000..fb79dcb6 --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/ed448.rst @@ -0,0 +1,131 @@ +.. hazmat:: + +Ed448 signing +============= + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed448 + + +Ed448 is an elliptic curve signing algorithm using `EdDSA`_. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey + >>> private_key = Ed448PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed448PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed448 private key. + + :returns: :class:`Ed448PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 57 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed448PrivateKey` + + .. method:: public_key() + + :returns: :class:`Ed448PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 114 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed448PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 57 byte public key. + + :returns: :class:`Ed448PublicKey` + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA diff --git a/docs/hazmat/primitives/asymmetric/index.rst b/docs/hazmat/primitives/asymmetric/index.rst index 4242a0bd..c27e1781 100644 --- a/docs/hazmat/primitives/asymmetric/index.rst +++ b/docs/hazmat/primitives/asymmetric/index.rst @@ -20,18 +20,18 @@ symmetric encryption. Someone with the public key is able to encrypt a message, providing confidentiality, and then only the person in possession of the private key is able to decrypt it. -Cryptography supports three different sets of asymmetric algorithms: RSA, DSA, -and Elliptic Curve. - .. toctree:: :maxdepth: 1 - dsa + ed25519 + x25519 + ed448 + x448 ec rsa dh + dsa serialization - interfaces utils diff --git a/docs/hazmat/primitives/asymmetric/interfaces.rst b/docs/hazmat/primitives/asymmetric/interfaces.rst deleted file mode 100644 index c4f176c6..00000000 --- a/docs/hazmat/primitives/asymmetric/interfaces.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. hazmat:: - -.. module:: cryptography.hazmat.primitives.asymmetric - -Signature Interfaces -==================== - -.. class:: AsymmetricSignatureContext - - .. versionadded:: 0.2 - - .. method:: update(data) - - :param bytes data: The data you want to sign. - - .. method:: finalize() - - :return bytes signature: The signature. - - -.. class:: AsymmetricVerificationContext - - .. versionadded:: 0.2 - - .. method:: update(data) - - :param bytes data: The data you wish to verify using the signature. - - .. method:: verify() - - :raises cryptography.exceptions.InvalidSignature: If the signature does - not validate. diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index 3b5b677b..dab90964 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -19,11 +19,12 @@ mathematical properties`_. .. versionadded:: 0.5 Generates a new RSA private key using the provided ``backend``. - ``key_size`` describes how many bits long the key should be, larger keys - provide more security, currently ``1024`` and below are considered - breakable, and ``2048`` or ``4096`` are reasonable default key sizes for + ``key_size`` describes how many :term:`bits` long the key should be. Larger + keys provide more security; currently ``1024`` and below are considered + breakable while ``2048`` or ``4096`` are reasonable default key sizes for new keys. The ``public_exponent`` indicates what one mathematical property - of the key generation will be, ``65537`` should almost always be used. + of the key generation will be. Unless you have a specific reason to do + otherwise, you should always `use 65537`_. .. doctest:: @@ -39,12 +40,12 @@ mathematical properties`_. Usually one of the small Fermat primes 3, 5, 17, 257, 65537. If in doubt you should `use 65537`_. - :param int key_size: The length of the modulus in bits. For keys + :param int key_size: The length of the modulus in :term:`bits`. For keys generated in 2015 it is strongly recommended to be `at least 2048`_ (See page 41). It must not be less than 512. Some backends may have additional limitations. - :param backend: A backend which provides + :param backend: A backend which implements :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. :return: An instance of @@ -63,6 +64,7 @@ markers), you can load it: .. code-block:: pycon + >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import serialization >>> with open("path/to/key.pem", "rb") as key_file: @@ -98,7 +100,7 @@ to serialize the key. ... encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') ... ) >>> pem.splitlines()[0] - '-----BEGIN ENCRYPTED PRIVATE KEY-----' + b'-----BEGIN ENCRYPTED PRIVATE KEY-----' It is also possible to serialize without encryption using :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`. @@ -111,12 +113,10 @@ It is also possible to serialize without encryption using ... encryption_algorithm=serialization.NoEncryption() ... ) >>> pem.splitlines()[0] - '-----BEGIN RSA PRIVATE KEY-----' + b'-----BEGIN RSA PRIVATE KEY-----' -Similarly, if your public key implements -:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` -interface you can use -:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization.public_bytes` +For public keys you can use +:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.public_bytes` to serialize the key. .. doctest:: @@ -128,7 +128,7 @@ to serialize the key. ... format=serialization.PublicFormat.SubjectPublicKeyInfo ... ) >>> pem.splitlines()[0] - '-----BEGIN PUBLIC KEY-----' + b'-----BEGIN PUBLIC KEY-----' Signing ~~~~~~~ @@ -143,17 +143,15 @@ secure hash function and padding: >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import padding - - >>> signer = private_key.signer( + >>> message = b"A message I want to sign" + >>> signature = private_key.sign( + ... message, ... padding.PSS( ... mgf=padding.MGF1(hashes.SHA256()), ... salt_length=padding.PSS.MAX_LENGTH ... ), ... hashes.SHA256() ... ) - >>> message = b"A message I want to sign" - >>> signer.update(message) - >>> signature = signer.finalize() Valid paddings for signatures are :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` and @@ -161,31 +159,78 @@ Valid paddings for signatures are is the recommended choice for any new protocols or applications, ``PKCS1v15`` should only be used to support legacy protocols. +If your data is too large to be passed in a single call, you can hash it +separately and pass that value using +:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import utils + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> sig = private_key.sign( + ... digest, + ... padding.PSS( + ... mgf=padding.MGF1(hashes.SHA256()), + ... salt_length=padding.PSS.MAX_LENGTH + ... ), + ... utils.Prehashed(chosen_hash) + ... ) + Verification ~~~~~~~~~~~~ The previous section describes what to do if you have a private key and want to -sign something. If you have a public key, a message, and a signature, you can -check that the public key genuinely was used to sign that specific message. You -also need to know which signing algorithm was used: +sign something. If you have a public key, a message, a signature, and the +signing algorithm that was used you can check that the private key associated +with a given public key was used to sign that specific message. You can obtain +a public key to use in verification using +:func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`, +:func:`~cryptography.hazmat.primitives.serialization.load_der_public_key`, +:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers.public_key` +, or +:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.public_key`. .. doctest:: >>> public_key = private_key.public_key() - >>> verifier = public_key.verifier( + >>> public_key.verify( ... signature, + ... message, ... padding.PSS( ... mgf=padding.MGF1(hashes.SHA256()), ... salt_length=padding.PSS.MAX_LENGTH ... ), ... hashes.SHA256() ... ) - >>> verifier.update(message) - >>> verifier.verify() If the signature does not match, ``verify()`` will raise an :class:`~cryptography.exceptions.InvalidSignature` exception. +If your data is too large to be passed in a single call, you can hash it +separately and pass that value using +:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`. + +.. doctest:: + + >>> chosen_hash = hashes.SHA256() + >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher.update(b"data & ") + >>> hasher.update(b"more data") + >>> digest = hasher.finalize() + >>> public_key.verify( + ... sig, + ... digest, + ... padding.PSS( + ... mgf=padding.MGF1(hashes.SHA256()), + ... salt_length=padding.PSS.MAX_LENGTH + ... ), + ... utils.Prehashed(chosen_hash) + ... ) + Encryption ~~~~~~~~~~ @@ -202,8 +247,8 @@ options. Here's an example using a secure padding and hash function: >>> ciphertext = public_key.encrypt( ... message, ... padding.OAEP( - ... mgf=padding.MGF1(algorithm=hashes.SHA1()), - ... algorithm=hashes.SHA1(), + ... mgf=padding.MGF1(algorithm=hashes.SHA256()), + ... algorithm=hashes.SHA256(), ... label=None ... ) ... ) @@ -225,8 +270,8 @@ Once you have an encrypted message, it can be decrypted using the private key: >>> plaintext = private_key.decrypt( ... ciphertext, ... padding.OAEP( - ... mgf=padding.MGF1(algorithm=hashes.SHA1()), - ... algorithm=hashes.SHA1(), + ... mgf=padding.MGF1(algorithm=hashes.SHA256()), + ... algorithm=hashes.SHA256(), ... label=None ... ) ... ) @@ -267,7 +312,7 @@ Padding Pass this attribute to ``salt_length`` to get the maximum salt length available. -.. class:: OAEP(mgf, label) +.. class:: OAEP(mgf, algorithm, label) .. versionadded:: 0.4 @@ -279,6 +324,9 @@ Padding :param mgf: A mask generation function object. At this time the only supported MGF is :class:`MGF1`. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + :param bytes label: A label to apply. This is a rarely used field and should typically be set to ``None`` or ``b""``, which are equivalent. @@ -294,6 +342,20 @@ Padding :class:`OAEP` should be preferred for encryption and :class:`PSS` should be preferred for signatures. + +.. function:: calculate_max_pss_salt_length(key, hash_algorithm) + + .. versionadded:: 1.5 + + :param key: An RSA public or private key. + :param hash_algorithm: A + :class:`cryptography.hazmat.primitives.hashes.HashAlgorithm`. + :returns int: The computed salt length. + + Computes the length of the salt that :class:`PSS` will use if + :data:`PSS.MAX_LENGTH` is used. + + Mask generation functions ------------------------- @@ -305,11 +367,10 @@ Mask generation functions Removed the deprecated ``salt_length`` parameter. MGF1 (Mask Generation Function 1) is used as the mask generation function - in :class:`PSS` padding. It takes a hash algorithm and a salt length. + in :class:`PSS` and :class:`OAEP` padding. It takes a hash algorithm. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. Numbers ~~~~~~~ @@ -340,13 +401,11 @@ is unavailable. .. method:: public_key(backend) - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.RSABackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. - :returns: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` - provider. + :returns: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`. .. class:: RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, public_numbers) @@ -409,13 +468,11 @@ is unavailable. .. method:: private_key(backend) - :param backend: A new instance of a - :class:`~cryptography.hazmat.backends.interfaces.RSABackend` - provider. + :param backend: A new instance of + :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. - :returns: A - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` - provider. + :returns: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`. Handling partial RSA private keys ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -423,7 +480,7 @@ Handling partial RSA private keys If you are trying to load RSA private keys yourself you may find that not all parameters required by ``RSAPrivateNumbers`` are available. In particular the `Chinese Remainder Theorem`_ (CRT) values ``dmp1``, ``dmq1``, ``iqmp`` may be -missing or present in a different form. For example `OpenPGP`_ does not include +missing or present in a different form. For example, `OpenPGP`_ does not include the ``iqmp``, ``dmp1`` or ``dmq1`` parameters. The following functions are provided for users who want to work with keys like @@ -440,15 +497,15 @@ this without having to do the math themselves. .. versionadded:: 0.4 - Computes the ``dmp1`` parameter from the RSA private exponent and prime - ``p``. + Computes the ``dmp1`` parameter from the RSA private exponent (``d``) and + prime ``p``. .. function:: rsa_crt_dmq1(private_exponent, q) .. versionadded:: 0.4 - Computes the ``dmq1`` parameter from the RSA private exponent and prime - ``q``. + Computes the ``dmq1`` parameter from the RSA private exponent (``d``) and + prime ``q``. .. function:: rsa_recover_prime_factors(n, e, d) @@ -460,7 +517,9 @@ this without having to do the math themselves. .. note:: When recovering prime factors this algorithm will always return ``p`` - and ``q`` such that ``p < q``. + and ``q`` such that ``p > q``. Note: before 1.5, this function always + returned ``p`` and ``q`` such that ``p < q``. It was changed because + libraries commonly require ``p > q``. :return: A tuple ``(p, q)`` @@ -472,24 +531,9 @@ Key interfaces .. versionadded:: 0.2 - An `RSA`_ private key. - - .. method:: signer(padding, algorithm) - - .. versionadded:: 0.3 - - Sign data which can be verified later by others using the public key. - - :param padding: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding` - provider. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext` + An `RSA`_ private key. An RSA private key that is not an + :term:`opaque key` also implements :class:`RSAPrivateKeyWithSerialization` + to provide serialization methods. .. method:: decrypt(ciphertext, padding) @@ -499,9 +543,8 @@ Key interfaces :param bytes ciphertext: The ciphertext to decrypt. - :param padding: An instance of an - :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding` - provider. + :param padding: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. :return bytes: Decrypted data. @@ -517,29 +560,36 @@ Key interfaces The bit length of the modulus. + .. method:: sign(data, padding, algorithm) -.. class:: RSAPrivateKeyWithNumbers + .. versionadded:: 1.4 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. - .. versionadded:: 0.5 + Sign one block of data which can be verified later by others using the + public key. - Extends :class:`RSAPrivateKey`. + :param bytes data: The message string to sign. - .. method:: private_numbers() + :param padding: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. - Create a - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers` - object. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to sign has already been hashed. - :returns: An - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers` - instance. + :return bytes: Signature. .. class:: RSAPrivateKeyWithSerialization .. versionadded:: 0.8 - Extends :class:`RSAPrivateKey`. + This interface contains additional methods relating to serialization. + Any object with this interface also has all the methods from + :class:`RSAPrivateKey`. .. method:: private_numbers() @@ -585,26 +635,6 @@ Key interfaces An `RSA`_ public key. - .. method:: verifier(signature, padding, algorithm) - - .. versionadded:: 0.3 - - Verify data was signed by the private key associated with this public - key. - - :param bytes signature: The signature to verify. - - :param padding: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding` - provider. - - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. - - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext` - .. method:: encrypt(plaintext, padding) .. versionadded:: 0.4 @@ -613,9 +643,8 @@ Key interfaces :param bytes plaintext: The plaintext to encrypt. - :param padding: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding` - provider. + :param padding: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. :return bytes: Encrypted data. @@ -625,30 +654,6 @@ Key interfaces The bit length of the modulus. - -.. class:: RSAPublicKeyWithNumbers - - .. versionadded:: 0.5 - - Extends :class:`RSAPublicKey`. - - .. method:: public_numbers() - - Create a - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers` - object. - - :returns: An - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers` - instance. - - -.. class:: RSAPublicKeyWithSerialization - - .. versionadded:: 0.8 - - Extends :class:`RSAPublicKey`. - .. method:: public_numbers() Create a @@ -678,14 +683,46 @@ Key interfaces :return bytes: Serialized key. + .. method:: verify(signature, data, padding, algorithm) + + .. versionadded:: 1.4 + .. versionchanged:: 1.6 + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + can now be used as an ``algorithm``. + + Verify one block of data was signed by the private key + associated with this public key. + + :param bytes signature: The signature to verify. + + :param bytes data: The message string that was signed. + + :param padding: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`. + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` or + :class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed` + if the ``data`` you want to verify has already been hashed. + + :raises cryptography.exceptions.InvalidSignature: If the signature does + not validate. + + +.. class:: RSAPublicKeyWithSerialization + + .. versionadded:: 0.8 + + Alias for :class:`RSAPublicKey`. + .. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem) .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`specific mathematical properties`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation -.. _`use 65537`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf +.. _`use 65537`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`at least 2048`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf .. _`OpenPGP`: https://en.wikipedia.org/wiki/Pretty_Good_Privacy .. _`Chinese Remainder Theorem`: https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29#Using_the_Chinese_remainder_algorithm -.. _`security proof`: http://eprint.iacr.org/2001/062.pdf -.. _`recommended padding algorithm`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`proven secure`: http://cseweb.ucsd.edu/~mihir/papers/oae.pdf +.. _`security proof`: https://eprint.iacr.org/2001/062.pdf +.. _`recommended padding algorithm`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`proven secure`: https://cseweb.ucsd.edu/~mihir/papers/oae.pdf diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 7839f346..7c1fc82e 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -63,6 +63,20 @@ Key Serialization def sign_with_dsa_key(key, message): return b"" + parameters_pem_data = b""" + -----BEGIN DH PARAMETERS----- + MIGHAoGBALsrWt44U1ojqTy88o0wfjysBE51V6Vtarjm2+5BslQK/RtlndHde3gx + +ccNs+InANszcuJFI8AHt4743kGRzy5XSlul4q4dDJENOHoyqYxueFuFVJELEwLQ + XrX/McKw+hS6GPVQnw6tZhgGo9apdNdYgeLQeQded8Bum8jqzP3rAgEC + -----END DH PARAMETERS----- + """.strip() + + parameters_der_data = base64.b64decode( + b"MIGHAoGBALsrWt44U1ojqTy88o0wfjysBE51V6Vtarjm2+5BslQK/RtlndHde3gx+ccNs+In" + b"ANsz\ncuJFI8AHt4743kGRzy5XSlul4q4dDJENOHoyqYxueFuFVJELEwLQXrX/McKw+hS6GP" + b"VQnw6tZhgG\no9apdNdYgeLQeQded8Bum8jqzP3rAgEC" + ) + There are several common schemes for serializing asymmetric private and public keys to bytes. They generally support encryption of private keys and additional key metadata. @@ -85,6 +99,16 @@ methods. ... else: ... raise TypeError +Key dumping +~~~~~~~~~~~ + +The ``serialization`` module contains functions for loading keys from +``bytes``. To dump a ``key`` object to ``bytes``, you must call the appropriate +method on the key object. Documentation for these methods in found in the +:mod:`~cryptography.hazmat.primitives.asymmetric.rsa`, +:mod:`~cryptography.hazmat.primitives.asymmetric.dsa`, and +:mod:`~cryptography.hazmat.primitives.asymmetric.ec` module documentation. + PEM ~~~ @@ -97,8 +121,8 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END .. note:: A PEM block which starts with ``-----BEGIN CERTIFICATE-----`` is not a - public or private key, it's an :doc:`X.509 Certificate </x509>`. You can - load it using :func:`~cryptography.x509.load_pem_x509_certificate` and + public or private key, it's an :doc:`X.509 Certificate </x509/index>`. You + can load it using :func:`~cryptography.x509.load_pem_x509_certificate` and extract the public key with :meth:`Certificate.public_key <cryptography.x509.Certificate.public_key>`. @@ -109,16 +133,23 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END Deserialize a private key from PEM encoded data to one of the supported asymmetric private key types. - :param bytes data: The PEM encoded key data. + :param data: The PEM encoded key data. + :type data: :term:`bytes-like` - :param bytes password: The password to use to decrypt the data. Should + :param password: The password to use to decrypt the data. Should be ``None`` if the private key is not encrypted. + :type data: :term:`bytes-like` - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. - :returns: A new instance of a private key. + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, + or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + depending on the contents of ``data``. :raises ValueError: If the PEM data could not be decrypted or if its structure could not be decoded successfully. @@ -136,7 +167,8 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END .. versionadded:: 0.6 Deserialize a public key from PEM encoded data to one of the supported - asymmetric public key types. + asymmetric public key types. The PEM encoded data is typically a + ``subjectPublicKeyInfo`` payload as specified in :rfc:`5280`. .. doctest:: @@ -147,11 +179,17 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END :param bytes data: The PEM encoded key data. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. - :returns: A new instance of a public key. + + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, + or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + depending on the contents of ``data``. :raises ValueError: If the PEM data's structure could not be decoded successfully. @@ -159,6 +197,37 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported by the backend. +.. function:: load_pem_parameters(data, backend) + + .. versionadded:: 2.0 + + Deserialize parameters from PEM encoded data to one of the supported + asymmetric parameters types. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.serialization import load_pem_parameters + >>> from cryptography.hazmat.primitives.asymmetric import dh + >>> parameters = load_pem_parameters(parameters_pem_data, backend=default_backend()) + >>> isinstance(parameters, dh.DHParameters) + True + + :param bytes data: The PEM encoded parameters data. + + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. + + + :returns: Currently only + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters` + supported. + + :raises ValueError: If the PEM data's structure could not be decoded + successfully. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized parameters + is of a type that is not supported by the backend. + DER ~~~ @@ -174,16 +243,23 @@ the rest. Deserialize a private key from DER encoded data to one of the supported asymmetric private key types. - :param bytes data: The DER encoded key data. + :param data: The DER encoded key data. + :type data: :term:`bytes-like` - :param bytes password: The password to use to decrypt the data. Should + :param password: The password to use to decrypt the data. Should be ``None`` if the private key is not encrypted. + :type password: :term:`bytes-like` - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. - :returns: A new instance of a private key. + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, + or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + depending on the contents of ``data``. :raises ValueError: If the DER data could not be decrypted or if its structure could not be decoded successfully. @@ -210,15 +286,21 @@ the rest. .. versionadded:: 0.8 Deserialize a public key from DER encoded data to one of the supported - asymmetric public key types. + asymmetric public key types. The DER encoded data is typically a + ``subjectPublicKeyInfo`` payload as specified in :rfc:`5280`. :param bytes data: The DER encoded key data. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. - :returns: A new instance of a public key. + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, + or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + depending on the contents of ``data``. :raises ValueError: If the DER data's structure could not be decoded successfully. @@ -235,6 +317,37 @@ the rest. >>> isinstance(key, rsa.RSAPublicKey) True +.. function:: load_der_parameters(data, backend) + + .. versionadded:: 2.0 + + Deserialize parameters from DER encoded data to one of the supported + asymmetric parameters types. + + :param bytes data: The DER encoded parameters data. + + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. + + :returns: Currently only + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters` + supported. + + :raises ValueError: If the DER data's structure could not be decoded + successfully. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that + is not supported by the backend. + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives.asymmetric import dh + >>> from cryptography.hazmat.primitives.serialization import load_der_parameters + >>> parameters = load_der_parameters(parameters_der_data, backend=default_backend()) + >>> isinstance(parameters, dh.DHParameters) + True + OpenSSH Public Key ~~~~~~~~~~~~~~~~~~ @@ -263,19 +376,21 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than Deserialize a public key from OpenSSH (:rfc:`4253`) encoded data to an instance of the public key type for the specified backend. - .. note:: - - Currently Ed25519 keys are not supported. - :param bytes data: The OpenSSH encoded key data. - :param backend: A backend providing + :param backend: A backend which implements :class:`~cryptography.hazmat.backends.interfaces.RSABackend`, :class:`~cryptography.hazmat.backends.interfaces.DSABackend`, or :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` depending on the key's type. - :returns: A new instance of a public key type. + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + , or + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + depending on the contents of ``data``. :raises ValueError: If the OpenSSH data could not be properly decoded or if the key is not in the proper format. @@ -283,9 +398,48 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported. +PKCS12 +~~~~~~ + +.. currentmodule:: cryptography.hazmat.primitives.serialization.pkcs12 + +PKCS12 is a binary format described in :rfc:`7292`. It can contain +certificates, keys, and more. PKCS12 files commonly have a ``pfx`` or ``p12`` +file suffix. + +.. note:: + + ``cryptography`` only supports a single private key and associated + certificates when parsing PKCS12 files at this time. + +.. function:: load_key_and_certificates(data, password, backend) + + .. versionadded:: 2.5 + + Deserialize a PKCS12 blob. + + :param data: The binary data. + :type data: :term:`bytes-like` + + :param password: The password to use to decrypt the data. ``None`` + if the PKCS12 is not encrypted. + :type password: :term:`bytes-like` + + :param backend: A backend instance. + + :returns: A tuple of + ``(private_key, certificate, additional_certificates)``. + ``private_key`` is a private key type or ``None``, ``certificate`` + is either the :class:`~cryptography.x509.Certificate` whose public key + matches the private key in the PKCS 12 object or ``None``, and + ``additional_certificates`` is a list of all other + :class:`~cryptography.x509.Certificate` instances in the PKCS12 object. + Serialization Formats ~~~~~~~~~~~~~~~~~~~~~ +.. currentmodule:: cryptography.hazmat.primitives.serialization + .. class:: PrivateFormat .. versionadded:: 0.8 @@ -295,6 +449,7 @@ Serialization Formats :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` , :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization` and :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`. @@ -303,12 +458,31 @@ Serialization Formats Frequently known as PKCS#1 format. Still a widely used format, but generally considered legacy. + A PEM encoded RSA key will look like:: + + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + .. attribute:: PKCS8 A more modern format for serializing keys which allows for better encryption. Choose this unless you have explicit legacy compatibility requirements. + A PEM encoded key will look like:: + + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + .. class:: PublicFormat .. versionadded:: 0.8 @@ -318,6 +492,7 @@ Serialization Formats :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` , :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKeyWithSerialization` , and :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`. @@ -327,38 +502,116 @@ Serialization Formats identifier and the public key as a bit string. Choose this unless you have specific needs. + A PEM encoded key will look like:: + + -----BEGIN PUBLIC KEY----- + ... + -----END PUBLIC KEY----- + .. attribute:: PKCS1 Just the public key elements (without the algorithm identifier). This format is RSA only, but is used by some older systems. + A PEM encoded key will look like:: + + -----BEGIN RSA PUBLIC KEY----- + ... + -----END RSA PUBLIC KEY----- + + .. attribute:: OpenSSH + + .. versionadded:: 1.4 + + The public key format used by OpenSSH (e.g. as found in + ``~/.ssh/id_rsa.pub`` or ``~/.ssh/authorized_keys``). + + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + + .. attribute:: CompressedPoint + + .. versionadded:: 2.5 + + A compressed elliptic curve public key as defined in ANSI X9.62 section + 4.3.6 (as well as `SEC 1 v2.0`_). + + .. attribute:: UncompressedPoint + + .. versionadded:: 2.5 + + An uncompressed elliptic curve public key as defined in ANSI X9.62 + section 4.3.6 (as well as `SEC 1 v2.0`_). + +.. class:: ParameterFormat + + .. versionadded:: 2.0 + + An enumeration for parameters formats. Used with the ``parameter_bytes`` + method available on + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParametersWithSerialization`. + + .. attribute:: PKCS3 + + ASN1 DH parameters sequence as defined in `PKCS3`_. + Serialization Encodings ~~~~~~~~~~~~~~~~~~~~~~~ .. class:: Encoding - .. versionadded:: 0.8 - An enumeration for encoding types. Used with the ``private_bytes`` method available on :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` , :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`, and - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey` as well as ``public_bytes`` on - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, and - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PublicKey`. .. attribute:: PEM + .. versionadded:: 0.8 + For PEM format. This is a base64 format with delimiters. .. attribute:: DER + .. versionadded:: 0.9 + For DER format. This is a binary format. + .. attribute:: OpenSSH + + .. versionadded:: 1.4 + + The format used by OpenSSH public keys. This is a text format. + + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + + .. attribute:: X962 + + .. versionadded:: 2.5 + + The format used by elliptic curve point encodings. This is a binary + format. + Serialization Encryption Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -370,6 +623,7 @@ Serialization Encryption Types :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` , :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization` and :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`. All other classes in this section represent the available choices for @@ -387,3 +641,7 @@ Serialization Encryption Types .. class:: NoEncryption Do not encrypt. + + +.. _`PKCS3`: https://www.teletrust.de/fileadmin/files/oid/oid_pkcs-3v1-4.pdf +.. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf diff --git a/docs/hazmat/primitives/asymmetric/utils.rst b/docs/hazmat/primitives/asymmetric/utils.rst index 7380f0b5..f46acb2e 100644 --- a/docs/hazmat/primitives/asymmetric/utils.rst +++ b/docs/hazmat/primitives/asymmetric/utils.rst @@ -6,10 +6,11 @@ Asymmetric Utilities .. currentmodule:: cryptography.hazmat.primitives.asymmetric.utils -.. function:: decode_rfc6979_signature(signature) +.. function:: decode_dss_signature(signature) - Takes in :rfc:`6979` signatures generated by the DSA/ECDSA signers and - returns a tuple ``(r, s)``. + Takes in signatures generated by the DSA/ECDSA signers and returns a + tuple ``(r, s)``. These signatures are ASN.1 encoded ``Dss-Sig-Value`` + sequences (as defined in :rfc:`3279`) :param bytes signature: The signature to decode. @@ -17,12 +18,71 @@ Asymmetric Utilities :raises ValueError: Raised if the signature is malformed. -.. function:: encode_rfc6979_signature(r, s) +.. function:: encode_dss_signature(r, s) - Creates an :rfc:`6979` byte string from raw signature values. + Creates an ASN.1 encoded ``Dss-Sig-Value`` (as defined in :rfc:`3279`) from + raw ``r`` and ``s`` values. :param int r: The raw signature value ``r``. :param int s: The raw signature value ``s``. :return bytes: The encoded signature. + +.. class:: Prehashed(algorithm) + + .. versionadded:: 1.6 + + ``Prehashed`` can be passed as the ``algorithm`` in the RSA + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.sign` + and + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.verify` + as well as DSA + :meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey.sign` + and + :meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey.verify` + methods. + + For elliptic curves it can be passed as the ``algorithm`` in + :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA` and then used + with + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.sign` + and + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.verify` + . + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + + .. doctest:: + + >>> import hashlib + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric import ( + ... padding, rsa, utils + ... ) + >>> private_key = rsa.generate_private_key( + ... public_exponent=65537, + ... key_size=2048, + ... backend=default_backend() + ... ) + >>> prehashed_msg = hashlib.sha256(b"A message I want to sign").digest() + >>> signature = private_key.sign( + ... prehashed_msg, + ... padding.PSS( + ... mgf=padding.MGF1(hashes.SHA256()), + ... salt_length=padding.PSS.MAX_LENGTH + ... ), + ... utils.Prehashed(hashes.SHA256()) + ... ) + >>> public_key = private_key.public_key() + >>> public_key.verify( + ... signature, + ... prehashed_msg, + ... padding.PSS( + ... mgf=padding.MGF1(hashes.SHA256()), + ... salt_length=padding.PSS.MAX_LENGTH + ... ), + ... utils.Prehashed(hashes.SHA256()) + ... ) diff --git a/docs/hazmat/primitives/asymmetric/x25519.rst b/docs/hazmat/primitives/asymmetric/x25519.rst new file mode 100644 index 00000000..ea01fbaa --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/x25519.rst @@ -0,0 +1,184 @@ +.. hazmat:: + +X25519 key exchange +=================== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.x25519 + + +X25519 is an elliptic curve `Diffie-Hellman key exchange`_ using `Curve25519`_. +It 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. + +.. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> private_key = X25519PrivateKey.generate() + >>> # 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 = X25519PrivateKey.generate().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', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # For the next handshake we MUST generate another private key. + >>> private_key_2 = X25519PrivateKey.generate() + >>> peer_public_key_2 = X25519PrivateKey.generate().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', + ... backend=default_backend() + ... ).derive(shared_key_2) + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: X25519PrivateKey + + .. versionadded:: 2.0 + + .. classmethod:: generate() + + Generate an X25519 private key. + + :returns: :class:`X25519PrivateKey` + + .. classmethod:: from_private_bytes(data) + + .. versionadded:: 2.5 + + A class method for loading an X25519 key encoded as + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`. + + :param bytes data: 32 byte private key. + + :returns: :class:`X25519PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x25519 + >>> private_key = x25519.X25519PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = x25519.X25519PrivateKey.from_private_bytes(private_bytes) + + .. method:: public_key() + + :returns: :class:`X25519PublicKey` + + .. method:: exchange(peer_public_key) + + :param X25519PublicKey peer_public_key: The public key for the + peer. + + :returns bytes: A shared key. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + .. versionadded:: 2.5 + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: X25519PublicKey + + .. versionadded:: 2.0 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 32 byte public key. + + :returns: :class:`X25519PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import x25519 + >>> private_key = x25519.X25519PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = x25519.X25519PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + +.. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange +.. _`Curve25519`: https://en.wikipedia.org/wiki/Curve25519 diff --git a/docs/hazmat/primitives/asymmetric/x448.rst b/docs/hazmat/primitives/asymmetric/x448.rst new file mode 100644 index 00000000..4e1f0421 --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/x448.rst @@ -0,0 +1,179 @@ +.. hazmat:: + +X448 key exchange +=================== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.x448 + + +X448 is an elliptic curve `Diffie-Hellman key exchange`_ using `Curve448`_. +It 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. + +.. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric.x448 import X448PrivateKey + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> private_key = X448PrivateKey.generate() + >>> # 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 = X448PrivateKey.generate().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', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # For the next handshake we MUST generate another private key. + >>> private_key_2 = X448PrivateKey.generate() + >>> peer_public_key_2 = X448PrivateKey.generate().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', + ... backend=default_backend() + ... ).derive(shared_key_2) + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: X448PrivateKey + + .. versionadded:: 2.5 + + .. classmethod:: generate() + + Generate an X448 private key. + + :returns: :class:`X448PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 56 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`X448PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x448 + >>> private_key = x448.X448PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = x448.X448PrivateKey.from_private_bytes(private_bytes) + + .. method:: public_key() + + :returns: :class:`X448PublicKey` + + .. method:: exchange(peer_public_key) + + :param X448PublicKey peer_public_key: The public key for the + peer. + + :returns bytes: A shared key. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: X448PublicKey + + .. versionadded:: 2.5 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 56 byte public key. + + :returns: :class:`X448PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x448 + >>> private_key = x448.X448PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = x448.X448PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) 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. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + +.. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange +.. _`Curve448`: https://en.wikipedia.org/wiki/Curve448 |
