diff options
Diffstat (limited to 'docs/hazmat')
34 files changed, 4055 insertions, 1110 deletions
diff --git a/docs/hazmat/backends/commoncrypto.rst b/docs/hazmat/backends/commoncrypto.rst deleted file mode 100644 index ddaf97e5..00000000 --- a/docs/hazmat/backends/commoncrypto.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. hazmat:: - -CommonCrypto backend -==================== - -The `CommonCrypto`_ C library provided by Apple on OS X and iOS. The -CommonCrypto backend is only supported on OS X versions 10.8 and above. - -.. currentmodule:: cryptography.hazmat.backends.commoncrypto.backend - -.. versionadded:: 0.2 - -.. data:: cryptography.hazmat.backends.commoncrypto.backend - - This is the exposed API for the CommonCrypto backend. - - It implements the following interfaces: - - * :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` - * :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - * :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - * :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend` - - It has one additional public attribute. - - .. attribute:: name - - The string name of this backend: ``"commoncrypto"`` - -.. _`CommonCrypto`: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/Common%20Crypto.3cc.html diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst index aec7a1e0..a8a1ff30 100644 --- a/docs/hazmat/backends/index.rst +++ b/docs/hazmat/backends/index.rst @@ -8,15 +8,11 @@ Getting a backend .. currentmodule:: cryptography.hazmat.backends -``cryptography`` aims to support multiple backends to ensure it can provide -the widest number of supported cryptographic algorithms as well as supporting -platform specific implementations. +``cryptography`` was originally designed to support multiple backends, but +this design has been deprecated. You can get the default backend by calling :func:`~default_backend`. -The default backend will change over time as we implement new backends and -the libraries we use in those backends changes. - .. function:: default_backend() @@ -31,6 +27,4 @@ Individual backends :maxdepth: 1 openssl - commoncrypto - multibackend interfaces diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index fb3786c3..36dd3a7a 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -22,18 +22,17 @@ A specific ``backend`` may provide one or more of these interfaces. The following backends implement this interface: * :doc:`/hazmat/backends/openssl` - * :doc:`/hazmat/backends/commoncrypto` .. method:: cipher_supported(cipher, mode) Check if a ``cipher`` and ``mode`` combination is supported by this backend. - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode` provider. + :param cipher: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm`. + + :param mode: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode`. :returns: ``True`` if the specified ``cipher`` and ``mode`` combination is supported by this backend, otherwise ``False`` @@ -46,11 +45,11 @@ A specific ``backend`` may provide one or more of these interfaces. can be used for encrypting data with the symmetric ``cipher`` using the given ``mode``. - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode` provider. + :param cipher: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm`. + + :param mode: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode`. :returns: :class:`~cryptography.hazmat.primitives.ciphers.CipherContext` @@ -65,11 +64,11 @@ A specific ``backend`` may provide one or more of these interfaces. can be used for decrypting data with the symmetric ``cipher`` using the given ``mode``. - :param cipher: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` - provider. - :param mode: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode` provider. + :param cipher: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm`. + + :param mode: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode`. :returns: :class:`~cryptography.hazmat.primitives.ciphers.CipherContext` @@ -84,15 +83,13 @@ A specific ``backend`` may provide one or more of these interfaces. The following backends implement this interface: * :doc:`/hazmat/backends/openssl` - * :doc:`/hazmat/backends/commoncrypto` .. method:: hash_supported(algorithm) Check if the specified ``algorithm`` is supported by this backend. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :returns: ``True`` if the specified ``algorithm`` is supported by this backend, otherwise ``False``. @@ -104,9 +101,8 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.hashes.HashContext` that uses the specified ``algorithm`` to calculate a message digest. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :returns: :class:`~cryptography.hazmat.primitives.hashes.HashContext` @@ -120,29 +116,28 @@ A specific ``backend`` may provide one or more of these interfaces. The following backends implement this interface: * :doc:`/hazmat/backends/openssl` - * :doc:`/hazmat/backends/commoncrypto` .. method:: hmac_supported(algorithm) Check if the specified ``algorithm`` is supported by this backend. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :returns: ``True`` if the specified ``algorithm`` is supported for HMAC by this backend, otherwise ``False``. - .. method:: create_hmac_ctx(algorithm) + .. method:: create_hmac_ctx(key, algorithm) Create a :class:`~cryptography.hazmat.primitives.hashes.HashContext` that uses the specified ``algorithm`` to calculate a hash-based message authentication code. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param bytes key: Secret key as ``bytes``. + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :returns: :class:`~cryptography.hazmat.primitives.hashes.HashContext` @@ -156,23 +151,21 @@ A specific ``backend`` may provide one or more of these interfaces. .. method:: cmac_algorithm_supported(algorithm) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. + :return: Returns True if the block cipher is supported for CMAC by this backend .. method:: create_cmac_ctx(algorithm) Create a - :class:`~cryptography.hazmat.primitives.interfaces.MACContext` that + context that uses the specified ``algorithm`` to calculate a message authentication code. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. - :returns: - :class:`~cryptography.hazmat.primitives.interfaces.MACContext` + :returns: CMAC object. .. class:: PBKDF2HMACBackend @@ -184,24 +177,21 @@ A specific ``backend`` may provide one or more of these interfaces. The following backends implement this interface: * :doc:`/hazmat/backends/openssl` - * :doc:`/hazmat/backends/commoncrypto` .. method:: pbkdf2_hmac_supported(algorithm) Check if the specified ``algorithm`` is supported by this backend. - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :returns: ``True`` if the specified ``algorithm`` is supported for PBKDF2 HMAC by this backend, otherwise ``False``. .. method:: derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, key_material) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :param int length: The desired length of the derived key. Maximum is (2\ :sup:`32` - 1) * ``algorithm.digest_size`` @@ -233,9 +223,8 @@ A specific ``backend`` may provide one or more of these interfaces. :param int key_size: The length in bits of the modulus. Should be at least 2048. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`. :raises ValueError: If the public_exponent is not valid. @@ -243,9 +232,8 @@ A specific ``backend`` may provide one or more of these interfaces. Check if the specified ``padding`` is supported by the backend. - :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`. :returns: ``True`` if the specified ``padding`` is supported by this backend, otherwise ``False``. @@ -264,7 +252,7 @@ A specific ``backend`` may provide one or more of these interfaces. :param numbers: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`. - :returns: A provider of + :returns: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`. :raises ValueError: This is raised when the values of ``p``, ``q``, @@ -277,9 +265,9 @@ A specific ``backend`` may provide one or more of these interfaces. .. method:: load_rsa_public_numbers(numbers) :param numbers: An instance of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers`. - :returns: A provider of + :returns: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`. :raises ValueError: This is raised when the values of @@ -305,24 +293,19 @@ A specific ``backend`` may provide one or more of these interfaces. 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. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`. .. method:: generate_dsa_private_key(parameters) - :param parameters: A - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters` - provider. + :param parameters: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. :raises ValueError: This is raised if the key size is not one of 1024, - 2048, or 3072. It is also raised when OpenSSL is older than version - 1.0.0 and the key size is larger than 1024; older OpenSSL versions - do not support keys larger than 1024 bits. + 2048, or 3072. .. method:: generate_dsa_private_key_and_parameters(key_size) @@ -333,18 +316,16 @@ A specific ``backend`` may provide one or more of these interfaces. 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. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. :raises ValueError: This is raised if the key size is not supported by the backend. .. method:: dsa_hash_supported(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`. :returns: ``True`` if the specified ``algorithm`` is supported by this backend, otherwise ``False``. @@ -365,7 +346,7 @@ A specific ``backend`` may provide one or more of these interfaces. :param numbers: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`. - :returns: A provider of + :returns: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised @@ -376,7 +357,7 @@ A specific ``backend`` may provide one or more of these interfaces. :param numbers: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers`. - :returns: A provider of + :returns: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised @@ -387,7 +368,7 @@ A specific ``backend`` may provide one or more of these interfaces. :param numbers: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`. - :returns: A provider of + :returns: An instance of :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised @@ -400,49 +381,51 @@ A specific ``backend`` may provide one or more of these interfaces. .. method:: elliptic_curve_supported(curve) - :param curve: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` - provider. + :param curve: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. :returns: True if the elliptic curve is supported by this backend. .. method:: elliptic_curve_signature_algorithm_supported(signature_algorithm, curve) - :param signature_algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurveSignatureAlgorithm` - provider. + :param signature_algorithm: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurveSignatureAlgorithm`. - :param curve: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` - provider. + :param curve: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. :returns: True if the signature algorithm and curve are supported by this backend. .. method:: generate_elliptic_curve_private_key(curve) - :param curve: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` - provider. + :param curve: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. .. method:: load_elliptic_curve_private_numbers(numbers) - :param numbers: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers` - provider. + :param numbers: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers`. - :returns: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` - provider. + :returns: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`. .. method:: load_elliptic_curve_public_numbers(numbers) - :param numbers: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers` - provider. + :param numbers: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers`. + + :returns: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + + .. method:: derive_elliptic_curve_private_key(private_value, curve) - :returns: An instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` - provider. + :param private_value: A secret scalar value. + + :param curve: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. + + :returns: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`. .. class:: PEMSerializationBackend @@ -468,6 +451,15 @@ A specific ``backend`` may provide one or more of these interfaces. serialized data contains. :raises ValueError: If the data could not be deserialized. + .. method:: load_pem_parameters(data) + + .. versionadded:: 2.0 + + :param bytes data: PEM data to load. + :return: A new instance of the appropriate type of asymmetric + parameters the serialized data contains. + :raises ValueError: If the data could not be deserialized. + .. class:: DERSerializationBackend .. versionadded:: 0.8 @@ -492,6 +484,16 @@ A specific ``backend`` may provide one or more of these interfaces. serialized data contains. :raises ValueError: If the data could not be deserialized. + .. method:: load_der_parameters(data) + + .. versionadded:: 2.0 + + :param bytes data: DER data to load. + :return: A new instance of the appropriate type of asymmetric + parameters the serialized data contains. + :raises ValueError: If the data could not be deserialized. + + .. class:: X509Backend .. versionadded:: 0.7 @@ -547,9 +549,64 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that will be used to generate the request signature. - :returns: A new object with the - :class:`~cryptography.x509.CertificateSigningRequest` interface. + :returns: A new instance of + :class:`~cryptography.x509.CertificateSigningRequest`. + + .. method:: create_x509_certificate(builder, private_key, algorithm) + + .. versionadded:: 1.0 + + :param builder: An instance of + :class:`~cryptography.x509.CertificateBuilder`. + + :param private_key: The + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + that will be used to sign the certificate. + + :param algorithm: The + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + that will be used to generate the certificate signature. + + :returns: A new instance of :class:`~cryptography.x509.Certificate`. + + .. method:: create_x509_crl(builder, private_key, algorithm) + .. versionadded:: 1.2 + + :param builder: An instance of + :class:`~cryptography.x509.CertificateRevocationListBuilder`. + + :param private_key: The + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + that will be used to sign the CRL. + + :param algorithm: The + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + that will be used to generate the CRL signature. + + :returns: A new instance of + :class:`~cryptography.x509.CertificateRevocationList`. + + .. method:: create_x509_revoked_certificate(builder) + + .. versionadded:: 1.2 + + :param builder: An instance of RevokedCertificateBuilder. + + :returns: A new instance of + :class:`~cryptography.x509.RevokedCertificate`. + + .. method:: x509_name_bytes(name) + + .. versionadded:: 1.6 + + :param name: An instance of :class:`~cryptography.x509.Name`. + + :return bytes: The DER encoded bytes. .. class:: DHBackend @@ -557,33 +614,33 @@ A specific ``backend`` may provide one or more of these interfaces. A backend with methods for doing Diffie-Hellman key exchange. - .. method:: generate_dh_parameters(key_size) + .. method:: generate_dh_parameters(generator, key_size) + + :param int generator: The generator to use. Often 2 or 5. :param int key_size: The bit length of the prime modulus to generate. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. :raises ValueError: If ``key_size`` is not at least 512. .. method:: generate_dh_private_key(parameters) - :param parameters: A - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters` - provider. + :param parameters: An instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`. - .. method:: generate_dh_private_key_and_parameters(self, key_size) + .. method:: generate_dh_private_key_and_parameters(generator, key_size) + + :param int generator: The generator to use. Often 2 or 5. :param int key_size: The bit length of the prime modulus to generate. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`. :raises ValueError: If ``key_size`` is not at least 512. @@ -593,9 +650,8 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers` instance. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised when any backend specific criteria are not met. @@ -606,9 +662,8 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers` instance. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised when any backend specific criteria are not met. @@ -619,18 +674,56 @@ A specific ``backend`` may provide one or more of these interfaces. :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers` instance. - :return: A new instance of a - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters` - provider. + :return: A new instance of + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised when any backend specific criteria are not met. - .. method:: dh_parameters_supported(p, g) + .. method:: dh_parameters_supported(p, g, q=None) :param int p: The p value of the DH key. :param int g: The g value of the DH key. - :returns: ``True`` if the given values of ``p`` and ``g`` are supported - by this backend, otherwise ``False``. + :param int q: The q value of the DH key. + + :returns: ``True`` if the given values of ``p``, ``g`` and ``q`` + are supported by this backend, otherwise ``False``. + + .. versionadded:: 1.8 + + .. method:: dh_x942_serialization_supported() + + :returns: True if serialization of DH objects with + subgroup order (q) is supported by this backend. + + +.. class:: ScryptBackend + + .. versionadded:: 1.6 + + A backend with methods for using Scrypt. + + The following backends implement this interface: + + * :doc:`/hazmat/backends/openssl` + + .. method:: derive_scrypt(self, key_material, salt, length, n, r, p) + + :param bytes key_material: The key material to use as a basis for + the derived key. This is typically a password. + + :param bytes salt: A salt. + + :param int length: The desired length of the derived key. + + :param int n: CPU/Memory cost parameter. It must be larger than 1 and be a + power of 2. + + :param int r: Block size parameter. + + :param int p: Parallelization parameter. + + :return bytes: Derived key. + diff --git a/docs/hazmat/backends/multibackend.rst b/docs/hazmat/backends/multibackend.rst deleted file mode 100644 index 0aae04a7..00000000 --- a/docs/hazmat/backends/multibackend.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. hazmat:: - -MultiBackend -============ - -.. currentmodule:: cryptography.hazmat.backends.multibackend - -.. class:: MultiBackend(backends) - - .. versionadded:: 0.2 - - This class allows you to combine multiple backends into a single backend - that offers the combined features of all of its constituents. - - .. testsetup:: - - from cryptography import utils - from cryptography.exceptions import UnsupportedAlgorithm, _Reasons - from cryptography.hazmat.backends.interfaces import HashBackend - from cryptography.hazmat.backends.openssl.backend import backend as backend2 - - @utils.register_interface(HashBackend) - class DummyHashBackend(object): - def hash_supported(self, algorithm): - return False - - def create_hash_ctx(self, algorithm): - raise UnsupportedAlgorithm("", _Reasons.UNSUPPORTED_HASH) - - backend1 = DummyHashBackend() - - .. doctest:: - - >>> from cryptography.hazmat.backends.multibackend import MultiBackend - >>> from cryptography.hazmat.primitives import hashes - >>> backend1.hash_supported(hashes.SHA256()) - False - >>> backend2.hash_supported(hashes.SHA256()) - True - >>> multi_backend = MultiBackend([backend1, backend2]) - >>> multi_backend.hash_supported(hashes.SHA256()) - True - - :param backends: A ``list`` of backend objects. Backends are checked for - feature support in the order they appear in this list. diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 03ac5570..56121cb5 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -3,9 +3,8 @@ OpenSSL backend =============== -The `OpenSSL`_ C library. Cryptography supports version ``0.9.8e`` (present in -Red Hat Enterprise Linux 5) and greater. Earlier versions may work but are -**not tested or supported**. +The `OpenSSL`_ C library. Cryptography supports OpenSSL version 1.0.2 and +greater. .. data:: cryptography.hazmat.backends.openssl.backend @@ -16,6 +15,7 @@ Red Hat Enterprise Linux 5) and greater. Earlier versions may work but are * :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` * :class:`~cryptography.hazmat.backends.interfaces.CMACBackend` * :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend` + * :class:`~cryptography.hazmat.backends.interfaces.DHBackend` * :class:`~cryptography.hazmat.backends.interfaces.DSABackend` * :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` * :class:`~cryptography.hazmat.backends.interfaces.HashBackend` @@ -25,17 +25,42 @@ Red Hat Enterprise Linux 5) and greater. Earlier versions may work but are * :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend` * :class:`~cryptography.hazmat.backends.interfaces.X509Backend` + It also implements the following interface for OpenSSL versions ``1.1.0`` + and above. + + * :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend` + It also exposes the following: .. attribute:: name The string name of this backend: ``"openssl"`` + .. method:: openssl_version_text() + + :return text: The friendly string name of the loaded OpenSSL library. + This is not necessarily the same version as it was compiled against. + + .. method:: openssl_version_number() + + .. versionadded:: 1.8 + + :return int: The integer version of the loaded OpenSSL library. This is + defined in ``opensslv.h`` as ``OPENSSL_VERSION_NUMBER`` and is + typically shown in hexadecimal (e.g. ``0x1010003f``). This is + not necessarily the same version as it was compiled against. + .. method:: activate_osrandom_engine() Activates the OS random engine. This will effectively disable OpenSSL's default CSPRNG. + .. method:: osrandom_engine_implementation() + + .. versionadded:: 1.7 + + Returns the implementation of OS random engine. + .. method:: activate_builtin_random() This will activate the default OpenSSL CSPRNG. @@ -43,7 +68,7 @@ Red Hat Enterprise Linux 5) and greater. Earlier versions may work but are OS random engine ---------------- -OpenSSL uses a user-space CSPRNG that is seeded from system random ( +By default OpenSSL uses a user-space CSPRNG that is seeded from system random ( ``/dev/urandom`` or ``CryptGenRandom``). This CSPRNG is not reseeded automatically when a process calls ``fork()``. This can result in situations where two different processes can return similar or identical keys and @@ -67,8 +92,9 @@ When importing only the binding it is added to the engine list but OS random sources ----------------- -On OS X and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random`` and -utilizes the `Yarrow`_ algorithm. +On macOS and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random``. The +implementation on macOS uses the `Yarrow`_ algorithm. FreeBSD uses the +`Fortuna`_ algorithm. On Windows the implementation of ``CryptGenRandom`` depends on which version of the operation system you are using. See the `Microsoft documentation`_ for more @@ -77,8 +103,24 @@ details. Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source seeded from the same pool as ``/dev/random``. ++------------------------------------------+------------------------------+ +| Windows | ``CryptGenRandom()`` | ++------------------------------------------+------------------------------+ +| Linux >= 3.17 with working | ``getrandom()`` | +| ``SYS_getrandom`` syscall | | ++------------------------------------------+------------------------------+ +| OpenBSD >= 5.6 | ``getentropy()`` | ++------------------------------------------+------------------------------+ +| BSD family (including macOS 10.12+) with | ``getentropy()`` | +| ``SYS_getentropy`` in ``sys/syscall.h`` | | ++------------------------------------------+------------------------------+ +| fallback | ``/dev/urandom`` with | +| | cached file descriptor | ++------------------------------------------+------------------------------+ + .. _`OpenSSL`: https://www.openssl.org/ .. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_private_keys_.28Debian-specific.29 +.. _`Fortuna`: https://en.wikipedia.org/wiki/Fortuna_(PRNG) .. _`Yarrow`: https://en.wikipedia.org/wiki/Yarrow_algorithm -.. _`Microsoft documentation`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx +.. _`Microsoft documentation`: https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom diff --git a/docs/hazmat/bindings/commoncrypto.rst b/docs/hazmat/bindings/commoncrypto.rst deleted file mode 100644 index 4f58a6d3..00000000 --- a/docs/hazmat/bindings/commoncrypto.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. hazmat:: - -CommonCrypto binding -==================== - -.. currentmodule:: cryptography.hazmat.bindings.commoncrypto.binding - -.. versionadded:: 0.2 - -These are `CFFI`_ bindings to the `CommonCrypto`_ C library. It is only -available on Mac OS X versions 10.8 and above. - -.. class:: cryptography.hazmat.bindings.commoncrypto.binding.Binding() - - This is the exposed API for the CommonCrypto bindings. It has two public - attributes: - - .. attribute:: ffi - - This is a ``cffi.FFI`` instance. It can be used to allocate and - otherwise manipulate CommonCrypto structures. - - .. attribute:: lib - - This is a ``cffi`` library. It can be used to call CommonCrypto - functions, and access constants. - - -.. _`CFFI`: https://cffi.readthedocs.org/ -.. _`CommonCrypto`: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/Common%20Crypto.3cc.html diff --git a/docs/hazmat/bindings/index.rst b/docs/hazmat/bindings/index.rst index 8075be14..655f4620 100644 --- a/docs/hazmat/bindings/index.rst +++ b/docs/hazmat/bindings/index.rst @@ -20,4 +20,3 @@ Individual bindings :maxdepth: 1 openssl - commoncrypto diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst index 446c450c..bc7ec2d9 100644 --- a/docs/hazmat/bindings/openssl.rst +++ b/docs/hazmat/bindings/openssl.rst @@ -6,8 +6,7 @@ OpenSSL binding .. currentmodule:: cryptography.hazmat.bindings.openssl.binding These are `CFFI`_ bindings to the `OpenSSL`_ C library. Cryptography supports -version ``0.9.8e`` (present in Red Hat Enterprise Linux 5) and greater. Earlier -versions may work but are **not tested or supported**. +OpenSSL version 1.0.2 and greater. .. class:: cryptography.hazmat.bindings.openssl.binding.Binding() @@ -34,16 +33,15 @@ versions may work but are **not tested or supported**. Threading --------- -``cryptography`` enables OpenSSLs `thread safety facilities`_ in two different -ways depending on the configuration of your system. Normally the locking -callbacks provided by your Python implementation specifically for OpenSSL will -be used. However if you have linked ``cryptography`` to a different version of -OpenSSL than that used by your Python implementation we enable an alternative -locking callback. This version is implemented in Python and so may result in -lower performance in some situations. In particular parallelism is reduced -because it has to acquire the GIL whenever any lock operations occur within -OpenSSL. - -.. _`CFFI`: https://cffi.readthedocs.org/ +``cryptography`` enables OpenSSLs `thread safety facilities`_ in several +different ways depending on the configuration of your system. For users on +OpenSSL 1.1.0 or newer (including anyone who uses a binary wheel) the OpenSSL +internal locking callbacks are automatically used. Otherwise, we first attempt +to use the callbacks provided by your Python implementation specifically for +OpenSSL. This will work in every case except where ``cryptography`` is linked +against a different version of OpenSSL than the one used by your Python +implementation. For this final case we have a C-based locking callback. + +.. _`CFFI`: https://cffi.readthedocs.io .. _`OpenSSL`: https://www.openssl.org/ -.. _`thread safety facilities`: https://www.openssl.org/docs/crypto/threads.html +.. _`thread safety facilities`: https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_THREADID_set_callback.html diff --git a/docs/hazmat/primitives/aead.rst b/docs/hazmat/primitives/aead.rst new file mode 100644 index 00000000..d318367b --- /dev/null +++ b/docs/hazmat/primitives/aead.rst @@ -0,0 +1,248 @@ +.. hazmat:: + + +Authenticated encryption +======================== + +.. module:: cryptography.hazmat.primitives.ciphers.aead + +Authenticated encryption with associated data (AEAD) are encryption schemes +which provide both confidentiality and integrity for their ciphertext. They +also support providing integrity for associated data which is not encrypted. + +.. class:: ChaCha20Poly1305(key) + + .. versionadded:: 2.0 + + The ChaCha20Poly1305 construction is defined in :rfc:`7539` section 2.8. + It is a stream cipher combined with a MAC that offers strong integrity + guarantees. + + :param key: A 32-byte key. This **must** be kept secret. + :type key: :term:`bytes-like` + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of + OpenSSL does not support ChaCha20Poly1305. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 + >>> data = b"a secret message" + >>> aad = b"authenticated but unencrypted data" + >>> key = ChaCha20Poly1305.generate_key() + >>> chacha = ChaCha20Poly1305(key) + >>> nonce = os.urandom(12) + >>> ct = chacha.encrypt(nonce, data, aad) + >>> chacha.decrypt(nonce, ct, aad) + b'a secret message' + + .. classmethod:: generate_key() + + Securely generates a random ChaCha20Poly1305 key. + + :returns bytes: A 32 byte key. + + .. method:: encrypt(nonce, data, associated_data) + + .. warning:: + + Reuse of a ``nonce`` with a given ``key`` compromises the security + of any message with that ``nonce`` and ``key`` pair. + + Encrypts the ``data`` provided and authenticates the + ``associated_data``. The output of this can be passed directly + to the ``decrypt`` method. + + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to encrypt. + :param bytes associated_data: Additional data that should be + authenticated with the key, but does not need to be encrypted. Can + be ``None``. + :returns bytes: The ciphertext bytes with the 16 byte tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. + + .. method:: decrypt(nonce, data, associated_data) + + Decrypts the ``data`` and authenticates the ``associated_data``. If you + called encrypt with ``associated_data`` you must pass the same + ``associated_data`` in decrypt or the integrity check will fail. + + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a + key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to decrypt (with tag appended). + :param bytes associated_data: Additional data to authenticate. Can be + ``None`` if none was passed during encryption. + :returns bytes: The original plaintext. + :raises cryptography.exceptions.InvalidTag: If the authentication tag + doesn't validate this exception will be raised. This will occur + when the ciphertext has been changed, but will also occur when the + key, nonce, or associated data are wrong. + +.. class:: AESGCM(key) + + .. versionadded:: 2.0 + + The AES-GCM construction is composed of the + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block + cipher utilizing Galois Counter Mode (GCM). + + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives.ciphers.aead import AESGCM + >>> data = b"a secret message" + >>> aad = b"authenticated but unencrypted data" + >>> key = AESGCM.generate_key(bit_length=128) + >>> aesgcm = AESGCM(key) + >>> nonce = os.urandom(12) + >>> ct = aesgcm.encrypt(nonce, data, aad) + >>> aesgcm.decrypt(nonce, ct, aad) + b'a secret message' + + .. classmethod:: generate_key(bit_length) + + Securely generates a random AES-GCM key. + + :param bit_length: The bit length of the key to generate. Must be + 128, 192, or 256. + + :returns bytes: The generated key. + + .. method:: encrypt(nonce, data, associated_data) + + .. warning:: + + Reuse of a ``nonce`` with a given ``key`` compromises the security + of any message with that ``nonce`` and ``key`` pair. + + Encrypts and authenticates the ``data`` provided as well as + authenticating the ``associated_data``. The output of this can be + passed directly to the ``decrypt`` method. + + :param nonce: NIST `recommends a 96-bit IV length`_ for best + performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. + **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to encrypt. + :param bytes associated_data: Additional data that should be + authenticated with the key, but is not encrypted. Can be ``None``. + :returns bytes: The ciphertext bytes with the 16 byte tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. + + .. method:: decrypt(nonce, data, associated_data) + + Decrypts the ``data`` and authenticates the ``associated_data``. If you + called encrypt with ``associated_data`` you must pass the same + ``associated_data`` in decrypt or the integrity check will fail. + + :param nonce: NIST `recommends a 96-bit IV length`_ for best + performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. + **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to decrypt (with tag appended). + :param bytes associated_data: Additional data to authenticate. Can be + ``None`` if none was passed during encryption. + :returns bytes: The original plaintext. + :raises cryptography.exceptions.InvalidTag: If the authentication tag + doesn't validate this exception will be raised. This will occur + when the ciphertext has been changed, but will also occur when the + key, nonce, or associated data are wrong. + +.. class:: AESCCM(key, tag_length=16) + + .. versionadded:: 2.0 + + .. note: + + AES-CCM is provided largely for compatibility with existing protocols. + Due to its construction it is not as computationally efficient as + other AEAD ciphers. + + The AES-CCM construction is composed of the + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block + cipher utilizing Counter with CBC-MAC (CCM) (specified in :rfc:`3610`). + + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` + :param int tag_length: The length of the authentication tag. This + defaults to 16 bytes and it is **strongly** recommended that you + do not make it shorter unless absolutely necessary. Valid tag + lengths are 4, 6, 8, 10, 12, 14, and 16. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of + OpenSSL does not support AES-CCM. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives.ciphers.aead import AESCCM + >>> data = b"a secret message" + >>> aad = b"authenticated but unencrypted data" + >>> key = AESCCM.generate_key(bit_length=128) + >>> aesccm = AESCCM(key) + >>> nonce = os.urandom(13) + >>> ct = aesccm.encrypt(nonce, data, aad) + >>> aesccm.decrypt(nonce, ct, aad) + b'a secret message' + + .. classmethod:: generate_key(bit_length) + + Securely generates a random AES-CCM key. + + :param bit_length: The bit length of the key to generate. Must be + 128, 192, or 256. + + :returns bytes: The generated key. + + .. method:: encrypt(nonce, data, associated_data) + + .. warning:: + + Reuse of a ``nonce`` with a given ``key`` compromises the security + of any message with that ``nonce`` and ``key`` pair. + + Encrypts and authenticates the ``data`` provided as well as + authenticating the ``associated_data``. The output of this can be + passed directly to the ``decrypt`` method. + + :param nonce: A value of between 7 and 13 bytes. The maximum + length is determined by the length of the ciphertext you are + encrypting and must satisfy the condition: + ``len(data) < 2 ** (8 * (15 - len(nonce)))`` + **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to encrypt. + :param bytes associated_data: Additional data that should be + authenticated with the key, but is not encrypted. Can be ``None``. + :returns bytes: The ciphertext bytes with the tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. + + .. method:: decrypt(nonce, data, associated_data) + + Decrypts the ``data`` and authenticates the ``associated_data``. If you + called encrypt with ``associated_data`` you must pass the same + ``associated_data`` in decrypt or the integrity check will fail. + + :param nonce: A value of between 7 and 13 bytes. This + is the same value used when you originally called encrypt. + **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` + :param bytes data: The data to decrypt (with tag appended). + :param bytes associated_data: Additional data to authenticate. Can be + ``None`` if none was passed during encryption. + :returns bytes: The original plaintext. + :raises cryptography.exceptions.InvalidTag: If the authentication tag + doesn't validate this exception will be raised. This will occur + when the ciphertext has been changed, but will also occur when the + key, nonce, or associated data are wrong. + +.. _`recommends a 96-bit IV length`: https://csrc.nist.gov/publications/detail/sp/800-38d/final 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 diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst index 1394b6b3..1c1d544f 100644 --- a/docs/hazmat/primitives/constant-time.rst +++ b/docs/hazmat/primitives/constant-time.rst @@ -40,4 +40,4 @@ about the timing attacks on KeyCzar and Java's ``MessageDigest.isEqual()``. ``bytes``. -.. _`Coda Hale's blog post`: http://codahale.com/a-lesson-in-timing-attacks/ +.. _`Coda Hale's blog post`: https://codahale.com/a-lesson-in-timing-attacks/ diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index 49288326..24cc70b5 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -1,7 +1,7 @@ .. hazmat:: -Message digests -=============== +Message digests (Hashing) +========================= .. module:: cryptography.hazmat.primitives.hashes @@ -26,7 +26,7 @@ Message digests >>> digest.update(b"abc") >>> digest.update(b"123") >>> digest.finalize() - 'l\xa1=R\xcap\xc8\x83\xe0\xf0\xbb\x10\x1eBZ\x89\xe8bM\xe5\x1d\xb2\xd29%\x93\xafj\x84\x11\x80\x90' + b'l\xa1=R\xcap\xc8\x83\xe0\xf0\xbb\x10\x1eBZ\x89\xe8bM\xe5\x1d\xb2\xd29%\x93\xafj\x84\x11\x80\x90' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be @@ -40,11 +40,11 @@ Message digests :param algorithm: A :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider such as those described in + instance such as those described in :ref:`below <cryptographic-hash-algorithms>`. :param backend: A :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - provider. + instance. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -79,19 +79,6 @@ Message digests .. _cryptographic-hash-algorithms: -SHA-1 -~~~~~ - -.. attention:: - - NIST has deprecated SHA-1 in favor of the SHA-2 variants. New applications - are strongly suggested to use SHA-2 over SHA-1. - -.. class:: SHA1() - - SHA-1 is a cryptographic hash function standardized by NIST. It produces an - 160-bit message digest. - SHA-2 family ~~~~~~~~~~~~ @@ -115,21 +102,134 @@ SHA-2 family SHA-512 is a cryptographic hash function from the SHA-2 family and is standardized by NIST. It produces a 512-bit message digest. -RIPEMD160 -~~~~~~~~~ +.. class:: SHA512_224() + + .. versionadded:: 2.5 + + SHA-512/224 is a cryptographic hash function from the SHA-2 family and is + standardized by NIST. It produces a 224-bit message digest. + +.. class:: SHA512_256() + + .. versionadded:: 2.5 + + SHA-512/256 is a cryptographic hash function from the SHA-2 family and is + standardized by NIST. It produces a 256-bit message digest. + +BLAKE2 +~~~~~~ + +`BLAKE2`_ is a cryptographic hash function specified in :rfc:`7693`. BLAKE2's +design makes it immune to `length-extension attacks`_, an advantage over the +SHA-family of hashes. + +.. note:: + + While the RFC specifies keying, personalization, and salting features, + these are not supported at this time due to limitations in OpenSSL 1.1.0. + +.. class:: BLAKE2b(digest_size) + + BLAKE2b is optimized for 64-bit platforms and produces an 1 to 64-byte + message digest. + + :param int digest_size: The desired size of the hash output in bytes. Only + ``64`` is supported at this time. + + :raises ValueError: If the ``digest_size`` is invalid. + +.. class:: BLAKE2s(digest_size) + + BLAKE2s is optimized for 8 to 32-bit platforms and produces a + 1 to 32-byte message digest. + + :param int digest_size: The desired size of the hash output in bytes. Only + ``32`` is supported at this time. + + :raises ValueError: If the ``digest_size`` is invalid. + +SHA-3 family +~~~~~~~~~~~~ + +SHA-3 is the most recent NIST secure hash algorithm standard. Despite the +larger number SHA-3 is not considered to be better than SHA-2. Instead, it uses +a significantly different internal structure so that **if** an attack appears +against SHA-2 it is unlikely to apply to SHA-3. SHA-3 is significantly slower +than SHA-2 so at this time most users should choose SHA-2. + +.. class:: SHA3_224() + + .. versionadded:: 2.5 + + SHA3/224 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 224-bit message digest. + +.. class:: SHA3_256() + + .. versionadded:: 2.5 + + SHA3/256 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 256-bit message digest. + +.. class:: SHA3_384() + + .. versionadded:: 2.5 + + SHA3/384 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 384-bit message digest. + +.. class:: SHA3_512() + + .. versionadded:: 2.5 + + SHA3/512 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 512-bit message digest. + +.. class:: SHAKE128(digest_size) + + .. versionadded:: 2.5 + + SHAKE128 is an extendable output function (XOF) based on the same core + permutations as SHA3. It allows the caller to obtain an arbitrarily long + digest length. Longer lengths, however, do not increase security or + collision resistance and lengths shorter than 128 bit (16 bytes) will + decrease it. + + :param int digest_size: The length of output desired. Must be greater than + zero. -.. class:: RIPEMD160() + :raises ValueError: If the ``digest_size`` is invalid. - RIPEMD160 is a cryptographic hash function that is part of ISO/IEC - 10118-3:2004. It produces a 160-bit message digest. +.. class:: SHAKE256(digest_size) -Whirlpool -~~~~~~~~~ + .. versionadded:: 2.5 -.. class:: Whirlpool() + SHAKE256 is an extendable output function (XOF) based on the same core + permutations as SHA3. It allows the caller to obtain an arbitrarily long + digest length. Longer lengths, however, do not increase security or + collision resistance and lengths shorter than 256 bit (32 bytes) will + decrease it. - Whirlpool is a cryptographic hash function that is part of ISO/IEC - 10118-3:2004. It produces a 512-bit message digest. + :param int digest_size: The length of output desired. Must be greater than + zero. + + :raises ValueError: If the ``digest_size`` is invalid. + +SHA-1 +~~~~~ + +.. warning:: + + SHA-1 is a deprecated hash algorithm that has practical known collision + attacks. You are strongly discouraged from using it. Existing applications + should strongly consider moving away. + +.. class:: SHA1() + + SHA-1 is a cryptographic hash function standardized by NIST. It produces an + 160-bit message digest. Cryptanalysis of SHA-1 has demonstrated that it is + vulnerable to practical collision attacks, and collisions have been + demonstrated. MD5 ~~~ @@ -156,7 +256,7 @@ Interfaces :type: str The standard name for the hash algorithm, for example: ``"sha256"`` or - ``"whirlpool"``. + ``"blake2b"``. .. attribute:: digest_size @@ -164,12 +264,6 @@ Interfaces The size of the resulting digest in bytes. - .. attribute:: block_size - - :type: int - - The internal block size of the hash algorithm in bytes. - .. class:: HashContext @@ -190,4 +284,6 @@ Interfaces :return: A :class:`HashContext` that is a copy of the current context. -.. _`Lifetimes of cryptographic hash functions`: http://valerieaurora.org/hash.html +.. _`Lifetimes of cryptographic hash functions`: https://valerieaurora.org/hash.html +.. _`BLAKE2`: https://blake2.net +.. _`length-extension attacks`: https://en.wikipedia.org/wiki/Length_extension_attack diff --git a/docs/hazmat/primitives/index.rst b/docs/hazmat/primitives/index.rst index a9ab38a0..72e5b26c 100644 --- a/docs/hazmat/primitives/index.rst +++ b/docs/hazmat/primitives/index.rst @@ -6,12 +6,13 @@ Primitives .. toctree:: :maxdepth: 1 - cryptographic-hashes + aead + asymmetric/index + constant-time + key-derivation-functions + keywrap mac/index + cryptographic-hashes symmetric-encryption padding - key-derivation-functions - asymmetric/index - constant-time - interfaces twofactor diff --git a/docs/hazmat/primitives/interfaces.rst b/docs/hazmat/primitives/interfaces.rst deleted file mode 100644 index d60fe186..00000000 --- a/docs/hazmat/primitives/interfaces.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. hazmat:: - -.. module:: cryptography.hazmat.primitives.interfaces - -Interfaces -========== - - -``cryptography`` uses `Abstract Base Classes`_ as interfaces to describe the -properties and methods of most primitive constructs. Backends may also use -this information to influence their operation. Interfaces should also be used -to document argument and return types. - -.. _`Abstract Base Classes`: https://docs.python.org/3/library/abc.html - - -Asymmetric interfaces ---------------------- - -In 0.8 the asymmetric signature and verification interfaces were moved to the -:mod:`cryptography.hazmat.primitives.asymmetric` module. - -In 0.8 the asymmetric padding interface was moved to the -:mod:`cryptography.hazmat.primitives.asymmetric.padding` module. - -DSA -~~~ - -In 0.8 the DSA key interfaces were moved to the -:mod:`cryptography.hazmat.primitives.asymmetric.dsa` module. - - -RSA -~~~ - -In 0.8 the RSA key interfaces were moved to the -:mod:`cryptography.hazmat.primitives.asymmetric.rsa` module. - - -Elliptic Curve -~~~~~~~~~~~~~~ - -In 0.8 the EC key interfaces were moved to the -:mod:`cryptography.hazmat.primitives.asymmetric.ec` module. - - -Key derivation functions ------------------------- - -In 0.8 the key derivation function interface was moved to the -:mod:`cryptography.hazmat.primitives.kdf` module. - - -.. class:: MACContext - - .. versionadded:: 0.7 - - .. method:: update(data) - - :param bytes data: The data you want to authenticate. - - .. method:: finalize() - - :return: The message authentication code. - - .. method:: copy() - - :return: A - :class:`~cryptography.hazmat.primitives.interfaces.MACContext` that - is a copy of the current context. - - .. method:: verify(signature) - - :param bytes signature: The signature to verify. - - :raises cryptography.exceptions.InvalidSignature: This is raised when - the provided signature does not match the expected signature. - - -.. _`CMAC`: https://en.wikipedia.org/wiki/CMAC diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst index 35e2dd87..4b474124 100644 --- a/docs/hazmat/primitives/key-derivation-functions.rst +++ b/docs/hazmat/primitives/key-derivation-functions.rst @@ -34,7 +34,8 @@ Different KDFs are suitable for different tasks such as: `PBKDF2`_ (Password Based Key Derivation Function 2) is typically used for deriving a cryptographic key from a password. It may also be used for - key storage, but an alternate key storage KDF such as `scrypt`_ is generally + key storage, but an alternate key storage KDF such as + :class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt` is generally considered a better solution. This class conforms to the @@ -48,6 +49,7 @@ Different KDFs are suitable for different tasks such as: >>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC >>> from cryptography.hazmat.backends import default_backend >>> backend = default_backend() + >>> # Salts should be randomly generated >>> salt = os.urandom(16) >>> # derive >>> kdf = PBKDF2HMAC( @@ -68,21 +70,19 @@ Different KDFs are suitable for different tasks such as: ... ) >>> kdf.verify(b"my great password", key) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. - :param int length: The desired length of the derived key. Maximum is - (2\ :sup:`32` - 1) * ``algorithm.digest_size``. - :param bytes salt: A salt. `NIST SP 800-132`_ recommends 128-bits or - longer. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + :param int length: The desired length of the derived key in bytes. Maximum + is (2\ :sup:`32` - 1) * ``algorithm.digest_size``. + :param bytes salt: A salt. Secure values [#nist]_ are 128-bits (16 bytes) + or longer and randomly generated. :param int iterations: The number of iterations to perform of the hash function. This can be used to control the length of time the operation takes. Higher numbers help mitigate brute force attacks against derived - keys. See OWASP's `Password Storage Cheat Sheet`_ for more - detailed recommendations if you intend to use this for password storage. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend` - provider. + keys. A `more detailed description`_ can be consulted for additional + information. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -92,8 +92,9 @@ Different KDFs are suitable for different tasks such as: .. method:: derive(key_material) - :param bytes key_material: The input key material. For PBKDF2 this + :param key_material: The input key material. For PBKDF2 this should be a password. + :type key_material: :term:`bytes-like` :return bytes: the derived key. :raises cryptography.exceptions.AlreadyFinalized: This is raised when :meth:`derive` or @@ -168,12 +169,11 @@ Different KDFs are suitable for different tasks such as: ... ) >>> hkdf.verify(b"input key", key) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - :param int length: The desired length of the derived key. Maximum is - ``255 * (algorithm.digest_size // 8)``. + :param int length: The desired length of the derived key in bytes. Maximum + is ``255 * (algorithm.digest_size // 8)``. :param bytes salt: A salt. Randomizes the KDF's output. Optional, but highly recommended. Ideally as many bits of entropy as the security @@ -181,16 +181,15 @@ Different KDFs are suitable for different tasks such as: long as the hash output. Worse (shorter, less entropy) salt values can still meaningfully contribute to security. May be reused. Does not have to be secret, but may cause stronger security guarantees if secret; see - `RFC 5869`_ and the `HKDF paper`_ for more details. If ``None`` is + :rfc:`5869` and the `HKDF paper`_ for more details. If ``None`` is explicitly passed a default salt of ``algorithm.digest_size // 8`` null bytes will be used. :param bytes info: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -201,10 +200,16 @@ Different KDFs are suitable for different tasks such as: .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material by performing both the extract and expand operations. @@ -269,24 +274,21 @@ Different KDFs are suitable for different tasks such as: ... ) >>> hkdf.verify(key_material, key) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - :param int length: The desired length of the derived key. Maximum is - ``255 * (algorithm.digest_size // 8)``. + :param int length: The desired length of the derived key in bytes. Maximum + is ``255 * (algorithm.digest_size // 8)``. :param bytes info: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - :raises TypeError: This is raised if the provided ``info`` is a unicode object :raises TypeError: This exception is raised if ``info`` is not ``bytes``. .. method:: derive(key_material) @@ -294,10 +296,13 @@ Different KDFs are suitable for different tasks such as: :param bytes key_material: The input key material. :return bytes: The derived key. - :raises TypeError: This is raised if the provided ``key_material`` is - a unicode object :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material by performing both the extract and expand operations. @@ -318,7 +323,7 @@ Different KDFs are suitable for different tasks such as: called more than once. :raises TypeError: This is raised if the provided ``key_material`` is - a unicode object + a ``unicode`` object This checks whether deriving a new key from the supplied ``key_material`` generates the same key as the ``expected_key``, and @@ -348,22 +353,21 @@ Different KDFs are suitable for different tasks such as: >>> otherinfo = b"concatkdf-example" >>> ckdf = ConcatKDFHash( ... algorithm=hashes.SHA256(), - ... length=256, + ... length=32, ... otherinfo=otherinfo, ... backend=backend ... ) >>> key = ckdf.derive(b"input key") >>> ckdf = ConcatKDFHash( ... algorithm=hashes.SHA256(), - ... length=256, + ... length=32, ... otherinfo=otherinfo, ... backend=backend ... ) >>> ckdf.verify(b"input key", key) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :param int length: The desired length of the derived key in bytes. Maximum is ``hashlen * (2^32 -1)``. @@ -371,9 +375,8 @@ Different KDFs are suitable for different tasks such as: :param bytes otherinfo: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.HashBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -384,10 +387,16 @@ Different KDFs are suitable for different tasks such as: .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material. @@ -433,7 +442,7 @@ Different KDFs are suitable for different tasks such as: >>> otherinfo = b"concatkdf-example" >>> ckdf = ConcatKDFHMAC( ... algorithm=hashes.SHA256(), - ... length=256, + ... length=32, ... salt=salt, ... otherinfo=otherinfo, ... backend=backend @@ -441,16 +450,15 @@ Different KDFs are suitable for different tasks such as: >>> key = ckdf.derive(b"input key") >>> ckdf = ConcatKDFHMAC( ... algorithm=hashes.SHA256(), - ... length=256, + ... length=32, ... salt=salt, ... otherinfo=otherinfo, ... backend=backend ... ) >>> ckdf.verify(b"input key", key) - :param algorithm: An instance of a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. :param int length: The desired length of the derived key in bytes. Maximum is ``hashlen * (2^32 -1)``. @@ -466,9 +474,8 @@ Different KDFs are suitable for different tasks such as: :param bytes otherinfo: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: A - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -483,6 +490,241 @@ Different KDFs are suitable for different tasks such as: :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + Derives a new key from the input key material. + + .. method:: verify(key_material, expected_key) + + :param bytes key_material: The input key material. This is the same as + ``key_material`` in :meth:`derive`. + :param bytes expected_key: The expected result of deriving a new key, + this is the same as the return value of + :meth:`derive`. + :raises cryptography.exceptions.InvalidKey: This is raised when the + derived key does not match + the expected key. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + This checks whether deriving a new key from the supplied + ``key_material`` generates the same key as the ``expected_key``, and + raises an exception if they do not match. + +.. currentmodule:: cryptography.hazmat.primitives.kdf.x963kdf + +.. class:: X963KDF(algorithm, length, otherinfo, backend) + + .. versionadded:: 1.1 + + X963KDF (ANSI X9.63 Key Derivation Function) is defined by ANSI + in the `ANSI X9.63:2001`_ document, to be used to derive keys for use + after a Key Exchange negotiation operation. + + SECG in `SEC 1 v2.0`_ recommends that + :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHash` be + used for new projects. This KDF should only be used for backwards + compatibility with pre-existing protocols. + + + .. warning:: + + X963KDF should not be used for password storage. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF + >>> from cryptography.hazmat.backends import default_backend + >>> backend = default_backend() + >>> sharedinfo = b"ANSI X9.63 Example" + >>> xkdf = X963KDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... sharedinfo=sharedinfo, + ... backend=backend + ... ) + >>> key = xkdf.derive(b"input key") + >>> xkdf = X963KDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... sharedinfo=sharedinfo, + ... backend=backend + ... ) + >>> xkdf.verify(b"input key", key) + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + + :param int length: The desired length of the derived key in bytes. + Maximum is ``hashlen * (2^32 -1)``. + + :param bytes sharedinfo: Application specific context information. + If ``None`` is explicitly passed an empty byte string will be used. + + :param backend: A cryptography backend + :class:`~cryptography.hazmat.backends.interfaces.HashBackend` + instance. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised + if the provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.HashBackend` + + :raises TypeError: This exception is raised if ``sharedinfo`` is not + ``bytes``. + + .. method:: derive(key_material) + + :param key_material: The input key material. + :type key_material: :term:`bytes-like` + :return bytes: The derived key. + :raises TypeError: This exception is raised if ``key_material`` is + not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + Derives a new key from the input key material. + + .. method:: verify(key_material, expected_key) + + :param bytes key_material: The input key material. This is the same as + ``key_material`` in :meth:`derive`. + :param bytes expected_key: The expected result of deriving a new key, + this is the same as the return value of + :meth:`derive`. + :raises cryptography.exceptions.InvalidKey: This is raised when the + derived key does not match + the expected key. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + This checks whether deriving a new key from the supplied + ``key_material`` generates the same key as the ``expected_key``, and + raises an exception if they do not match. + + +.. currentmodule:: cryptography.hazmat.primitives.kdf.kbkdf + +.. class:: KBKDFHMAC(algorithm, mode, length, rlen, llen, location,\ + label, context, fixed, backend) + + .. versionadded:: 1.4 + + KBKDF (Key Based Key Derivation Function) is defined by the + `NIST SP 800-108`_ document, to be used to derive additional + keys from a key that has been established through an automated + key-establishment scheme. + + .. warning:: + + KBKDFHMAC should not be used for password storage. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.kdf.kbkdf import ( + ... CounterLocation, KBKDFHMAC, Mode + ... ) + >>> from cryptography.hazmat.backends import default_backend + >>> backend = default_backend() + >>> label = b"KBKDF HMAC Label" + >>> context = b"KBKDF HMAC Context" + >>> kdf = KBKDFHMAC( + ... algorithm=hashes.SHA256(), + ... mode=Mode.CounterMode, + ... length=32, + ... rlen=4, + ... llen=4, + ... location=CounterLocation.BeforeFixed, + ... label=label, + ... context=context, + ... fixed=None, + ... backend=backend + ... ) + >>> key = kdf.derive(b"input key") + >>> kdf = KBKDFHMAC( + ... algorithm=hashes.SHA256(), + ... mode=Mode.CounterMode, + ... length=32, + ... rlen=4, + ... llen=4, + ... location=CounterLocation.BeforeFixed, + ... label=label, + ... context=context, + ... fixed=None, + ... backend=backend + ... ) + >>> kdf.verify(b"input key", key) + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + + :param mode: The desired mode of the PRF. A value from the + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.Mode` enum. + + :param int length: The desired length of the derived key in bytes. + + :param int rlen: An integer that indicates the length of the binary + representation of the counter in bytes. + + :param int llen: An integer that indicates the binary + representation of the ``length`` in bytes. + + :param location: The desired location of the counter. A value from the + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.CounterLocation` enum. + + :param bytes label: Application specific label information. If ``None`` + is explicitly passed an empty byte string will be used. + + :param bytes context: Application specific context information. If ``None`` + is explicitly passed an empty byte string will be used. + + :param bytes fixed: Instead of specifying ``label`` and ``context`` you + may supply your own fixed data. If ``fixed`` is specified, ``label`` + and ``context`` is ignored. + + :param backend: A cryptography backend + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` + instance. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised + if the provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` + + :raises TypeError: This exception is raised if ``label`` or ``context`` + is not ``bytes``. Also raised if ``rlen`` or ``llen`` is not ``int``. + + :raises ValueError: This exception is raised if ``rlen`` or ``llen`` + is greater than 4 or less than 1. This exception is also raised if + you specify a ``label`` or ``context`` and ``fixed``. + + .. method:: derive(key_material) + + :param key_material: The input key material. + :type key_material: :term:`bytes-like` + :return bytes: The derived key. + :raises TypeError: This exception is raised if ``key_material`` is + not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material. @@ -506,6 +748,137 @@ Different KDFs are suitable for different tasks such as: ``key_material`` generates the same key as the ``expected_key``, and raises an exception if they do not match. +.. class:: Mode + + An enumeration for the key based key derivative modes. + + .. attribute:: CounterMode + + The output of the PRF is computed with a counter + as the iteration variable. + +.. class:: CounterLocation + + An enumeration for the key based key derivative counter location. + + .. attribute:: BeforeFixed + + The counter iteration variable will be concatenated before + the fixed input data. + + .. attribute:: AfterFixed + + The counter iteration variable will be concatenated after + the fixed input data. + +.. currentmodule:: cryptography.hazmat.primitives.kdf.scrypt + +.. class:: Scrypt(salt, length, n, r, p, backend) + + .. versionadded:: 1.6 + + Scrypt is a KDF designed for password storage by Colin Percival to be + resistant against hardware-assisted attackers by having a tunable memory + cost. It is described in :rfc:`7914`. + + This class conforms to the + :class:`~cryptography.hazmat.primitives.kdf.KeyDerivationFunction` + interface. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives.kdf.scrypt import Scrypt + >>> from cryptography.hazmat.backends import default_backend + >>> backend = default_backend() + >>> salt = os.urandom(16) + >>> # derive + >>> kdf = Scrypt( + ... salt=salt, + ... length=32, + ... n=2**14, + ... r=8, + ... p=1, + ... backend=backend + ... ) + >>> key = kdf.derive(b"my great password") + >>> # verify + >>> kdf = Scrypt( + ... salt=salt, + ... length=32, + ... n=2**14, + ... r=8, + ... p=1, + ... backend=backend + ... ) + >>> kdf.verify(b"my great password", key) + + :param bytes salt: A salt. + :param int length: The desired length of the derived key in bytes. + :param int n: CPU/Memory cost parameter. It must be larger than 1 and be a + power of 2. + :param int r: Block size parameter. + :param int p: Parallelization parameter. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend`. + + The computational and memory cost of Scrypt can be adjusted by manipulating + the 3 parameters: ``n``, ``r``, and ``p``. In general, the memory cost of + Scrypt is affected by the values of both ``n`` and ``r``, while ``n`` also + determines the number of iterations performed. ``p`` increases the + computational cost without affecting memory usage. A more in-depth + explanation of the 3 parameters can be found `here`_. + + :rfc:`7914` `recommends`_ values of ``r=8`` and ``p=1`` while scaling ``n`` + to a number appropriate for your system. `The scrypt paper`_ suggests a + minimum value of ``n=2**14`` for interactive logins (t < 100ms), or + ``n=2**20`` for more sensitive files (t < 5s). + + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the + provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend` + + :raises TypeError: This exception is raised if ``salt`` is not ``bytes``. + :raises ValueError: This exception is raised if ``n`` is less than 2, if + ``n`` is not a power of 2, if ``r`` is less than 1 or if ``p`` is less + than 1. + + .. method:: derive(key_material) + + :param key_material: The input key material. + :type key_material: :term:`bytes-like` + :return bytes: the derived key. + :raises TypeError: This exception is raised if ``key_material`` is not + ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + This generates and returns a new key from the supplied password. + + .. method:: verify(key_material, expected_key) + + :param bytes key_material: The input key material. This is the same as + ``key_material`` in :meth:`derive`. + :param bytes expected_key: The expected result of deriving a new key, + this is the same as the return value of + :meth:`derive`. + :raises cryptography.exceptions.InvalidKey: This is raised when the + derived key does not match + the expected key. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + This checks whether deriving a new key from the supplied + ``key_material`` generates the same key as the ``expected_key``, and + raises an exception if they do not match. This can be used for + checking whether the password a user provides matches the stored derived + key. Interface ~~~~~~~~~ @@ -554,12 +927,18 @@ Interface stored derived key. -.. _`NIST SP 800-132`: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf -.. _`NIST SP 800-56Ar2`: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf -.. _`Password Storage Cheat Sheet`: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet +.. [#nist] See `NIST SP 800-132`_. + +.. _`NIST SP 800-132`: https://csrc.nist.gov/publications/detail/sp/800-132/final +.. _`NIST SP 800-108`: https://csrc.nist.gov/publications/detail/sp/800-108/final +.. _`NIST SP 800-56Ar2`: https://csrc.nist.gov/publications/detail/sp/800-56a/rev-2/final +.. _`ANSI X9.63:2001`: https://webstore.ansi.org +.. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf +.. _`more detailed description`: https://security.stackexchange.com/a/3993/43116 .. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 -.. _`scrypt`: https://en.wikipedia.org/wiki/Scrypt .. _`key stretching`: https://en.wikipedia.org/wiki/Key_stretching -.. _`HKDF`: -.. _`RFC 5869`: https://tools.ietf.org/html/rfc5869 +.. _`HKDF`: https://en.wikipedia.org/wiki/HKDF .. _`HKDF paper`: https://eprint.iacr.org/2010/264 +.. _`here`: https://stackoverflow.com/a/30308723/1170681 +.. _`recommends`: https://tools.ietf.org/html/rfc7914#section-2 +.. _`The scrypt paper`: https://www.tarsnap.com/scrypt/scrypt.pdf diff --git a/docs/hazmat/primitives/keywrap.rst b/docs/hazmat/primitives/keywrap.rst new file mode 100644 index 00000000..1c15f9d1 --- /dev/null +++ b/docs/hazmat/primitives/keywrap.rst @@ -0,0 +1,98 @@ +.. hazmat:: + +.. module:: cryptography.hazmat.primitives.keywrap + +Key wrapping +============ + +Key wrapping is a cryptographic construct that uses symmetric encryption to +encapsulate key material. Key wrapping algorithms are occasionally utilized +to protect keys at rest or transmit them over insecure networks. Many of the +protections offered by key wrapping are also offered by using authenticated +:doc:`symmetric encryption </hazmat/primitives/symmetric-encryption>`. + +.. function:: aes_key_wrap(wrapping_key, key_to_wrap, backend) + + .. versionadded:: 1.1 + + This function performs AES key wrap (without padding) as specified in + :rfc:`3394`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes key_to_wrap: The key to wrap. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The wrapped key as bytes. + +.. function:: aes_key_unwrap(wrapping_key, wrapped_key, backend) + + .. versionadded:: 1.1 + + This function performs AES key unwrap (without padding) as specified in + :rfc:`3394`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes wrapped_key: The wrapped key. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The unwrapped key as bytes. + + :raises cryptography.hazmat.primitives.keywrap.InvalidUnwrap: This is + raised if the key is not successfully unwrapped. + +.. function:: aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend) + + .. versionadded:: 2.2 + + This function performs AES key wrap with padding as specified in + :rfc:`5649`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes key_to_wrap: The key to wrap. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The wrapped key as bytes. + +.. function:: aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend) + + .. versionadded:: 2.2 + + This function performs AES key unwrap with padding as specified in + :rfc:`5649`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes wrapped_key: The wrapped key. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The unwrapped key as bytes. + + :raises cryptography.hazmat.primitives.keywrap.InvalidUnwrap: This is + raised if the key is not successfully unwrapped. + +Exceptions +~~~~~~~~~~ + +.. class:: InvalidUnwrap + + This is raised when a wrapped key fails to unwrap. It can be caused by a + corrupted or invalid wrapped key or an invalid wrapping key. diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst index e04a849f..a5b13caf 100644 --- a/docs/hazmat/primitives/mac/cmac.rst +++ b/docs/hazmat/primitives/mac/cmac.rst @@ -1,7 +1,7 @@ .. hazmat:: -Cipher-based message authentication code -======================================== +Cipher-based message authentication code (CMAC) +=============================================== .. currentmodule:: cryptography.hazmat.primitives.cmac @@ -22,7 +22,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. .. versionadded:: 0.4 CMAC objects take a - :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` provider. + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` instance. .. doctest:: @@ -32,7 +32,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. >>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend()) >>> c.update(b"message to authenticate") >>> c.finalize() - 'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk' + b'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be @@ -40,7 +40,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. If ``algorithm`` isn't a :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` - provider then ``TypeError`` will be raised. + instance then ``TypeError`` will be raised. To check that a given signature is correct use the :meth:`verify` method. You will receive an exception if the signature is wrong: @@ -54,12 +54,10 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. ... cryptography.exceptions.InvalidSignature: Signature did not match digest. - :param algorithm: An - :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` - provider. - :param backend: An - :class:`~cryptography.hazmat.backends.interfaces.CMACBackend` - provider. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. + :param backend: An instance of + :class:`~cryptography.hazmat.backends.interfaces.CMACBackend`. :raises TypeError: This is raised if the provided ``algorithm`` is not an instance of :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the diff --git a/docs/hazmat/primitives/mac/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst index 2515ac91..9d11694b 100644 --- a/docs/hazmat/primitives/mac/hmac.rst +++ b/docs/hazmat/primitives/mac/hmac.rst @@ -1,7 +1,7 @@ .. hazmat:: -Hash-based message authentication codes -======================================= +Hash-based message authentication codes (HMAC) +============================================== .. currentmodule:: cryptography.hazmat.primitives.hmac @@ -18,7 +18,7 @@ of a message. .. class:: HMAC(key, algorithm, backend) HMAC objects take a ``key`` and a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` provider. + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance. The ``key`` should be :doc:`randomly generated bytes </random-numbers>` and is recommended to be equal in length to the ``digest_size`` of the hash function chosen. You must keep the ``key`` secret. @@ -32,14 +32,14 @@ of a message. >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) >>> h.update(b"message to hash") >>> h.finalize() - '#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' + b'#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be raised. If ``algorithm`` isn't a - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` provider + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance then ``TypeError`` will be raised. To check that a given signature is correct use the :meth:`verify` method. @@ -54,14 +54,15 @@ of a message. ... cryptography.exceptions.InvalidSignature: Signature did not match digest. - :param bytes key: Secret key as ``bytes``. + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` :param algorithm: An :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` - provider such as those described in + instance such as those described in :ref:`Cryptographic Hashes <cryptographic-hash-algorithms>`. :param backend: An :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + instance. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -69,7 +70,8 @@ of a message. .. method:: update(msg) - :param bytes msg: The bytes to hash and authenticate. + :param msg: The bytes to hash and authenticate. + :type msg: :term:`bytes-like` :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` :raises TypeError: This exception is raised if ``msg`` is not ``bytes``. diff --git a/docs/hazmat/primitives/mac/index.rst b/docs/hazmat/primitives/mac/index.rst index bc54bae4..8bfe29e3 100644 --- a/docs/hazmat/primitives/mac/index.rst +++ b/docs/hazmat/primitives/mac/index.rst @@ -3,16 +3,17 @@ Message authentication codes ============================ -While cryptography supports both the CMAC and HMAC algorithms, we strongly -recommend that HMAC should be used unless you have a good reason otherwise. +While cryptography supports multiple MAC algorithms, we strongly +recommend that HMAC should be used unless you have a very specific need. For more information on why HMAC is preferred, see `Use cases for CMAC vs. HMAC?`_ -.. _`Use cases for CMAC vs. HMAC?`: http://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac - .. toctree:: :maxdepth: 1 cmac hmac + poly1305 + +.. _`Use cases for CMAC vs. HMAC?`: https://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac diff --git a/docs/hazmat/primitives/mac/poly1305.rst b/docs/hazmat/primitives/mac/poly1305.rst new file mode 100644 index 00000000..7504a076 --- /dev/null +++ b/docs/hazmat/primitives/mac/poly1305.rst @@ -0,0 +1,132 @@ +.. hazmat:: + +Poly1305 +======== + +.. currentmodule:: cryptography.hazmat.primitives.poly1305 + +.. testsetup:: + + key = b"\x01" * 32 + +Poly1305 is an authenticator that takes a 32-byte key and a message and +produces a 16-byte tag. This tag is used to authenticate the message. Each key +**must** only be used once. Using the same key to generate tags for multiple +messages allows an attacker to forge tags. Poly1305 is described in +:rfc:`7539`. + +.. class:: Poly1305(key) + + .. versionadded:: 2.7 + + .. warning:: + + Using the same key to generate tags for multiple messages allows an + attacker to forge tags. Always generate a new key per message you want + to authenticate. If you are using this as a MAC for + symmetric encryption please use + :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` + instead. + + .. doctest:: + + >>> from cryptography.hazmat.primitives import poly1305 + >>> p = poly1305.Poly1305(key) + >>> p.update(b"message to authenticate") + >>> p.finalize() + b'T\xae\xff3\xbdW\xef\xd5r\x01\xe2n=\xb7\xd2h' + + To check that a given tag is correct use the :meth:`verify` method. + You will receive an exception if the tag is wrong: + + .. doctest:: + + >>> p = poly1305.Poly1305(key) + >>> p.update(b"message to authenticate") + >>> p.verify(b"an incorrect tag") + Traceback (most recent call last): + ... + cryptography.exceptions.InvalidSignature: Value did not match computed tag. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + + .. method:: update(data) + + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises TypeError: This exception is raised if ``data`` is not ``bytes``. + + .. method:: verify(tag) + + Finalize the current context and securely compare the MAC to + ``tag``. + + :param bytes tag: The bytes to compare against. + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises cryptography.exceptions.InvalidSignature: If tag does not + match. + :raises TypeError: This exception is raised if ``tag`` is not + ``bytes``. + + .. method:: finalize() + + Finalize the current context and return the message authentication code + as bytes. + + After ``finalize`` has been called this object can no longer be used + and :meth:`update`, :meth:`verify`, and :meth:`finalize` + will raise an :class:`~cryptography.exceptions.AlreadyFinalized` + exception. + + :return bytes: The message authentication code as bytes. + :raises cryptography.exceptions.AlreadyFinalized: + + .. classmethod:: generate_tag(key, data) + + A single step alternative to do sign operations. Returns the message + authentication code as ``bytes`` for the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :return bytes: The message authentication code as bytes. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key`` or ``data`` are + not ``bytes``. + + .. doctest:: + + >>> poly1305.Poly1305.generate_tag(key, b"message to authenticate") + b'T\xae\xff3\xbdW\xef\xd5r\x01\xe2n=\xb7\xd2h' + + .. classmethod:: verify_tag(key, data, tag) + + A single step alternative to do verify operations. Securely compares the + MAC to ``tag``, using the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :param bytes tag: The bytes to compare against. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key``, ``data`` or + ``tag`` are not ``bytes``. + :raises cryptography.exceptions.InvalidSignature: If tag does not match. + + .. doctest:: + + >>> poly1305.Poly1305.verify_tag(key, b"message to authenticate", b"an incorrect tag") + Traceback (most recent call last): + ... + cryptography.exceptions.InvalidSignature: Value did not match computed tag. diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index a60f5ac8..9581df88 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -1,7 +1,7 @@ .. hazmat:: -Padding -======= +Symmetric Padding +================= .. module:: cryptography.hazmat.primitives.padding @@ -25,33 +25,76 @@ multiple of the block size. >>> padder = padding.PKCS7(128).padder() >>> padded_data = padder.update(b"11111111111111112222222222") >>> padded_data - '1111111111111111' + b'1111111111111111' >>> padded_data += padder.finalize() >>> padded_data - '11111111111111112222222222\x06\x06\x06\x06\x06\x06' + b'11111111111111112222222222\x06\x06\x06\x06\x06\x06' >>> unpadder = padding.PKCS7(128).unpadder() >>> data = unpadder.update(padded_data) >>> data - '1111111111111111' + b'1111111111111111' >>> data + unpadder.finalize() - '11111111111111112222222222' + b'11111111111111112222222222' - :param block_size: The size of the block in bits that the data is being - padded to. + :param block_size: The size of the block in :term:`bits` that the data is + being padded to. :raises ValueError: Raised if block size is not a multiple of 8 or is not - between 0 and 256. + between 0 and 2040 inclusive. .. method:: padder() :returns: A padding :class:`~cryptography.hazmat.primitives.padding.PaddingContext` - provider. + instance. .. method:: unpadder() :returns: An unpadding :class:`~cryptography.hazmat.primitives.padding.PaddingContext` - provider. + instance. + + +.. class:: ANSIX923(block_size) + + .. versionadded:: 1.3 + + `ANSI X.923`_ padding works by appending ``N-1`` bytes with the value of + ``0`` and a last byte with the value of ``chr(N)``, where ``N`` is the + number of bytes required to make the final block of data the same size as + the block size. A simple example of padding is: + + .. doctest:: + + >>> padder = padding.ANSIX923(128).padder() + >>> padded_data = padder.update(b"11111111111111112222222222") + >>> padded_data + b'1111111111111111' + >>> padded_data += padder.finalize() + >>> padded_data + b'11111111111111112222222222\x00\x00\x00\x00\x00\x06' + >>> unpadder = padding.ANSIX923(128).unpadder() + >>> data = unpadder.update(padded_data) + >>> data + b'1111111111111111' + >>> data + unpadder.finalize() + b'11111111111111112222222222' + + :param block_size: The size of the block in :term:`bits` that the data is + being padded to. + :raises ValueError: Raised if block size is not a multiple of 8 or is not + between 0 and 2040 inclusive. + + .. method:: padder() + + :returns: A padding + :class:`~cryptography.hazmat.primitives.padding.PaddingContext` + instance. + + .. method:: unpadder() + + :returns: An unpadding + :class:`~cryptography.hazmat.primitives.padding.PaddingContext` + instance. .. class:: PaddingContext @@ -82,3 +125,5 @@ multiple of the block size. :raises TypeError: Raised if data is not bytes. :raises ValueError: When trying to remove padding from incorrectly padded data. + +.. _`ANSI X.923`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X9.23 diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 309c6fd0..46f0786d 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -16,6 +16,9 @@ decrypt them. For this reason it is **strongly** recommended to combine encryption with a message authentication code, such as :doc:`HMAC </hazmat/primitives/mac/hmac>`, in an "encrypt-then-MAC" formulation as `described by Colin Percival`_. +``cryptography`` includes a recipe named :doc:`/fernet` that does this for you. +**To minimize the risk of security issues you should evaluate Fernet to see if +it fits your needs before implementing anything using this module.** .. class:: Cipher(algorithm, mode, backend) @@ -39,18 +42,18 @@ in an "encrypt-then-MAC" formulation as `described by Colin Percival`_. >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) + decryptor.finalize() - 'a secret message' + b'a secret message' - :param algorithms: A + :param algorithm: A :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` - provider such as those described + instance such as those described :ref:`below <symmetric-encryption-algorithms>`. :param mode: A :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode` - provider such as those described + instance such as those described :ref:`below <symmetric-encryption-modes>`. :param backend: A :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` - provider. + instance. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement @@ -60,7 +63,7 @@ in an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :return: An encrypting :class:`~cryptography.hazmat.primitives.ciphers.CipherContext` - provider. + instance. If the backend doesn't support the requested combination of ``cipher`` and ``mode`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` @@ -70,7 +73,7 @@ in an "encrypt-then-MAC" formulation as `described by Colin Percival`_. :return: A decrypting :class:`~cryptography.hazmat.primitives.ciphers.CipherContext` - provider. + instance. If the backend doesn't support the requested combination of ``cipher`` and ``mode`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` @@ -89,8 +92,9 @@ Algorithms AES is both fast, and cryptographically strong. It is a good default choice for encryption. - :param bytes key: The secret key. This must be kept secret. Either ``128``, - ``192``, or ``256`` bits long. + :param key: The secret key. This must be kept secret. Either ``128``, + ``192``, or ``256`` :term:`bits` long. + :type key: :term:`bytes-like` .. class:: Camellia(key) @@ -98,22 +102,76 @@ Algorithms It is considered to have comparable security and performance to AES but is not as widely studied or deployed. - :param bytes key: The secret key. This must be kept secret. Either ``128``, - ``192``, or ``256`` bits long. + :param key: The secret key. This must be kept secret. Either ``128``, + ``192``, or ``256`` :term:`bits` long. + :type key: :term:`bytes-like` + +.. class:: ChaCha20(key) + + .. versionadded:: 2.1 + + .. note:: + + In most cases users should use + :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` + instead of this class. `ChaCha20` alone does not provide integrity + so it must be combined with a MAC to be secure. + :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` + does this for you. + + ChaCha20 is a stream cipher used in several IETF protocols. It is + standardized in :rfc:`7539`. + + :param key: The secret key. This must be kept secret. ``256`` + :term:`bits` (32 bytes) in length. + :type key: :term:`bytes-like` + + :param nonce: Should be unique, a :term:`nonce`. It is + critical to never reuse a ``nonce`` with a given key. Any reuse of a + nonce with the same key compromises the security of every message + encrypted with that key. The nonce does not need to be kept secret + and may be included with the ciphertext. This must be ``128`` + :term:`bits` in length. + :type nonce: :term:`bytes-like` + + .. note:: + + In :rfc:`7539` the nonce is defined as a 96-bit value that is later + concatenated with a block counter (encoded as a 32-bit + little-endian). If you have a separate nonce and block counter + you will need to concatenate it yourself before passing it. For + example, if you have an initial block counter of 2 and a 96-bit + nonce the concatenated nonce would be + ``struct.pack("<i", 2) + nonce``. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + >>> from cryptography.hazmat.backends import default_backend + >>> nonce = os.urandom(16) + >>> algorithm = algorithms.ChaCha20(key, nonce) + >>> cipher = Cipher(algorithm, mode=None, backend=default_backend()) + >>> encryptor = cipher.encryptor() + >>> ct = encryptor.update(b"a secret message") + >>> decryptor = cipher.decryptor() + >>> decryptor.update(ct) + b'a secret message' .. class:: TripleDES(key) Triple DES (Data Encryption Standard), sometimes referred to as 3DES, is a block cipher standardized by NIST. Triple DES has known crypto-analytic flaws, however none of them currently enable a practical attack. - Nonetheless, Triples DES is not recommended for new applications because it + Nonetheless, Triple DES is not recommended for new applications because it is incredibly slow; old applications should consider moving away from it. - :param bytes key: The secret key. This must be kept secret. Either ``64``, - ``128``, or ``192`` bits long. DES only uses ``56``, ``112``, or ``168`` - bits of the key as there is a parity byte in each component of the key. - Some writing refers to there being up to three separate keys that are each - ``56`` bits long, they can simply be concatenated to produce the full key. + :param key: The secret key. This must be kept secret. Either ``64``, + ``128``, or ``192`` :term:`bits` long. DES only uses ``56``, ``112``, + or ``168`` bits of the key as there is a parity byte in each component + of the key. Some writing refers to there being up to three separate + keys that are each ``56`` bits long, they can simply be concatenated + to produce the full key. + :type key: :term:`bytes-like` .. class:: CAST5(key) @@ -121,10 +179,12 @@ Algorithms CAST5 (also known as CAST-128) is a block cipher approved for use in the Canadian government by the `Communications Security Establishment`_. It is - a variable key length cipher and supports keys from 40-128 bits in length. + a variable key length cipher and supports keys from 40-128 :term:`bits` in + length. - :param bytes key: The secret key, This must be kept secret. 40 to 128 bits - in length in increments of 8 bits. + :param key: The secret key, This must be kept secret. 40 to 128 + :term:`bits` in length in increments of 8 bits. + :type key: :term:`bytes-like` .. class:: SEED(key) @@ -134,8 +194,9 @@ Algorithms (KISA). It is defined in :rfc:`4269` and is used broadly throughout South Korean industry, but rarely found elsewhere. - :param bytes key: The secret key. This must be kept secret. ``128`` bits in - length. + :param key: The secret key. This must be kept secret. ``128`` + :term:`bits` in length. + :type key: :term:`bytes-like` Weak ciphers ------------ @@ -152,8 +213,9 @@ Weak ciphers susceptible to attacks when using weak keys. The author has recommended that users of Blowfish move to newer algorithms such as :class:`AES`. - :param bytes key: The secret key. This must be kept secret. 32 to 448 bits - in length in increments of 8 bits. + :param key: The secret key. This must be kept secret. 32 to 448 + :term:`bits` in length in increments of 8 bits. + :type key: :term:`bytes-like` .. class:: ARC4(key) @@ -161,8 +223,10 @@ Weak ciphers initial stream output. Its use is strongly discouraged. ARC4 does not use mode constructions. - :param bytes key: The secret key. This must be kept secret. Either ``40``, - ``56``, ``64``, ``80``, ``128``, ``192``, or ``256`` bits in length. + :param key: The secret key. This must be kept secret. Either ``40``, + ``56``, ``64``, ``80``, ``128``, ``192``, or ``256`` :term:`bits` in + length. + :type key: :term:`bytes-like` .. doctest:: @@ -174,7 +238,7 @@ Weak ciphers >>> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) - 'a secret message' + b'a secret message' .. class:: IDEA(key) @@ -183,8 +247,9 @@ Weak ciphers is susceptible to attacks when using weak keys. It is recommended that you do not use this cipher for new applications. - :param bytes key: The secret key. This must be kept secret. ``128`` bits in - length. + :param key: The secret key. This must be kept secret. ``128`` + :term:`bits` in length. + :type key: :term:`bytes-like` .. _symmetric-encryption-modes: @@ -201,13 +266,14 @@ Modes **Padding is required when using this mode.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes </random-numbers>`. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Each time something is encrypted a new ``initialization_vector`` should be generated. Do not reuse an ``initialization_vector`` with a given ``key``, and particularly do not use a constant ``initialization_vector``. + :type initialization_vector: :term:`bytes-like` A good construction looks like: @@ -223,7 +289,7 @@ Modes .. doctest:: >>> from cryptography.hazmat.primitives.ciphers.modes import CBC - >>> iv = "a" * 16 + >>> iv = b"a" * 16 >>> mode = CBC(iv) @@ -232,7 +298,7 @@ Modes .. warning:: Counter mode is not recommended for use with block ciphers that have a - block size of less than 128-bits. + block size of less than 128-:term:`bits`. CTR (Counter) is a mode of operation for block ciphers. It is considered cryptographically strong. It transforms a block cipher into a stream @@ -240,12 +306,13 @@ Modes **This mode does not require padding.** - :param bytes nonce: Should be unique, a :term:`nonce`. It is + :param nonce: Should be unique, a :term:`nonce`. It is critical to never reuse a ``nonce`` with a given key. Any reuse of a nonce with the same key compromises the security of every message encrypted with that key. Must be the same number of bytes as the ``block_size`` of the cipher with a given key. The nonce does not need to be kept secret and may be included with the ciphertext. + :type nonce: :term:`bytes-like` .. class:: OFB(initialization_vector) @@ -254,11 +321,12 @@ Modes **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes </random-numbers>`. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: CFB(initialization_vector) @@ -267,11 +335,12 @@ Modes **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes </random-numbers>`. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: CFB8(initialization_vector) @@ -281,18 +350,27 @@ Modes **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes </random-numbers>`. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: GCM(initialization_vector, tag=None, min_tag_length=16) .. danger:: + If you are encrypting data that can fit into memory you should strongly + consider using + :class:`~cryptography.hazmat.primitives.ciphers.aead.AESGCM` instead + of this. + When using this mode you **must** not use the decrypted data until - :meth:`~cryptography.hazmat.primitives.ciphers.CipherContext.finalize` + the appropriate finalization method + (:meth:`~cryptography.hazmat.primitives.ciphers.CipherContext.finalize` + or + :meth:`~cryptography.hazmat.primitives.ciphers.AEADDecryptionContext.finalize_with_tag`) has been called. GCM provides **no** guarantees of ciphertext integrity until decryption is complete. @@ -305,20 +383,22 @@ Modes **This mode does not require padding.** - :param bytes initialization_vector: Must be unique, a :term:`nonce`. + :param initialization_vector: Must be unique, a :term:`nonce`. They do not need to be kept secret and they can be included in a transmitted message. NIST `recommends a 96-bit IV length`_ for performance critical situations but it can be up to 2\ :sup:`64` - 1 - bits. Do not reuse an ``initialization_vector`` with a given ``key``. + :term:`bits`. Do not reuse an ``initialization_vector`` with a given + ``key``. + :type initialization_vector: :term:`bytes-like` .. note:: Cryptography will generate a 128-bit tag when finalizing encryption. You can shorten a tag by truncating it to the desired length but this - is **not recommended** as it lowers the security margins of the - authentication (`NIST SP-800-38D`_ recommends 96-bits or greater). - Applications wishing to allow truncation must pass the - ``min_tag_length`` parameter. + is **not recommended** as it makes it easier to forge messages, and + also potentially leaks the key (`NIST SP-800-38D`_ recommends + 96-:term:`bits` or greater). Applications wishing to allow truncation + can pass the ``min_tag_length`` parameter. .. versionchanged:: 0.5 @@ -326,18 +406,26 @@ Modes truncation down to ``4`` bytes was always allowed. :param bytes tag: The tag bytes to verify during decryption. When - encrypting this must be ``None``. + encrypting this must be ``None``. When decrypting, it may be ``None`` + if the tag is supplied on finalization using + :meth:`~cryptography.hazmat.primitives.ciphers.AEADDecryptionContext.finalize_with_tag`. + Otherwise, the tag is mandatory. - :param bytes min_tag_length: The minimum length ``tag`` must be. By default + :param int min_tag_length: The minimum length ``tag`` must be. By default this is ``16``, meaning tag truncation is not allowed. Allowing tag truncation is strongly discouraged for most applications. - :raises ValueError: This is raised if ``len(tag) < min_tag_length``. + :raises ValueError: This is raised if ``len(tag) < min_tag_length`` or the + ``initialization_vector`` is too short. + + An example of securely encrypting and decrypting data with ``AES`` in the + ``GCM`` mode looks like: .. testcode:: import os + from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes ) @@ -397,8 +485,34 @@ Modes .. testoutput:: - a secret message! + b'a secret message!' + +.. class:: XTS(tweak) + + .. versionadded:: 2.1 + + .. warning:: + + XTS mode is meant for disk encryption and should not be used in other + contexts. ``cryptography`` only supports XTS mode with + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + .. note:: + + AES XTS keys are double length. This means that to do AES-128 + encryption in XTS mode you need a 256-bit key. Similarly, AES-256 + requires passing a 512-bit key. AES 192 is not supported in XTS mode. + + XTS (XEX-based tweaked-codebook mode with ciphertext stealing) is a mode + of operation for the AES block cipher that is used for `disk encryption`_. + + **This mode does not require padding.** + + :param tweak: The tweak is a 16 byte value typically derived from + something like the disk sector number. A given ``(tweak, key)`` pair + should not be reused, although doing so is less catastrophic than + in CTR mode. + :type tweak: :term:`bytes-like` Insecure modes -------------- @@ -419,7 +533,7 @@ Insecure modes **Padding is required when using this mode.** Interfaces ----------- +~~~~~~~~~~ .. currentmodule:: cryptography.hazmat.primitives.ciphers @@ -443,7 +557,8 @@ Interfaces .. method:: update(data) - :param bytes data: The data you wish to pass into the context. + :param data: The data you wish to pass into the context. + :type data: :term:`bytes-like` :return bytes: Returns the data that was encrypted or decrypted. :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` @@ -453,6 +568,50 @@ Interfaces return bytes immediately, however in other modes it will return chunks whose size is determined by the cipher's block size. + .. method:: update_into(data, buf) + + .. versionadded:: 1.8 + + .. warning:: + + This method allows you to avoid a memory copy by passing a writable + buffer and reading the resulting data. You are responsible for + correctly sizing the buffer and properly handling the data. This + method should only be used when extremely high performance is a + requirement and you will be making many small calls to + ``update_into``. + + :param data: The data you wish to pass into the context. + :type data: :term:`bytes-like` + :param buf: A writable Python buffer that the data will be written + into. This buffer should be ``len(data) + n - 1`` bytes where ``n`` + is the block size (in bytes) of the cipher and mode combination. + :return int: Number of bytes written. + :raises NotImplementedError: This is raised if the version of ``cffi`` + used is too old (this can happen on older PyPy releases). + :raises ValueError: This is raised if the supplied buffer is too small. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + >>> from cryptography.hazmat.backends import default_backend + >>> backend = default_backend() + >>> key = os.urandom(32) + >>> iv = os.urandom(16) + >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) + >>> encryptor = cipher.encryptor() + >>> # the buffer needs to be at least len(data) + n - 1 where n is cipher/mode block size in bytes + >>> buf = bytearray(31) + >>> len_encrypted = encryptor.update_into(b"a secret message", buf) + >>> # get the ciphertext from the buffer reading only the bytes written to it (len_encrypted) + >>> ct = bytes(buf[:len_encrypted]) + encryptor.finalize() + >>> decryptor = cipher.decryptor() + >>> len_decrypted = decryptor.update_into(ct, buf) + >>> # get the plaintext from the buffer reading only the bytes written (len_decrypted) + >>> bytes(buf[:len_decrypted]) + decryptor.finalize() + b'a secret message' + .. method:: finalize() :return bytes: Returns the remainder of the data. @@ -469,12 +628,12 @@ Interfaces with an AEAD mode (e.g. :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM`) the result will conform to the ``AEADCipherContext`` and ``CipherContext`` interfaces. If - it is an encryption context it will additionally be an - ``AEADEncryptionContext`` provider. ``AEADCipherContext`` contains an - additional method :meth:`authenticate_additional_data` for adding - additional authenticated but unencrypted data (see note below). You should - call this before calls to ``update``. When you are done call ``finalize`` - to finish the operation. + it is an encryption or decryption context it will additionally be an + ``AEADEncryptionContext`` or ``AEADDecryptionContext`` instance, + respectively. ``AEADCipherContext`` contains an additional method + :meth:`authenticate_additional_data` for adding additional authenticated + but unencrypted data (see note below). You should call this before calls to + ``update``. When you are done call ``finalize`` to finish the operation. .. note:: @@ -485,7 +644,8 @@ Interfaces .. method:: authenticate_additional_data(data) - :param bytes data: Any data you wish to authenticate but not encrypt. + :param data: Any data you wish to authenticate but not encrypt. + :type data: :term:`bytes-like` :raises: :class:`~cryptography.exceptions.AlreadyFinalized` .. class:: AEADEncryptionContext @@ -504,6 +664,32 @@ Interfaces :raises: :class:`~cryptography.exceptions.NotYetFinalized` if called before the context is finalized. +.. class:: AEADDecryptionContext + + .. versionadded:: 1.9 + + When creating an encryption context using ``decryptor`` on a ``Cipher`` + object with an AEAD mode such as + :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` an object + conforming to both the ``AEADDecryptionContext`` and ``AEADCipherContext`` + interfaces will be returned. This interface provides one additional method + :meth:`finalize_with_tag` that allows passing the authentication tag for + validation after the ciphertext has been decrypted. + + .. method:: finalize_with_tag(tag) + + :param bytes tag: The tag bytes to verify after decryption. + :return bytes: Returns the remainder of the data. + :raises ValueError: This is raised when the data provided isn't + a multiple of the algorithm's block size, if ``min_tag_length`` is + less than 4, or if ``len(tag) < min_tag_length``. + ``min_tag_length`` is an argument to the ``GCM`` constructor. + + If the authentication tag was not already supplied to the constructor + of the :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` mode + object, this method must be used instead of + :meth:`~cryptography.hazmat.primitives.ciphers.CipherContext.finalize`. + .. class:: CipherAlgorithm A named symmetric encryption algorithm. @@ -519,7 +705,7 @@ Interfaces :type: int - The number of bits in the key being used. + The number of :term:`bits` in the key being used. .. class:: BlockCipherAlgorithm @@ -530,7 +716,7 @@ Interfaces :type: int - The number of bits in a block. + The number of :term:`bits` in a block. Interfaces used by the symmetric cipher modes described in :ref:`Symmetric Encryption Modes <symmetric-encryption-modes>`. @@ -571,7 +757,7 @@ Interfaces used by the symmetric cipher modes described in .. attribute:: initialization_vector - :type: bytes + :type: :term:`bytes-like` Exact requirements of the initialization are described by the documentation of individual modes. @@ -583,7 +769,7 @@ Interfaces used by the symmetric cipher modes described in .. attribute:: nonce - :type: bytes + :type: :term:`bytes-like` Exact requirements of the nonce are described by the documentation of individual modes. @@ -595,19 +781,45 @@ Interfaces used by the symmetric cipher modes described in .. attribute:: tag - :type: bytes + :type: :term:`bytes-like` Exact requirements of the tag are described by the documentation of individual modes. +.. class:: ModeWithTweak + + .. versionadded:: 2.1 + + A cipher mode with a tweak. + + .. attribute:: tweak + + :type: :term:`bytes-like` + + Exact requirements of the tweak are described by the documentation of + individual modes. + +Exceptions +~~~~~~~~~~ + +.. currentmodule:: cryptography.exceptions + + +.. class:: InvalidTag + + This is raised if an authenticated encryption tag fails to verify during + decryption. + + -.. _`described by Colin Percival`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`recommends a 96-bit IV length`: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf -.. _`NIST SP-800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf +.. _`described by Colin Percival`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`recommends a 96-bit IV length`: https://csrc.nist.gov/publications/detail/sp/800-38d/final +.. _`NIST SP-800-38D`: https://csrc.nist.gov/publications/detail/sp/800-38d/final .. _`Communications Security Establishment`: https://www.cse-cst.gc.ca -.. _`encrypt`: https://ssd.eff.org/en/module/what-encryption -.. _`CRYPTREC`: http://www.cryptrec.go.jp/english/ -.. _`significant patterns in the output`: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 +.. _`encrypt`: https://ssd.eff.org/en/module/what-should-i-know-about-encryption +.. _`CRYPTREC`: https://www.cryptrec.go.jp/english/ +.. _`significant patterns in the output`: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB) .. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm -.. _`OpenPGP`: http://www.openpgp.org +.. _`OpenPGP`: https://www.openpgp.org/ +.. _`disk encryption`: https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS diff --git a/docs/hazmat/primitives/twofactor.rst b/docs/hazmat/primitives/twofactor.rst index df70a58a..51625dfc 100644 --- a/docs/hazmat/primitives/twofactor.rst +++ b/docs/hazmat/primitives/twofactor.rst @@ -18,14 +18,15 @@ codes (HMAC). .. currentmodule:: cryptography.hazmat.primitives.twofactor.hotp -.. class:: HOTP(key, length, algorithm, backend) +.. class:: HOTP(key, length, algorithm, backend, enforce_key_length=True) .. versionadded:: 0.3 HOTP objects take a ``key``, ``length`` and ``algorithm`` parameter. The ``key`` should be :doc:`randomly generated bytes </random-numbers>` and is - recommended to be 160 bits in length. The ``length`` parameter controls the - length of the generated one time password and must be >= 6 and <= 8. + recommended to be 160 :term:`bits` in length. The ``length`` parameter + controls the length of the generated one time password and must be >= 6 + and <= 8. This is an implementation of :rfc:`4226`. @@ -35,23 +36,34 @@ codes (HMAC). >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.twofactor.hotp import HOTP >>> from cryptography.hazmat.primitives.hashes import SHA1 - >>> key = os.urandom(16) + >>> key = os.urandom(20) >>> hotp = HOTP(key, 6, SHA1(), backend=default_backend()) >>> hotp_value = hotp.generate(0) >>> hotp.verify(hotp_value, 0) - :param bytes key: Per-user secret key. This value must be kept secret - and be at least 128 bits. It is recommended that the - key be 160 bits. + :param key: Per-user secret key. This value must be kept secret + and be at least 128 :term:`bits`. It is recommended that + the key be 160 bits. + :type key: :term:`bytes-like` :param int length: Length of generated one time password as ``int``. :param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A :class:`~cryptography.hazmat.primitives.hashes` - provider. + instance. :param backend: A :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + instance. + :param enforce_key_length: A boolean flag defaulting to True that toggles + whether a minimum key length of 128 :term:`bits` is enforced. This + exists to work around the fact that as documented in `Issue #2915`_, + the Google Authenticator PAM module by default generates 80 bit keys. + If this flag is set to False, the application develop should implement + additional checks of the key length before passing it into + :class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP`. + + .. versionadded:: 1.5 + :raises ValueError: This is raised if the provided ``key`` is shorter than - 128 bits or if the ``length`` parameter is not 6, 7 or 8. + 128 :term:`bits` or if the ``length`` parameter is not 6, 7 or 8. :raises TypeError: This is raised if the provided ``algorithm`` is not :class:`~cryptography.hazmat.primitives.hashes.SHA1()`, :class:`~cryptography.hazmat.primitives.hashes.SHA256()` or @@ -76,6 +88,8 @@ codes (HMAC). .. method:: get_provisioning_uri(account_name, counter, issuer) + .. versionadded:: 1.0 + :param account_name: The display name of account, such as ``'Alice Smith'`` or ``'alice@example.com'``. :type account_name: :term:`text` @@ -127,7 +141,7 @@ similar to the following code. .. currentmodule:: cryptography.hazmat.primitives.twofactor.totp -.. class:: TOTP(key, length, algorithm, time_step, backend) +.. class:: TOTP(key, length, algorithm, time_step, backend, enforce_key_length=True) TOTP objects take a ``key``, ``length``, ``algorithm`` and ``time_step`` parameter. The ``key`` should be :doc:`randomly generated bytes @@ -144,25 +158,35 @@ similar to the following code. >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.twofactor.totp import TOTP >>> from cryptography.hazmat.primitives.hashes import SHA1 - >>> key = os.urandom(16) + >>> key = os.urandom(20) >>> totp = TOTP(key, 8, SHA1(), 30, backend=default_backend()) >>> time_value = time.time() >>> totp_value = totp.generate(time_value) >>> totp.verify(totp_value, time_value) - :param bytes key: Per-user secret key. This value must be kept secret - and be at least 128 bits. It is recommended that the - key be 160 bits. + :param key: Per-user secret key. This value must be kept secret + and be at least 128 :term:`bits`. It is recommended that the + key be 160 bits. + :type key: :term:`bytes-like` :param int length: Length of generated one time password as ``int``. :param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A :class:`~cryptography.hazmat.primitives.hashes` - provider. + instance. :param int time_step: The time step size. The recommended size is 30. :param backend: A :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - provider. + instance. + :param enforce_key_length: A boolean flag defaulting to True that toggles + whether a minimum key length of 128 :term:`bits` is enforced. This exists to + work around the fact that as documented in `Issue #2915`_, the + Google Authenticator PAM module by default generates 80 bit keys. If + this flag is set to False, the application develop should implement + additional checks of the key length before passing it into + :class:`~cryptography.hazmat.primitives.twofactor.totp.TOTP`. + + .. versionadded:: 1.5 :raises ValueError: This is raised if the provided ``key`` is shorter than - 128 bits or if the ``length`` parameter is not 6, 7 or 8. + 128 :term:`bits` or if the ``length`` parameter is not 6, 7 or 8. :raises TypeError: This is raised if the provided ``algorithm`` is not :class:`~cryptography.hazmat.primitives.hashes.SHA1()`, :class:`~cryptography.hazmat.primitives.hashes.SHA256()` or @@ -186,9 +210,11 @@ similar to the following code. .. method:: get_provisioning_uri(account_name, issuer) + .. versionadded:: 1.0 + :param account_name: The display name of account, such as ``'Alice Smith'`` or ``'alice@example.com'``. - :type: :term:`text` + :type account_name: :term:`text` :param issuer: The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token. @@ -198,11 +224,11 @@ similar to the following code. Provisioning URI ~~~~~~~~~~~~~~~~ -The provisioning URI of HOTP and TOTP is not actual the part of RFC 4226 and -RFC 6238, but a `spec of Google Authenticator`_. It is widely supported by web -sites and mobile applications which are using Two-Factor authentication. +The provisioning URI of HOTP and TOTP is a `feature of Google Authenticator`_ +and not actually part of the HOTP or TOTP RFCs. However, it is widely supported +by web sites and mobile applications which are using Two-Factor authentication. -For generating a provisioning URI, you could use the ``get_provisioning_uri`` +For generating a provisioning URI you can use the ``get_provisioning_uri`` method of HOTP/TOTP instances. .. code-block:: python @@ -217,4 +243,5 @@ method of HOTP/TOTP instances. A common usage is encoding the provisioning URI into QR code and guiding users to scan it with Two-Factor authentication applications in their mobile devices. -.. _`spec of Google Authenticator`: https://github.com/google/google-authenticator/wiki/Key-Uri-Format +.. _`feature of Google Authenticator`: https://github.com/google/google-authenticator/wiki/Key-Uri-Format +.. _`Issue #2915`: https://github.com/pyca/cryptography/issues/2915 |
