Import python-cryptography_1.7.1.orig.tar.gz

[dgit import orig python-cryptography_1.7.1.orig.tar.gz]
This commit is contained in:
Tristan Seligmann 2016-12-14 06:59:21 +01:00
commit 443c9c11a1
292 changed files with 63385 additions and 0 deletions

38
AUTHORS.rst Normal file
View File

@ -0,0 +1,38 @@
AUTHORS
=======
PGP key fingerprints are enclosed in parentheses.
* Alex Gaynor <alex.gaynor@gmail.com> (E27D 4AA0 1651 72CB C5D2 AF2B 125F 5C67 DFE9 4084)
* Hynek Schlawack <hs@ox.cx> (C2A0 4F86 ACE2 8ADC F817 DBB7 AE25 3622 7F69 F181)
* Donald Stufft <donald@stufft.io>
* Laurens Van Houtven <_@lvh.io> (D9DC 4315 772F 8E91 DD22 B153 DFD1 3DF7 A8DD 569B)
* Christian Heimes <christian@python.org>
* Paul Kehrer <paul.l.kehrer@gmail.com> (05FD 9FA1 6CF7 5735 0D91 A560 235A E5F1 29F9 ED98)
* Jarret Raim <jarito@gmail.com>
* Alex Stapleton <alexs@prol.etari.at> (A1C7 E50B 66DE 39ED C847 9665 8E3C 20D1 9BD9 5C4C)
* David Reid <dreid@dreid.org> (0F83 CC87 B32F 482B C726 B58A 9FBF D8F4 DA89 6D74)
* Matthew Lefkowitz <glyph@twistedmatrix.com> (06AB F638 E878 CD29 1264 18AB 7EC2 8125 0FBC 4A07)
* Konstantinos Koukopoulos <koukopoulos@gmail.com> (D6BD 52B6 8C99 A91C E2C8 934D 3300 566B 3A46 726E)
* Stephen Holsapple <sholsapp@gmail.com>
* Terry Chia <terrycwk1994@gmail.com>
* Matthew Iversen <matt@notevencode.com> (2F04 3DCC D6E6 D5AC D262 2E0B C046 E8A8 7452 2973)
* Mohammed Attia <skeuomorf@gmail.com>
* Michael Hart <michael.hart1994@gmail.com>
* Mark Adams <mark@markadams.me> (A18A 7DD3 283C CF2A B0CE FE0E C7A0 5E3F C972 098C)
* Gregory Haynes <greg@greghaynes.net> (6FB6 44BF 9FD0 EBA2 1CE9 471F B08F 42F9 0DC6 599F)
* Chelsea Winfree <chelsea.winfree@gmail.com>
* Steven Buss <steven.buss@gmail.com> (1FB9 2EC1 CF93 DFD6 B47F F583 B1A5 6C22 290D A4C3)
* Andre Caron <andre.l.caron@gmail.com>
* Jiangge Zhang <tonyseek@gmail.com> (BBEC 782B 015F 71B1 5FF7 EACA 1A8C AA98 255F 5000)
* Major Hayden <major@mhtx.net> (1BF9 9264 9596 0033 698C 252B 7370 51E0 C101 1FB1)
* Phoebe Queen <foibey@gmail.com> (10D4 7741 AB65 50F4 B264 3888 DA40 201A 072B C1FA)
* Google Inc.
* Amaury Forgeot d'Arc <amauryfa@google.com>
* Dirkjan Ochtman <dirkjan@ochtman.nl> (25BB BAC1 13C1 BFD5 AA59 4A4C 9F96 B929 3038 0381)
* Maximilian Hils <max@maximilianhils.com>
* Simo Sorce <simo@redhat.com>
* Thomas Sileo <t@a4.io>
* Fraser Tweedale <ftweedal@redhat.com>
* Ofek Lev <ofekmeister@gmail.com> (FFB6 B92B 30B1 7848 546E 9912 972F E913 DAD5 A46E)
* Erik Daguerre <fallenwolf@wolfthefallen.com>

792
CHANGELOG.rst Normal file
View File

@ -0,0 +1,792 @@
Changelog
=========
1.7.1 - 2016-12-13
~~~~~~~~~~~~~~~~~~
* Fixed a regression in ``int_from_bytes`` where it failed to accept
``bytearray``.
1.7 - 2016-12-12
~~~~~~~~~~~~~~~~
* Support for OpenSSL 1.0.0 has been removed. Users on older version of OpenSSL
will need to upgrade.
* Added support for Diffie-Hellman key exchange using
:meth:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization.exchange`
* The OS random engine for OpenSSL has been rewritten to improve compatibility
with embedded Python and other edge cases. More information about this change
can be found in the
`pull request <https://github.com/pyca/cryptography/pull/3229>`_.
1.6 - 2016-11-22
~~~~~~~~~~~~~~~~
* Deprecated support for OpenSSL 1.0.0. Support will be removed in
``cryptography`` 1.7.
* Replaced the Python-based OpenSSL locking callbacks with a C version to fix
a potential deadlock that could occur if a garbage collection cycle occurred
while inside the lock.
* Added support for :class:`~cryptography.hazmat.primitives.hashes.BLAKE2b` and
:class:`~cryptography.hazmat.primitives.hashes.BLAKE2s` when using OpenSSL
1.1.0.
* Added
:attr:`~cryptography.x509.Certificate.signature_algorithm_oid` support to
:class:`~cryptography.x509.Certificate`.
* Added
:attr:`~cryptography.x509.CertificateSigningRequest.signature_algorithm_oid`
support to :class:`~cryptography.x509.CertificateSigningRequest`.
* Added
:attr:`~cryptography.x509.CertificateRevocationList.signature_algorithm_oid`
support to :class:`~cryptography.x509.CertificateRevocationList`.
* Added support for :class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt`
when using OpenSSL 1.1.0.
* Added a workaround to improve compatibility with Python application bundling
tools like ``PyInstaller`` and ``cx_freeze``.
* Added support for generating a
:meth:`~cryptography.x509.random_serial_number`.
* Added support for encoding ``IPv4Network`` and ``IPv6Network`` in X.509
certificates for use with :class:`~cryptography.x509.NameConstraints`.
* Added :meth:`~cryptography.x509.Name.public_bytes` to
:class:`~cryptography.x509.Name`.
* Added :class:`~cryptography.x509.RelativeDistinguishedName`
* :class:`~cryptography.x509.DistributionPoint` now accepts
:class:`~cryptography.x509.RelativeDistinguishedName` for
:attr:`~cryptography.x509.DistributionPoint.relative_name`.
Deprecated use of :class:`~cryptography.x509.Name` as
:attr:`~cryptography.x509.DistributionPoint.relative_name`.
* :class:`~cryptography.x509.Name` now accepts an iterable of
:class:`~cryptography.x509.RelativeDistinguishedName`. RDNs can
be accessed via the :attr:`~cryptography.x509.Name.rdns`
attribute. When constructed with an iterable of
:class:`~cryptography.x509.NameAttribute`, each attribute becomes
a single-valued RDN.
* Added
:func:`~cryptography.hazmat.primitives.asymmetric.ec.derive_private_key`.
* Added support for signing and verifying RSA, DSA, and ECDSA signatures with
:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`
digests.
1.5.3 - 2016-11-05
~~~~~~~~~~~~~~~~~~
* **SECURITY ISSUE**: Fixed a bug where ``HKDF`` would return an empty
byte-string if used with a ``length`` less than ``algorithm.digest_size``.
Credit to **Markus Döring** for reporting the issue. *CVE-2016-9243*
1.5.2 - 2016-09-26
~~~~~~~~~~~~~~~~~~
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2j.
1.5.1 - 2016-09-22
~~~~~~~~~~~~~~~~~~
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2i.
* Resolved a ``UserWarning`` when used with cffi 1.8.3.
* Fixed a memory leak in name creation with X.509.
* Added a workaround for old versions of setuptools.
* Fixed an issue preventing ``cryptography`` from compiling against
OpenSSL 1.0.2i.
1.5 - 2016-08-26
~~~~~~~~~~~~~~~~
* Added
:func:`~cryptography.hazmat.primitives.asymmetric.padding.calculate_max_pss_salt_length`.
* Added "one shot"
:meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey.sign`
and
:meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey.verify`
methods to DSA keys.
* Added "one shot"
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.sign`
and
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.verify`
methods to ECDSA keys.
* Switched back to the older callback model on Python 3.5 in order to mitigate
the locking callback problem with OpenSSL <1.1.0.
* :class:`~cryptography.x509.CertificateBuilder`,
:class:`~cryptography.x509.CertificateRevocationListBuilder`, and
:class:`~cryptography.x509.RevokedCertificateBuilder` now accept timezone
aware ``datetime`` objects as method arguments
* ``cryptography`` now supports OpenSSL 1.1.0 as a compilation target.
1.4 - 2016-06-04
~~~~~~~~~~~~~~~~
* Support for OpenSSL 0.9.8 has been removed. Users on older versions of
OpenSSL will need to upgrade.
* Added :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFHMAC`.
* Added support for ``OpenSSH`` public key serialization.
* Added support for SHA-2 in RSA
:class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP` when using
OpenSSL 1.0.2 or greater.
* Added "one shot"
:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.sign`
and
:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.verify`
methods to RSA keys.
1.3.4 - 2016-06-03
~~~~~~~~~~~~~~~~~~
* Added another OpenSSL function to the bindings to support an upcoming
``pyOpenSSL`` release.
1.3.3 - 2016-06-02
~~~~~~~~~~~~~~~~~~
* Added two new OpenSSL functions to the bindings to support an upcoming
``pyOpenSSL`` release.
1.3.2 - 2016-05-04
~~~~~~~~~~~~~~~~~~
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2h.
* Fixed an issue preventing ``cryptography`` from compiling against
LibreSSL 2.3.x.
1.3.1 - 2016-03-21
~~~~~~~~~~~~~~~~~~
* Fixed a bug that caused an ``AttributeError`` when using ``mock`` to patch
some ``cryptography`` modules.
1.3 - 2016-03-18
~~~~~~~~~~~~~~~~
* Added support for padding ANSI X.923 with
:class:`~cryptography.hazmat.primitives.padding.ANSIX923`.
* Deprecated support for OpenSSL 0.9.8. Support will be removed in
``cryptography`` 1.4.
* Added support for the :class:`~cryptography.x509.PolicyConstraints`
X.509 extension including both parsing and generation using
:class:`~cryptography.x509.CertificateBuilder` and
:class:`~cryptography.x509.CertificateSigningRequestBuilder`.
* Added :attr:`~cryptography.x509.CertificateSigningRequest.is_signature_valid`
to :class:`~cryptography.x509.CertificateSigningRequest`.
* Fixed an intermittent ``AssertionError`` when performing an RSA decryption on
an invalid ciphertext, ``ValueError`` is now correctly raised in all cases.
* Added
:meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`.
1.2.3 - 2016-03-01
~~~~~~~~~~~~~~~~~~
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2g.
1.2.2 - 2016-01-29
~~~~~~~~~~~~~~~~~~
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2f.
1.2.1 - 2016-01-08
~~~~~~~~~~~~~~~~~~
* Reverts a change to an OpenSSL ``EVP_PKEY`` object that caused errors with
``pyOpenSSL``.
1.2 - 2016-01-08
~~~~~~~~~~~~~~~~
* **BACKWARDS INCOMPATIBLE:**
:class:`~cryptography.x509.RevokedCertificate`
:attr:`~cryptography.x509.RevokedCertificate.extensions` now uses extension
classes rather than returning raw values inside the
:class:`~cryptography.x509.Extension`
:attr:`~cryptography.x509.Extension.value`. The new classes
are:
* :class:`~cryptography.x509.CertificateIssuer`
* :class:`~cryptography.x509.CRLReason`
* :class:`~cryptography.x509.InvalidityDate`
* Deprecated support for OpenSSL 0.9.8 and 1.0.0. At this time there is no time
table for actually dropping support, however we strongly encourage all users
to upgrade, as those versions no longer receive support from the OpenSSL
project.
* The :class:`~cryptography.x509.Certificate` class now has
:attr:`~cryptography.x509.Certificate.signature` and
:attr:`~cryptography.x509.Certificate.tbs_certificate_bytes` attributes.
* The :class:`~cryptography.x509.CertificateSigningRequest` class now has
:attr:`~cryptography.x509.CertificateSigningRequest.signature` and
:attr:`~cryptography.x509.CertificateSigningRequest.tbs_certrequest_bytes`
attributes.
* The :class:`~cryptography.x509.CertificateRevocationList` class now has
:attr:`~cryptography.x509.CertificateRevocationList.signature` and
:attr:`~cryptography.x509.CertificateRevocationList.tbs_certlist_bytes`
attributes.
* :class:`~cryptography.x509.NameConstraints` are now supported in the
:class:`~cryptography.x509.CertificateBuilder` and
:class:`~cryptography.x509.CertificateSigningRequestBuilder`.
* Support serialization of certificate revocation lists using the
:meth:`~cryptography.x509.CertificateRevocationList.public_bytes` method of
:class:`~cryptography.x509.CertificateRevocationList`.
* Add support for parsing :class:`~cryptography.x509.CertificateRevocationList`
:meth:`~cryptography.x509.CertificateRevocationList.extensions` in the
OpenSSL backend. The following extensions are currently supported:
* :class:`~cryptography.x509.AuthorityInformationAccess`
* :class:`~cryptography.x509.AuthorityKeyIdentifier`
* :class:`~cryptography.x509.CRLNumber`
* :class:`~cryptography.x509.IssuerAlternativeName`
* Added :class:`~cryptography.x509.CertificateRevocationListBuilder` and
:class:`~cryptography.x509.RevokedCertificateBuilder` to allow creation of
CRLs.
* Unrecognized non-critical X.509 extensions are now parsed into an
:class:`~cryptography.x509.UnrecognizedExtension` object.
1.1.2 - 2015-12-10
~~~~~~~~~~~~~~~~~~
* Fixed a SIGBUS crash with the OS X wheels caused by redefinition of a
method.
* Fixed a runtime error ``undefined symbol EC_GFp_nistp224_method`` that
occurred with some OpenSSL installations.
* Updated Windows and OS X wheels to be compiled against OpenSSL 1.0.2e.
1.1.1 - 2015-11-19
~~~~~~~~~~~~~~~~~~
* Fixed several small bugs related to compiling the OpenSSL bindings with
unusual OpenSSL configurations.
* Resolved an issue where, depending on the method of installation and
which Python interpreter they were using, users on El Capitan (OS X 10.11)
may have seen an ``InternalError`` on import.
1.1 - 2015-10-28
~~~~~~~~~~~~~~~~
* Added support for Elliptic Curve Diffie-Hellman with
:class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDH`.
* Added :class:`~cryptography.hazmat.primitives.kdf.x963kdf.X963KDF`.
* Added support for parsing certificate revocation lists (CRLs) using
:func:`~cryptography.x509.load_pem_x509_crl` and
:func:`~cryptography.x509.load_der_x509_crl`.
* Add support for AES key wrapping with
:func:`~cryptography.hazmat.primitives.keywrap.aes_key_wrap` and
:func:`~cryptography.hazmat.primitives.keywrap.aes_key_unwrap`.
* Added a ``__hash__`` method to :class:`~cryptography.x509.Name`.
* Add support for encoding and decoding elliptic curve points to a byte string
form using
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers.encode_point`
and
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers.from_encoded_point`.
* Added :meth:`~cryptography.x509.Extensions.get_extension_for_class`.
* :class:`~cryptography.x509.CertificatePolicies` are now supported in the
:class:`~cryptography.x509.CertificateBuilder`.
* ``countryName`` is now encoded as a ``PrintableString`` when creating subject
and issuer distinguished names with the Certificate and CSR builder classes.
1.0.2 - 2015-09-27
~~~~~~~~~~~~~~~~~~
* **SECURITY ISSUE**: The OpenSSL backend prior to 1.0.2 made extensive use
of assertions to check response codes where our tests could not trigger a
failure. However, when Python is run with ``-O`` these asserts are optimized
away. If a user ran Python with this flag and got an invalid response code
this could result in undefined behavior or worse. Accordingly, all response
checks from the OpenSSL backend have been converted from ``assert``
to a true function call. Credit **Emilia Käsper (Google Security Team)**
for the report.
1.0.1 - 2015-09-05
~~~~~~~~~~~~~~~~~~
* We now ship OS X wheels that statically link OpenSSL by default. When
installing a wheel on OS X 10.10+ (and using a Python compiled against the
10.10 SDK) users will no longer need to compile. See :doc:`/installation` for
alternate installation methods if required.
* Set the default string mask to UTF-8 in the OpenSSL backend to resolve
character encoding issues with older versions of OpenSSL.
* Several new OpenSSL bindings have been added to support a future pyOpenSSL
release.
* Raise an error during install on PyPy < 2.6. 1.0+ requires PyPy 2.6+.
1.0 - 2015-08-12
~~~~~~~~~~~~~~~~
* Switched to the new `cffi`_ ``set_source`` out-of-line API mode for
compilation. This results in significantly faster imports and lowered
memory consumption. Due to this change we no longer support PyPy releases
older than 2.6 nor do we support any released version of PyPy3 (until a
version supporting cffi 1.0 comes out).
* Fix parsing of OpenSSH public keys that have spaces in comments.
* Support serialization of certificate signing requests using the
``public_bytes`` method of
:class:`~cryptography.x509.CertificateSigningRequest`.
* Support serialization of certificates using the ``public_bytes`` method of
:class:`~cryptography.x509.Certificate`.
* Add ``get_provisioning_uri`` method to
:class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP` and
:class:`~cryptography.hazmat.primitives.twofactor.totp.TOTP` for generating
provisioning URIs.
* Add :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHash`
and :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHMAC`.
* Raise a ``TypeError`` when passing objects that are not text as the value to
:class:`~cryptography.x509.NameAttribute`.
* Add support for :class:`~cryptography.x509.OtherName` as a general name
type.
* Added new X.509 extension support in :class:`~cryptography.x509.Certificate`
The following new extensions are now supported:
* :class:`~cryptography.x509.OCSPNoCheck`
* :class:`~cryptography.x509.InhibitAnyPolicy`
* :class:`~cryptography.x509.IssuerAlternativeName`
* :class:`~cryptography.x509.NameConstraints`
* Extension support was added to
:class:`~cryptography.x509.CertificateSigningRequest`.
* Add support for creating signed certificates with
:class:`~cryptography.x509.CertificateBuilder`. This includes support for
the following extensions:
* :class:`~cryptography.x509.BasicConstraints`
* :class:`~cryptography.x509.SubjectAlternativeName`
* :class:`~cryptography.x509.KeyUsage`
* :class:`~cryptography.x509.ExtendedKeyUsage`
* :class:`~cryptography.x509.SubjectKeyIdentifier`
* :class:`~cryptography.x509.AuthorityKeyIdentifier`
* :class:`~cryptography.x509.AuthorityInformationAccess`
* :class:`~cryptography.x509.CRLDistributionPoints`
* :class:`~cryptography.x509.InhibitAnyPolicy`
* :class:`~cryptography.x509.IssuerAlternativeName`
* :class:`~cryptography.x509.OCSPNoCheck`
* Add support for creating certificate signing requests with
:class:`~cryptography.x509.CertificateSigningRequestBuilder`. This includes
support for the same extensions supported in the ``CertificateBuilder``.
* Deprecate ``encode_rfc6979_signature`` and ``decode_rfc6979_signature`` in
favor of
:func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature`
and
:func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`.
0.9.3 - 2015-07-09
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.2d.
0.9.2 - 2015-07-04
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.2c.
0.9.1 - 2015-06-06
~~~~~~~~~~~~~~~~~~
* **SECURITY ISSUE**: Fixed a double free in the OpenSSL backend when using DSA
to verify signatures. Note that this only affects PyPy 2.6.0 and (presently
unreleased) CFFI versions greater than 1.1.0.
0.9 - 2015-05-13
~~~~~~~~~~~~~~~~
* Removed support for Python 3.2. This version of Python is rarely used
and caused support headaches. Users affected by this should upgrade to 3.3+.
* Deprecated support for Python 2.6. At the time there is no time table for
actually dropping support, however we strongly encourage all users to upgrade
their Python, as Python 2.6 no longer receives support from the Python core
team.
* Add support for the
:class:`~cryptography.hazmat.primitives.asymmetric.ec.SECP256K1` elliptic
curve.
* Fixed compilation when using an OpenSSL which was compiled with the
``no-comp`` (``OPENSSL_NO_COMP``) option.
* Support :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`
serialization of public keys using the ``public_bytes`` method of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`,
and
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`.
* Support :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`
serialization of private keys using the ``private_bytes`` method of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`,
and
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`.
* Add support for parsing X.509 certificate signing requests (CSRs) with
:func:`~cryptography.x509.load_pem_x509_csr` and
:func:`~cryptography.x509.load_der_x509_csr`.
* Moved ``cryptography.exceptions.InvalidToken`` to
:class:`cryptography.hazmat.primitives.twofactor.InvalidToken` and deprecated
the old location. This was moved to minimize confusion between this exception
and :class:`cryptography.fernet.InvalidToken`.
* Added support for X.509 extensions in :class:`~cryptography.x509.Certificate`
objects. The following extensions are supported as of this release:
* :class:`~cryptography.x509.BasicConstraints`
* :class:`~cryptography.x509.AuthorityKeyIdentifier`
* :class:`~cryptography.x509.SubjectKeyIdentifier`
* :class:`~cryptography.x509.KeyUsage`
* :class:`~cryptography.x509.SubjectAlternativeName`
* :class:`~cryptography.x509.ExtendedKeyUsage`
* :class:`~cryptography.x509.CRLDistributionPoints`
* :class:`~cryptography.x509.AuthorityInformationAccess`
* :class:`~cryptography.x509.CertificatePolicies`
Note that unsupported extensions with the critical flag raise
:class:`~cryptography.x509.UnsupportedExtension` while unsupported extensions
set to non-critical are silently ignored. Read the
:doc:`X.509 documentation</x509/index>` for more information.
0.8.2 - 2015-04-10
~~~~~~~~~~~~~~~~~~
* Fixed a race condition when initializing the OpenSSL or CommonCrypto backends
in a multi-threaded scenario.
0.8.1 - 2015-03-20
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.2a.
0.8 - 2015-03-08
~~~~~~~~~~~~~~~~
* :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` can
now load elliptic curve public keys.
* Added
:attr:`~cryptography.x509.Certificate.signature_hash_algorithm` support to
:class:`~cryptography.x509.Certificate`.
* Added
:func:`~cryptography.hazmat.primitives.asymmetric.rsa.rsa_recover_prime_factors`
* :class:`~cryptography.hazmat.primitives.kdf.KeyDerivationFunction` was moved
from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.kdf`.
* Added support for parsing X.509 names. See the
:doc:`X.509 documentation</x509/index>` for more information.
* Added
:func:`~cryptography.hazmat.primitives.serialization.load_der_private_key` to
support loading of DER encoded private keys and
:func:`~cryptography.hazmat.primitives.serialization.load_der_public_key` to
support loading DER encoded public keys.
* Fixed building against LibreSSL, a compile-time substitute for OpenSSL.
* FreeBSD 9.2 was removed from the continuous integration system.
* Updated Windows wheels to be compiled against OpenSSL 1.0.2.
* :func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key`
and :func:`~cryptography.hazmat.primitives.serialization.load_der_public_key`
now support PKCS1 RSA public keys (in addition to the previous support for
SubjectPublicKeyInfo format for RSA, EC, and DSA).
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`
and deprecated ``EllipticCurvePrivateKeyWithNumbers``.
* Added
:meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization.private_bytes`
to
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`.
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
and deprecated ``RSAPrivateKeyWithNumbers``.
* Added
:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`
to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`.
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`
and deprecated ``DSAPrivateKeyWithNumbers``.
* Added
:meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization.private_bytes`
to
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`.
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`
and deprecated ``RSAPublicKeyWithNumbers``.
* Added ``public_bytes`` to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`.
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`
and deprecated ``EllipticCurvePublicKeyWithNumbers``.
* Added ``public_bytes`` to
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`.
* Added
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`
and deprecated ``DSAPublicKeyWithNumbers``.
* Added ``public_bytes`` to
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`.
* :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` and
:class:`~cryptography.hazmat.primitives.hashes.HashContext` were moved from
:mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.hashes`.
* :class:`~cryptography.hazmat.primitives.ciphers.CipherContext`,
:class:`~cryptography.hazmat.primitives.ciphers.AEADCipherContext`,
:class:`~cryptography.hazmat.primitives.ciphers.AEADEncryptionContext`,
:class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm`, and
:class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`
were moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.ciphers`.
* :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode`,
:class:`~cryptography.hazmat.primitives.ciphers.modes.ModeWithInitializationVector`,
:class:`~cryptography.hazmat.primitives.ciphers.modes.ModeWithNonce`, and
:class:`~cryptography.hazmat.primitives.ciphers.modes.ModeWithAuthenticationTag`
were moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.ciphers.modes`.
* :class:`~cryptography.hazmat.primitives.padding.PaddingContext` was moved
from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.padding`.
*
:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`
was moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric.padding`.
*
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext`
and
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext`
were moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric`.
* :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParametersWithNumbers`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`,
``DSAPrivateKeyWithNumbers``,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` and
``DSAPublicKeyWithNumbers`` were moved from
:mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric.dsa`
* :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurveSignatureAlgorithm`,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`,
``EllipticCurvePrivateKeyWithNumbers``,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`,
and ``EllipticCurvePublicKeyWithNumbers``
were moved from :mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric.ec`.
* :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
``RSAPrivateKeyWithNumbers``,
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` and
``RSAPublicKeyWithNumbers`` were moved from
:mod:`~cryptography.hazmat.primitives.interfaces` to
:mod:`~cryptography.hazmat.primitives.asymmetric.rsa`.
0.7.2 - 2015-01-16
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.1l.
* ``enum34`` is no longer installed on Python 3.4, where it is included in
the standard library.
* Added a new function to the OpenSSL bindings to support additional
functionality in pyOpenSSL.
0.7.1 - 2014-12-28
~~~~~~~~~~~~~~~~~~
* Fixed an issue preventing compilation on platforms where ``OPENSSL_NO_SSL3``
was defined.
0.7 - 2014-12-17
~~~~~~~~~~~~~~~~
* Cryptography has been relicensed from the Apache Software License, Version
2.0, to being available under *either* the Apache Software License, Version
2.0, or the BSD license.
* Added key-rotation support to :doc:`Fernet </fernet>` with
:class:`~cryptography.fernet.MultiFernet`.
* More bit-lengths are now supported for ``p`` and ``q`` when loading DSA keys
from numbers.
* Added :class:`~cryptography.hazmat.primitives.interfaces.MACContext` as a
common interface for CMAC and HMAC and deprecated ``CMACContext``.
* Added support for encoding and decoding :rfc:`6979` signatures in
:doc:`/hazmat/primitives/asymmetric/utils`.
* Added
:func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` to
support the loading of OpenSSH public keys (:rfc:`4253`). Only RSA and DSA
keys are currently supported.
* Added initial support for X.509 certificate parsing. See the
:doc:`X.509 documentation</x509/index>` for more information.
0.6.1 - 2014-10-15
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.1j.
* Fixed an issue where OpenSSL 1.0.1j changed the errors returned by some
functions.
* Added our license file to the ``cryptography-vectors`` package.
* Implemented DSA hash truncation support (per FIPS 186-3) in the OpenSSL
backend. This works around an issue in 1.0.0, 1.0.0a, and 1.0.0b where
truncation was not implemented.
0.6 - 2014-09-29
~~~~~~~~~~~~~~~~
* Added
:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key` to
ease loading private keys, and
:func:`~cryptography.hazmat.primitives.serialization.load_pem_public_key` to
support loading public keys.
* Removed the, deprecated in 0.4, support for the ``salt_length`` argument to
the :class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1`
constructor. The ``salt_length`` should be passed to
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` instead.
* Fix compilation on OS X Yosemite.
* Deprecated ``elliptic_curve_private_key_from_numbers`` and
``elliptic_curve_public_key_from_numbers`` in favor of
``load_elliptic_curve_private_numbers`` and
``load_elliptic_curve_public_numbers`` on
:class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`.
* Added ``EllipticCurvePrivateKeyWithNumbers`` and
``EllipticCurvePublicKeyWithNumbers`` support.
* Work around three GCM related bugs in CommonCrypto and OpenSSL.
* On the CommonCrypto backend adding AAD but not subsequently calling update
would return null tag bytes.
* One the CommonCrypto backend a call to update without an empty add AAD call
would return null ciphertext bytes.
* On the OpenSSL backend with certain versions adding AAD only would give
invalid tag bytes.
* Support loading EC private keys from PEM.
0.5.4 - 2014-08-20
~~~~~~~~~~~~~~~~~~
* Added several functions to the OpenSSL bindings to support new
functionality in pyOpenSSL.
* Fixed a redefined constant causing compilation failure with Solaris 11.2.
0.5.3 - 2014-08-06
~~~~~~~~~~~~~~~~~~
* Updated Windows wheels to be compiled against OpenSSL 1.0.1i.
0.5.2 - 2014-07-09
~~~~~~~~~~~~~~~~~~
* Add ``TraditionalOpenSSLSerializationBackend`` support to
:doc:`/hazmat/backends/multibackend`.
* Fix compilation error on OS X 10.8 (Mountain Lion).
0.5.1 - 2014-07-07
~~~~~~~~~~~~~~~~~~
* Add ``PKCS8SerializationBackend`` support to
:doc:`/hazmat/backends/multibackend`.
0.5 - 2014-07-07
~~~~~~~~~~~~~~~~
* **BACKWARDS INCOMPATIBLE:**
:class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` no longer allows
truncation of tags by default. Previous versions of ``cryptography`` allowed
tags to be truncated by default, applications wishing to preserve this
behavior (not recommended) can pass the ``min_tag_length`` argument.
* Windows builds now statically link OpenSSL by default. When installing a
wheel on Windows you no longer need to install OpenSSL separately. Windows
users can switch between static and dynamic linking with an environment
variable. See :doc:`/installation` for more details.
* Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDFExpand`.
* Added :class:`~cryptography.hazmat.primitives.ciphers.modes.CFB8` support
for :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` and
:class:`~cryptography.hazmat.primitives.ciphers.algorithms.TripleDES` on
:doc:`/hazmat/backends/commoncrypto` and :doc:`/hazmat/backends/openssl`.
* Added ``AES`` :class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`
support to the OpenSSL backend when linked against 0.9.8.
* Added ``PKCS8SerializationBackend`` and
``TraditionalOpenSSLSerializationBackend`` support to the
:doc:`/hazmat/backends/openssl`.
* Added :doc:`/hazmat/primitives/asymmetric/ec` and
:class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`.
* Added :class:`~cryptography.hazmat.primitives.ciphers.modes.ECB` support
for :class:`~cryptography.hazmat.primitives.ciphers.algorithms.TripleDES` on
:doc:`/hazmat/backends/commoncrypto` and :doc:`/hazmat/backends/openssl`.
* Deprecated the concrete ``RSAPrivateKey`` class in favor of backend
specific providers of the
:class:`cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`
interface.
* Deprecated the concrete ``RSAPublicKey`` in favor of backend specific
providers of the
:class:`cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`
interface.
* Deprecated the concrete ``DSAPrivateKey`` class in favor of backend
specific providers of the
:class:`cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`
interface.
* Deprecated the concrete ``DSAPublicKey`` class in favor of backend specific
providers of the
:class:`cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`
interface.
* Deprecated the concrete ``DSAParameters`` class in favor of backend specific
providers of the
:class:`cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`
interface.
* Deprecated ``encrypt_rsa``, ``decrypt_rsa``, ``create_rsa_signature_ctx`` and
``create_rsa_verification_ctx`` on
:class:`~cryptography.hazmat.backends.interfaces.RSABackend`.
* Deprecated ``create_dsa_signature_ctx`` and ``create_dsa_verification_ctx``
on :class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
0.4 - 2014-05-03
~~~~~~~~~~~~~~~~
* Deprecated ``salt_length`` on
:class:`~cryptography.hazmat.primitives.asymmetric.padding.MGF1` and added it
to :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`. It will
be removed from ``MGF1`` in two releases per our :doc:`/api-stability`
policy.
* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SEED`
support.
* Added :class:`~cryptography.hazmat.primitives.cmac.CMAC`.
* Added decryption support to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`
and encryption support to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`.
* Added signature support to
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`
and verification support to
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`.
0.3 - 2014-03-27
~~~~~~~~~~~~~~~~
* Added :class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP`.
* Added :class:`~cryptography.hazmat.primitives.twofactor.totp.TOTP`.
* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.IDEA`
support.
* Added signature support to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`
and verification support to
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`.
* Moved test vectors to the new ``cryptography_vectors`` package.
0.2.2 - 2014-03-03
~~~~~~~~~~~~~~~~~~
* Removed a constant definition that was causing compilation problems with
specific versions of OpenSSL.
0.2.1 - 2014-02-22
~~~~~~~~~~~~~~~~~~
* Fix a bug where importing cryptography from multiple paths could cause
initialization to fail.
0.2 - 2014-02-20
~~~~~~~~~~~~~~~~
* Added :doc:`/hazmat/backends/commoncrypto`.
* Added initial :doc:`/hazmat/bindings/commoncrypto`.
* Removed ``register_cipher_adapter`` method from
:class:`~cryptography.hazmat.backends.interfaces.CipherBackend`.
* Added support for the OpenSSL backend under Windows.
* Improved thread-safety for the OpenSSL backend.
* Fixed compilation on systems where OpenSSL's ``ec.h`` header is not
available, such as CentOS.
* Added :class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC`.
* Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`.
* Added :doc:`/hazmat/backends/multibackend`.
* Set default random for the :doc:`/hazmat/backends/openssl` to the OS
random engine.
* Added :class:`~cryptography.hazmat.primitives.ciphers.algorithms.CAST5`
(CAST-128) support.
0.1 - 2014-01-08
~~~~~~~~~~~~~~~~
* Initial release.
.. _`master`: https://github.com/pyca/cryptography/
.. _`cffi`: https://cffi.readthedocs.io/

23
CONTRIBUTING.rst Normal file
View File

@ -0,0 +1,23 @@
Contributing to cryptography
============================
As an open source project, cryptography welcomes contributions of many forms.
Examples of contributions include:
* Code patches
* Documentation improvements
* Bug reports and patch reviews
Extensive contribution guidelines are available in the repository at
``docs/development/index.rst``, or online at:
https://cryptography.io/en/latest/development/
Security issues
---------------
To report a security issue, please follow the special `security reporting
guidelines`_, do not report them in the public issue tracker.
.. _`security reporting guidelines`: https://cryptography.io/en/latest/security/

7
LICENSE Normal file
View File

@ -0,0 +1,7 @@
This software is made available under the terms of *either* of the licenses
found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
under the terms of *both* these licenses.
The code used in the OpenSSL locking callback and OS random engine is derived
from the same in CPython itself, and is licensed under the terms of the PSF
License Agreement.

202
LICENSE.APACHE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

27
LICENSE.BSD Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) Individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of PyCA Cryptography nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

13
MANIFEST.in Normal file
View File

@ -0,0 +1,13 @@
include AUTHORS.rst
include CHANGELOG.rst
include CONTRIBUTING.rst
include LICENSE
include LICENSE.APACHE
include LICENSE.BSD
include README.rst
recursive-include docs *
recursive-include src/_cffi_src *.py *.c *.h
prune docs/_build
recursive-include tests *.py
recursive-exclude vectors *

94
PKG-INFO Normal file
View File

@ -0,0 +1,94 @@
Metadata-Version: 1.1
Name: cryptography
Version: 1.7.1
Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
Home-page: https://github.com/pyca/cryptography
Author: The cryptography developers
Author-email: cryptography-dev@python.org
License: BSD or Apache License, Version 2.0
Description: Cryptography
============
.. image:: https://img.shields.io/pypi/v/cryptography.svg
:target: https://pypi.python.org/pypi/cryptography/
:alt: Latest Version
.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
:target: https://cryptography.io
:alt: Latest Docs
.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master
:target: https://travis-ci.org/pyca/cryptography
.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master
:target: https://codecov.io/github/pyca/cryptography?branch=master
``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 2.6-2.7, Python 3.3+, and PyPy 2.6+.
``cryptography`` includes both high level recipes, and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests and
key derivation functions. For example, to encrypt something with
``cryptography``'s high level symmetric encryption recipe:
.. code-block:: pycon
>>> from cryptography.fernet import Fernet
>>> # Put this somewhere safe!
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
>>> token
'...'
>>> f.decrypt(token)
'A really secret message. Not for prying eyes.'
You can find more information in the `documentation`_.
You can install ``cryptography`` with:
.. code-block:: console
$ pip install cryptography
For full details see `the installation documentation`_.
Discussion
~~~~~~~~~~
If you run into bugs, you can file them in our `issue tracker`_.
We maintain a `cryptography-dev`_ mailing list for development discussion.
You can also join ``#cryptography-dev`` on Freenode to ask questions or get
involved.
.. _`documentation`: https://cryptography.io/
.. _`the installation documentation`: https://cryptography.io/en/latest/installation/
.. _`issue tracker`: https://github.com/pyca/cryptography/issues
.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX
Classifier: Operating System :: POSIX :: BSD
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Security :: Cryptography

64
README.rst Normal file
View File

@ -0,0 +1,64 @@
Cryptography
============
.. image:: https://img.shields.io/pypi/v/cryptography.svg
:target: https://pypi.python.org/pypi/cryptography/
:alt: Latest Version
.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
:target: https://cryptography.io
:alt: Latest Docs
.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master
:target: https://travis-ci.org/pyca/cryptography
.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master
:target: https://codecov.io/github/pyca/cryptography?branch=master
``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 2.6-2.7, Python 3.3+, and PyPy 2.6+.
``cryptography`` includes both high level recipes, and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests and
key derivation functions. For example, to encrypt something with
``cryptography``'s high level symmetric encryption recipe:
.. code-block:: pycon
>>> from cryptography.fernet import Fernet
>>> # Put this somewhere safe!
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
>>> token
'...'
>>> f.decrypt(token)
'A really secret message. Not for prying eyes.'
You can find more information in the `documentation`_.
You can install ``cryptography`` with:
.. code-block:: console
$ pip install cryptography
For full details see `the installation documentation`_.
Discussion
~~~~~~~~~~
If you run into bugs, you can file them in our `issue tracker`_.
We maintain a `cryptography-dev`_ mailing list for development discussion.
You can also join ``#cryptography-dev`` on Freenode to ask questions or get
involved.
.. _`documentation`: https://cryptography.io/
.. _`the installation documentation`: https://cryptography.io/en/latest/installation/
.. _`issue tracker`: https://github.com/pyca/cryptography/issues
.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev

153
docs/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Cryptography.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Cryptography.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Cryptography"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Cryptography"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

0
docs/_static/.keep vendored Normal file
View File

51
docs/api-stability.rst Normal file
View File

@ -0,0 +1,51 @@
API stability
=============
From its first release, ``cryptography`` will have a strong API stability
policy.
What does this policy cover?
----------------------------
This policy includes any API or behavior that is documented in this
documentation.
What does "stable" mean?
------------------------
* Public APIs will not be removed or renamed without providing a compatibility
alias.
* The behavior of existing APIs will not change.
What doesn't this policy cover?
-------------------------------
* We may add new features, things like the result of ``dir(obj))`` or the
contents of ``obj.__dict__`` may change.
* Objects are not guaranteed to be pickleable, and pickled objects from one
version of ``cryptography`` may not be loadable in future versions.
* Development versions of ``cryptography``. Before a feature is in a release,
it is not covered by this policy and may change.
Security
~~~~~~~~
One exception to our API stability policy is for security. We will violate this
policy as necessary in order to resolve a security issue or harden
``cryptography`` against a possible attack.
Deprecation
-----------
From time to time we will want to change the behavior of an API or remove it
entirely. In that case, here's how the process will work:
* In ``cryptography X.Y`` the feature exists.
* In ``cryptography X.Y+1`` using that feature will emit a
``PendingDeprecationWarning``.
* In ``cryptography X.Y+2`` using that feature will emit a
``DeprecationWarning``.
* In ``cryptography X.Y+3`` the feature will be removed or changed.
In short, code that runs without warnings will always continue to work for a
period of two releases.

1
docs/changelog.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../CHANGELOG.rst

20
docs/community.rst Normal file
View File

@ -0,0 +1,20 @@
Community
=========
You can find ``cryptography`` all over the web:
* `Mailing list`_
* `Source code`_
* `Issue tracker`_
* `Documentation`_
* IRC: ``#cryptography-dev`` on ``irc.freenode.net``
Wherever we interact, we strive to follow the `Python Community Code of
Conduct`_.
.. _`Mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`Source code`: https://github.com/pyca/cryptography
.. _`Issue tracker`: https://github.com/pyca/cryptography/issues
.. _`Documentation`: https://cryptography.io/
.. _`Python Community Code of Conduct`: https://www.python.org/psf/codeofconduct/

179
docs/conf.py Normal file
View File

@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
#
# Cryptography documentation build configuration file, created by
# sphinx-quickstart on Tue Aug 6 19:19:14 2013.
#
# This file is execfile()d with the current directory set to its containing dir
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
from __future__ import absolute_import, division, print_function
import os
import sys
try:
import sphinx_rtd_theme
except ImportError:
sphinx_rtd_theme = None
try:
from sphinxcontrib import spelling
except ImportError:
spelling = None
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.viewcode',
'cryptography-docs',
]
if spelling is not None:
extensions.append('sphinxcontrib.spelling')
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
nitpicky = True
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Cryptography'
copyright = '2013-2016, Individual Contributors'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
base_dir = os.path.join(os.path.dirname(__file__), os.pardir)
about = {}
with open(os.path.join(base_dir, "src", "cryptography", "__about__.py")) as f:
exec(f.read(), about)
version = release = about["__version__"]
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
# language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# -- Options for HTML output --------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
if sphinx_rtd_theme:
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
else:
html_theme = "default"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Output file base name for HTML help builder.
htmlhelp_basename = 'Cryptographydoc'
# -- Options for LaTeX output -------------------------------------------------
latex_elements = {
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [
('index', 'Cryptography.tex', 'Cryptography Documentation',
'Individual Contributors', 'manual'),
]
# -- Options for manual page output -------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'cryptography', 'Cryptography Documentation',
['Individual Contributors'], 1)
]
# -- Options for Texinfo output -----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Cryptography', 'Cryptography Documentation',
'Individual Contributors', 'Cryptography',
'One line description of project.',
'Miscellaneous'),
]
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/3': None}
epub_theme = 'epub'
# Retry requests in the linkcheck builder so that we're resillient against
# transient network errors.
linkcheck_retries = 2

70
docs/cryptography-docs.py Normal file
View File

@ -0,0 +1,70 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from docutils import nodes
from sphinx.util.compat import Directive, make_admonition
DANGER_MESSAGE = """
This is a "Hazardous Materials" module. You should **ONLY** use it if you're
100% absolutely sure that you know what you're doing because this module is
full of land mines, dragons, and dinosaurs with laser guns.
"""
DANGER_ALTERNATE = """
You may instead be interested in :doc:`{alternate}`.
"""
class HazmatDirective(Directive):
has_content = True
def run(self):
message = DANGER_MESSAGE
if self.content:
message += DANGER_ALTERNATE.format(alternate=self.content[0])
ad = make_admonition(
Hazmat,
self.name,
[],
self.options,
nodes.paragraph("", message),
self.lineno,
self.content_offset,
self.block_text,
self.state,
self.state_machine
)
ad[0].line = self.lineno
return ad
class Hazmat(nodes.Admonition, nodes.Element):
pass
def html_visit_hazmat_node(self, node):
return self.visit_admonition(node, "danger")
def latex_visit_hazmat_node(self, node):
return self.visit_admonition(node)
def depart_hazmat_node(self, node):
return self.depart_admonition(node)
def setup(app):
app.add_node(
Hazmat,
html=(html_visit_hazmat_node, depart_hazmat_node),
latex=(latex_visit_hazmat_node, depart_hazmat_node),
)
app.add_directive("hazmat", HazmatDirective)

View File

@ -0,0 +1,196 @@
C bindings
==========
C bindings are bindings to C libraries, using cffi_ whenever possible.
.. _cffi: https://cffi.readthedocs.io
Bindings live in :py:mod:`cryptography.hazmat.bindings`.
When modifying the bindings you will need to recompile the C extensions to
test the changes. This can be accomplished with ``pip install -e .`` in the
project root. If you do not do this a ``RuntimeError`` will be raised.
Style guide
-----------
Don't name parameters:
.. code-block:: c
/* Good */
long f(long);
/* Bad */
long f(long x);
...unless they're inside a struct:
.. code-block:: c
struct my_struct {
char *name;
int number;
...;
};
Include ``void`` if the function takes no arguments:
.. code-block:: c
/* Good */
long f(void);
/* Bad */
long f();
Wrap lines at 80 characters like so:
.. code-block:: c
/* Pretend this went to 80 characters */
long f(long, long,
int *)
Include a space after commas between parameters:
.. code-block:: c
/* Good */
long f(int, char *)
/* Bad */
long f(int,char *)
Use C-style ``/* */`` comments instead of C++-style ``//``:
.. code-block:: c
// Bad
/* Good */
Values set by ``#define`` should be assigned the appropriate type. If you see
this:
.. code-block:: c
#define SOME_INTEGER_LITERAL 0x0;
#define SOME_UNSIGNED_INTEGER_LITERAL 0x0001U;
#define SOME_STRING_LITERAL "hello";
...it should be added to the bindings like so:
.. code-block:: c
static const int SOME_INTEGER_LITERAL;
static const unsigned int SOME_UNSIGNED_INTEGER_LITERAL;
static const char *const SOME_STRING_LITERAL;
Adding constant, types, functions...
------------------------------------
You can create bindings for any name that exists in some version of
the library you're binding against. However, the project also has to
keep supporting older versions of the library. In order to achieve
this, binding modules have ``CUSTOMIZATIONS`` and
``CONDITIONAL_NAMES`` constants.
Let's say you want to enable quantum transmogrification. The upstream
library implements this as the following API::
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
typedef ... QM_TRANSMOGRIFICATION_CTX;
int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
To start, create a new constant that defines if the *actual* library
has the feature you want, and add it to ``TYPES``::
static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION;
This should start with ``Cryptography_``, since we're adding it in
this library. This prevents namespace collisions.
Then, define the actual features (constants, types, functions...) you
want to expose. If it's a constant, just add it to ``TYPES``::
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT;
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT;
If it's a struct, add it to ``TYPES`` as well. The following is an
opaque struct::
typedef ... QM_TRANSMOGRIFICATION_CTX;
... but you can also make some or all items in the struct accessible::
typedef struct {
/* Fundamental constant k for your particular universe */
BIGNUM *k;
...;
} QM_TRANSMOGRIFICATION_CTX;
Confusingly, functions that aren't always available on all supported
versions of the library, should be defined in ``MACROS`` and *not* in
``FUNCTIONS``. Fortunately, you just have to copy the signature::
int QM_transmogrify(QM_TRANSMOGRIFICATION_CTX *, int);
Then, we define the ``CUSTOMIZATIONS`` entry. To do that, we have to
come up with a C preprocessor expression that decides whether or not a
feature exists in the library. For example::
#ifdef QM_transmogrify
Then, we set the flag that signifies the feature exists::
static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 1;
Otherwise, we set that flag to 0::
#else
static const long Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION = 0;
Then, in that ``#else`` block, we define the names that aren't
available as dummy values. For an integer constant, use 0::
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT = 0;
static const int QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT = 0;
For a function, it's a bit trickier. You have to define a function
pointer of the appropriate type to be NULL::
int (*QM_transmogrify)(QM_TRANSMOGRIFICATION_CTX *, int) = NULL;
(To do that, copy the signature, put a ``*`` in front of the function
name and wrap it in parentheses, and then put ``= NULL`` at the end).
Note how types don't need to be conditionally defined, as long as all
the necessarily type definitions are in place.
Finally, add an entry to ``CONDITIONAL_NAMES`` with all of the things
you want to conditionally export::
CONDITIONAL_NAMES = {
...
"Cryptography_HAS_QUANTUM_TRANSMOGRIFICATION": [
"QM_TRANSMOGRIFICATION_ALIGNMENT_LEFT",
"QM_TRANSMOGRIFICATION_ALIGNMENT_RIGHT",
"QM_transmogrify"
]
}
Caveats
~~~~~~~
Sometimes, a set of loosely related features are added in the same
version, and it's impractical to create ``#ifdef`` statements for each
one. In that case, it may make sense to either check for a particular
version. For example, to check for OpenSSL 1.0.0 or newer::
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
Sometimes, the version of a library on a particular platform will have
features that you thought it wouldn't, based on its version.
Occasionally, packagers appear to ship arbitrary VCS checkouts. As a
result, sometimes you may have to add separate ``#ifdef`` statements
for particular features. This kind of issue is typically only caught
by running the tests on a wide variety of systems, which is the job of
our continuous integration infrastructure.

View File

@ -0,0 +1,30 @@
ARC4 vector creation
====================
This page documents the code that was used to generate the ARC4 test
vectors for key lengths not available in RFC 6229. All the vectors
were generated using OpenSSL and verified with Go.
Creation
--------
``cryptography`` was modified to support ARC4 key lengths not listed
in RFC 6229. Then the following Python script was run to generate the
vector files.
.. literalinclude:: /development/custom-vectors/arc4/generate_arc4.py
Download link: :download:`generate_arc4.py
</development/custom-vectors/arc4/generate_arc4.py>`
Verification
------------
The following Go code was used to verify the vectors.
.. literalinclude:: /development/custom-vectors/arc4/verify_arc4.go
:language: go
Download link: :download:`verify_arc4.go
</development/custom-vectors/arc4/verify_arc4.go>`

View File

@ -0,0 +1,98 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import binascii
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers import algorithms
_RFC6229_KEY_MATERIALS = [
(True,
8 * '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20'),
(False,
8 * '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a')
]
_RFC6229_OFFSETS = [
0,
16,
240,
256,
496,
512,
752,
768,
1008,
1024,
1520,
1536,
2032,
2048,
3056,
3072,
4080,
4096
]
_SIZES_TO_GENERATE = [
160
]
def _key_for_size(size, keyinfo):
msb, key = keyinfo
if msb:
return key[:size // 4]
else:
return key[-size // 4:]
def _build_vectors():
count = 0
output = []
key = None
plaintext = binascii.unhexlify(32 * '0')
for size in _SIZES_TO_GENERATE:
for keyinfo in _RFC6229_KEY_MATERIALS:
key = _key_for_size(size, keyinfo)
cipher = ciphers.Cipher(
algorithms.ARC4(binascii.unhexlify(key)),
None,
default_backend())
encryptor = cipher.encryptor()
current_offset = 0
for offset in _RFC6229_OFFSETS:
if offset % 16 != 0:
raise ValueError(
"Offset {} is not evenly divisible by 16"
.format(offset))
while current_offset < offset:
encryptor.update(plaintext)
current_offset += len(plaintext)
output.append("\nCOUNT = {}".format(count))
count += 1
output.append("KEY = {}".format(key))
output.append("OFFSET = {}".format(offset))
output.append("PLAINTEXT = {}".format(
binascii.hexlify(plaintext)))
output.append("CIPHERTEXT = {}".format(
binascii.hexlify(encryptor.update(plaintext))))
current_offset += len(plaintext)
assert not encryptor.finalize()
return "\n".join(output)
def _write_file(data, filename):
with open(filename, 'w') as f:
f.write(data)
if __name__ == '__main__':
_write_file(_build_vectors(), 'arc4.txt')

View File

@ -0,0 +1,111 @@
package main
import (
"bufio"
"bytes"
"crypto/rc4"
"encoding/hex"
"fmt"
"os"
"strconv"
"strings"
)
func unhexlify(s string) []byte {
bytes, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return bytes
}
type vectorArgs struct {
count string
offset uint64
key string
plaintext string
ciphertext string
}
type vectorVerifier interface {
validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte)
}
type arc4Verifier struct{}
func (o arc4Verifier) validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte) {
if offset%16 != 0 || len(plaintext) != 16 || len(expectedCiphertext) != 16 {
panic(fmt.Errorf("Unexpected input value encountered: offset=%v; len(plaintext)=%v; len(expectedCiphertext)=%v",
offset,
len(plaintext),
len(expectedCiphertext)))
}
stream, err := rc4.NewCipher(key)
if err != nil {
panic(err)
}
var currentOffset uint64 = 0
ciphertext := make([]byte, len(plaintext))
for currentOffset <= offset {
stream.XORKeyStream(ciphertext, plaintext)
currentOffset += uint64(len(plaintext))
}
if !bytes.Equal(ciphertext, expectedCiphertext) {
panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n",
count,
hex.EncodeToString(expectedCiphertext),
hex.EncodeToString(ciphertext)))
}
}
func validateVectors(verifier vectorVerifier, filename string) {
vectors, err := os.Open(filename)
if err != nil {
panic(err)
}
defer vectors.Close()
var segments []string
var vector *vectorArgs
scanner := bufio.NewScanner(vectors)
for scanner.Scan() {
segments = strings.Split(scanner.Text(), " = ")
switch {
case strings.ToUpper(segments[0]) == "COUNT":
if vector != nil {
verifier.validate(vector.count,
vector.offset,
unhexlify(vector.key),
unhexlify(vector.plaintext),
unhexlify(vector.ciphertext))
}
vector = &vectorArgs{count: segments[1]}
case strings.ToUpper(segments[0]) == "OFFSET":
vector.offset, err = strconv.ParseUint(segments[1], 10, 64)
if err != nil {
panic(err)
}
case strings.ToUpper(segments[0]) == "KEY":
vector.key = segments[1]
case strings.ToUpper(segments[0]) == "PLAINTEXT":
vector.plaintext = segments[1]
case strings.ToUpper(segments[0]) == "CIPHERTEXT":
vector.ciphertext = segments[1]
}
}
if vector != nil {
verifier.validate(vector.count,
vector.offset,
unhexlify(vector.key),
unhexlify(vector.plaintext),
unhexlify(vector.ciphertext))
}
}
func main() {
validateVectors(arc4Verifier{}, "vectors/cryptography_vectors/ciphers/ARC4/arc4.txt")
fmt.Println("ARC4 OK.")
}

View File

@ -0,0 +1,31 @@
CAST5 vector creation
=====================
This page documents the code that was used to generate the CAST5 CBC, CFB, OFB,
and CTR test vectors as well as the code used to verify them against another
implementation. The CBC, CFB, and OFB vectors were generated using OpenSSL and
the CTR vectors were generated using Apple's CommonCrypto. All the generated
vectors were verified with Go.
Creation
--------
``cryptography`` was modified to support CAST5 in CBC, CFB, and OFB modes. Then
the following Python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/cast5/generate_cast5.py
Download link: :download:`generate_cast5.py
</development/custom-vectors/cast5/generate_cast5.py>`
Verification
------------
The following Go code was used to verify the vectors.
.. literalinclude:: /development/custom-vectors/cast5/verify_cast5.go
:language: go
Download link: :download:`verify_cast5.go
</development/custom-vectors/cast5/verify_cast5.go>`

View File

@ -0,0 +1,68 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import binascii
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import algorithms, base, modes
def encrypt(mode, key, iv, plaintext):
cipher = base.Cipher(
algorithms.CAST5(binascii.unhexlify(key)),
mode(binascii.unhexlify(iv)),
default_backend()
)
encryptor = cipher.encryptor()
ct = encryptor.update(binascii.unhexlify(plaintext))
ct += encryptor.finalize()
return binascii.hexlify(ct)
def build_vectors(mode, filename):
vector_file = open(filename, "r")
count = 0
output = []
key = None
iv = None
plaintext = None
for line in vector_file:
line = line.strip()
if line.startswith("KEY"):
if count != 0:
output.append("CIPHERTEXT = {}".format(
encrypt(mode, key, iv, plaintext))
)
output.append("\nCOUNT = {}".format(count))
count += 1
name, key = line.split(" = ")
output.append("KEY = {}".format(key))
elif line.startswith("IV"):
name, iv = line.split(" = ")
iv = iv[0:16]
output.append("IV = {}".format(iv))
elif line.startswith("PLAINTEXT"):
name, plaintext = line.split(" = ")
output.append("PLAINTEXT = {}".format(plaintext))
output.append("CIPHERTEXT = {}".format(encrypt(mode, key, iv, plaintext)))
return "\n".join(output)
def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
cbc_path = "tests/hazmat/primitives/vectors/ciphers/AES/CBC/CBCMMT128.rsp"
write_file(build_vectors(modes.CBC, cbc_path), "cast5-cbc.txt")
ofb_path = "tests/hazmat/primitives/vectors/ciphers/AES/OFB/OFBMMT128.rsp"
write_file(build_vectors(modes.OFB, ofb_path), "cast5-ofb.txt")
cfb_path = "tests/hazmat/primitives/vectors/ciphers/AES/CFB/CFB128MMT128.rsp"
write_file(build_vectors(modes.CFB, cfb_path), "cast5-cfb.txt")
ctr_path = "tests/hazmat/primitives/vectors/ciphers/AES/CTR/aes-128-ctr.txt"
write_file(build_vectors(modes.CTR, ctr_path), "cast5-ctr.txt")

View File

@ -0,0 +1,164 @@
package main
import (
"bufio"
"bytes"
"code.google.com/p/go.crypto/cast5"
"crypto/cipher"
"encoding/hex"
"fmt"
"os"
"strings"
)
func unhexlify(s string) []byte {
bytes, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return bytes
}
type vectorArgs struct {
count string
key string
iv string
plaintext string
ciphertext string
}
type vectorVerifier interface {
validate(count string, key, iv, plaintext, expectedCiphertext []byte)
}
type ofbVerifier struct{}
func (o ofbVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
block, err := cast5.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewOFB(block, iv)
stream.XORKeyStream(ciphertext, plaintext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n",
count,
hex.EncodeToString(expectedCiphertext),
hex.EncodeToString(ciphertext)))
}
}
type cbcVerifier struct{}
func (o cbcVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
block, err := cast5.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext))
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, plaintext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n",
count,
hex.EncodeToString(expectedCiphertext),
hex.EncodeToString(ciphertext)))
}
}
type cfbVerifier struct{}
func (o cfbVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
block, err := cast5.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(ciphertext, plaintext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n",
count,
hex.EncodeToString(expectedCiphertext),
hex.EncodeToString(ciphertext)))
}
}
type ctrVerifier struct{}
func (o ctrVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
block, err := cast5.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, len(plaintext))
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext, plaintext)
if !bytes.Equal(ciphertext, expectedCiphertext) {
panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n",
count,
hex.EncodeToString(expectedCiphertext),
hex.EncodeToString(ciphertext)))
}
}
func validateVectors(verifier vectorVerifier, filename string) {
vectors, err := os.Open(filename)
if err != nil {
panic(err)
}
defer vectors.Close()
var segments []string
var vector *vectorArgs
scanner := bufio.NewScanner(vectors)
for scanner.Scan() {
segments = strings.Split(scanner.Text(), " = ")
switch {
case strings.ToUpper(segments[0]) == "COUNT":
if vector != nil {
verifier.validate(vector.count,
unhexlify(vector.key),
unhexlify(vector.iv),
unhexlify(vector.plaintext),
unhexlify(vector.ciphertext))
}
vector = &vectorArgs{count: segments[1]}
case strings.ToUpper(segments[0]) == "IV":
vector.iv = segments[1][:16]
case strings.ToUpper(segments[0]) == "KEY":
vector.key = segments[1]
case strings.ToUpper(segments[0]) == "PLAINTEXT":
vector.plaintext = segments[1]
case strings.ToUpper(segments[0]) == "CIPHERTEXT":
vector.ciphertext = segments[1]
}
}
}
func main() {
validateVectors(ofbVerifier{},
"vectors/cryptography_vectors/ciphers/CAST5/cast5-ofb.txt")
fmt.Println("OFB OK.")
validateVectors(cfbVerifier{},
"vectors/cryptography_vectors/ciphers/CAST5/cast5-cfb.txt")
fmt.Println("CFB OK.")
validateVectors(cbcVerifier{},
"vectors/cryptography_vectors/ciphers/CAST5/cast5-cbc.txt")
fmt.Println("CBC OK.")
validateVectors(ctrVerifier{},
"vectors/cryptography_vectors/ciphers/CAST5/cast5-ctr.txt")
fmt.Println("CTR OK.")
}

View File

@ -0,0 +1,32 @@
IDEA vector creation
=====================
This page documents the code that was used to generate the IDEA CBC, CFB, and
OFB test vectors as well as the code used to verify them against another
implementation. The vectors were generated using OpenSSL and verified with
`Botan`_.
Creation
--------
``cryptography`` was modified to support IDEA in CBC, CFB, and OFB modes. Then
the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/idea/generate_idea.py
Download link: :download:`generate_idea.py
</development/custom-vectors/idea/generate_idea.py>`
Verification
------------
The following Python code was used to verify the vectors using the `Botan`_
project's Python bindings.
.. literalinclude:: /development/custom-vectors/idea/verify_idea.py
Download link: :download:`verify_idea.py
</development/custom-vectors/idea/verify_idea.py>`
.. _`Botan`: https://botan.randombit.net

View File

@ -0,0 +1,61 @@
import binascii
from cryptography.hazmat.backends.openssl.backend import backend
from cryptography.hazmat.primitives.ciphers import algorithms, base, modes
def encrypt(mode, key, iv, plaintext):
cipher = base.Cipher(
algorithms.IDEA(binascii.unhexlify(key)),
mode(binascii.unhexlify(iv)),
backend
)
encryptor = cipher.encryptor()
ct = encryptor.update(binascii.unhexlify(plaintext))
ct += encryptor.finalize()
return binascii.hexlify(ct)
def build_vectors(mode, filename):
with open(filename, "r") as f:
vector_file = f.read().splitlines()
count = 0
output = []
key = None
iv = None
plaintext = None
for line in vector_file:
line = line.strip()
if line.startswith("KEY"):
if count != 0:
output.append("CIPHERTEXT = {0}".format(
encrypt(mode, key, iv, plaintext))
)
output.append("\nCOUNT = {0}".format(count))
count += 1
name, key = line.split(" = ")
output.append("KEY = {0}".format(key))
elif line.startswith("IV"):
name, iv = line.split(" = ")
iv = iv[0:16]
output.append("IV = {0}".format(iv))
elif line.startswith("PLAINTEXT"):
name, plaintext = line.split(" = ")
output.append("PLAINTEXT = {0}".format(plaintext))
output.append("CIPHERTEXT = {0}".format(encrypt(mode, key, iv, plaintext)))
return "\n".join(output)
def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
CBC_PATH = "tests/hazmat/primitives/vectors/ciphers/AES/CBC/CBCMMT128.rsp"
write_file(build_vectors(modes.CBC, CBC_PATH), "idea-cbc.txt")
OFB_PATH = "tests/hazmat/primitives/vectors/ciphers/AES/OFB/OFBMMT128.rsp"
write_file(build_vectors(modes.OFB, OFB_PATH), "idea-ofb.txt")
CFB_PATH = "tests/hazmat/primitives/vectors/ciphers/AES/CFB/CFB128MMT128.rsp"
write_file(build_vectors(modes.CFB, CFB_PATH), "idea-cfb.txt")

View File

@ -0,0 +1,39 @@
import binascii
import botan
from tests.utils import load_nist_vectors
BLOCK_SIZE = 64
def encrypt(mode, key, iv, plaintext):
encryptor = botan.Cipher("IDEA/{0}/NoPadding".format(mode), "encrypt",
binascii.unhexlify(key))
cipher_text = encryptor.cipher(binascii.unhexlify(plaintext),
binascii.unhexlify(iv))
return binascii.hexlify(cipher_text)
def verify_vectors(mode, filename):
with open(filename, "r") as f:
vector_file = f.read().splitlines()
vectors = load_nist_vectors(vector_file)
for vector in vectors:
ct = encrypt(
mode,
vector["key"],
vector["iv"],
vector["plaintext"]
)
assert ct == vector["ciphertext"]
cbc_path = "tests/hazmat/primitives/vectors/ciphers/IDEA/idea-cbc.txt"
verify_vectors("CBC", cbc_path)
ofb_path = "tests/hazmat/primitives/vectors/ciphers/IDEA/idea-ofb.txt"
verify_vectors("OFB", ofb_path)
cfb_path = "tests/hazmat/primitives/vectors/ciphers/IDEA/idea-cfb.txt"
verify_vectors("CFB", cfb_path)

View File

@ -0,0 +1,56 @@
RSA OAEP SHA2 vector creation
=============================
This page documents the code that was used to generate the RSA OAEP SHA2
test vectors as well as code used to verify them against another
implementation.
Creation
--------
``cryptography`` was modified to allow the use of SHA2 in OAEP encryption. Then
the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py
Download link: :download:`generate_rsa_oaep_sha2.py
</development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py>`
Verification
------------
A Java 8 program was written using `Bouncy Castle`_ to load and verify the test
vectors.
.. literalinclude:: /development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java
Download link: :download:`VerifyRSAOAEPSHA2.java
</development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java>`
Using the Verifier
------------------
Download and install the `Java 8 SDK`_. Initial verification was performed
using ``jdk-8u77-macosx-x64.dmg``.
Download the latest `Bouncy Castle`_ JAR. Initial verification was performed
using ``bcprov-jdk15on-154.jar``.
Set the ``-classpath`` to include the Bouncy Castle jar and the path to
``VerifyRSAOAEPSHA2.java`` and compile the program.
.. code-block:: console
$ javac -classpath ~/Downloads/bcprov-jdk15on-154.jar:./ VerifyRSAOAEPSHA2.java
Finally, run the program with the path to the SHA-2 vectors:
.. code-block:: console
$ java -classpath ~/Downloads/bcprov-jdk15on-154.jar:./ VerifyRSAOAEPSHA2
.. _`Bouncy Castle`: https://www.bouncycastle.org/
.. _`Java 8 SDK`: https://www.oracle.com/technetwork/java/javase/downloads/index.html

View File

@ -0,0 +1,416 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.RSAPrivateKeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.xml.bind.DatatypeConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
class TestVectorData {
public BigInteger pub_key_modulus;
public BigInteger pub_key_exponent;
public BigInteger priv_key_public_exponent;
public BigInteger priv_key_modulus;
public BigInteger priv_key_exponent;
public BigInteger priv_key_prime_1;
public BigInteger priv_key_prime_2;
public BigInteger priv_key_prime_exponent_1;
public BigInteger priv_key_prime_exponent_2;
public BigInteger priv_key_coefficient;
public byte[] plaintext;
public byte[] ciphertext;
}
class TestVectorLoader {
private static final String FILE_HEADER = "# RSA OAEP SHA2 vectors built";
private static final String EXAMPLE_HEADER = "# =====";
private static final String EXAMPLE = "# Example";
private static final String PUBLIC_KEY = "# Public key";
private static final String PUB_MODULUS = "# Modulus:";
private static final String PUB_EXPONENT = "# Exponent:";
private static final String PRIVATE_KEY = "# Private key";
private static final String PRIV_MODULUS = "# Modulus:";
private static final String PRIV_PUBLIC_EXPONENT = "# Public exponent:";
private static final String PRIV_EXPONENT = "# Exponent:";
private static final String PRIV_PRIME_1 = "# Prime 1:";
private static final String PRIV_PRIME_2 = "# Prime 2:";
private static final String PRIV_PRIME_EXPONENT_1 = "# Prime exponent 1:";
private static final String PRIV_PRIME_EXPONENT_2 = "# Prime exponent 2:";
private static final String PRIV_COEFFICIENT = "# Coefficient:";
private static final String OAEP_EXAMPLE_HEADER = "# OAEP Example";
private static final String MESSAGE = "# Message:";
private static final String ENCRYPTION = "# Encryption:";
private BufferedReader m_reader = null;
private FileReader m_file_reader = null;
private TestVectorData m_data = null;
TestVectorLoader() {
}
protected void finalize() {
close();
}
public void open(String path) throws IOException {
close();
m_file_reader = new FileReader(path);
m_reader = new BufferedReader(m_file_reader);
m_data = new TestVectorData();
}
public void close() {
try {
if (m_reader != null) {
m_reader.close();
m_reader = null;
}
if (m_file_reader != null) {
m_file_reader.close();
m_file_reader = null;
}
m_data = null;
} catch (IOException e) {
System.out.println("Exception closing files");
e.printStackTrace();
}
}
public TestVectorData loadNextTest() throws IOException {
if (m_file_reader == null || m_reader == null || m_data == null) {
throw new IOException("A test vector file must be opened first");
}
String line = m_reader.readLine();
if (line == null) {
// end of file
return null;
}
if (line.startsWith(FILE_HEADER)) {
// start of file
skipFileHeader(m_reader);
line = m_reader.readLine();
}
if (line.startsWith(OAEP_EXAMPLE_HEADER)) {
// Next example, keep existing keys and load next message
loadMessage(m_reader, m_data);
return m_data;
}
// otherwise it's a new example
if (!line.startsWith(EXAMPLE_HEADER)) {
throw new IOException("Test Header Missing");
}
startNewTest(m_reader);
m_data = new TestVectorData();
line = m_reader.readLine();
if (!line.startsWith(PUBLIC_KEY))
throw new IOException("Public Key Missing");
loadPublicKey(m_reader, m_data);
line = m_reader.readLine();
if (!line.startsWith(PRIVATE_KEY))
throw new IOException("Private Key Missing");
loadPrivateKey(m_reader, m_data);
line = m_reader.readLine();
if (!line.startsWith(OAEP_EXAMPLE_HEADER))
throw new IOException("Message Missing");
loadMessage(m_reader, m_data);
return m_data;
}
private byte[] unhexlify(String line) {
byte[] bytes = DatatypeConverter.parseHexBinary(line);
return bytes;
}
private BigInteger readBigInteger(BufferedReader br) throws IOException {
return new BigInteger(br.readLine(), 16);
}
private void skipFileHeader(BufferedReader br) throws IOException {
br.readLine(); // # # Derived from the NIST OAEP SHA1 vectors
br.readLine(); // # # Verified against the Bouncy Castle OAEP SHA2 implementation
br.readLine(); // #
}
private void startNewTest(BufferedReader br) throws IOException {
String line = br.readLine();
if (!line.startsWith(EXAMPLE))
throw new IOException("Example Header Missing");
}
private void loadPublicKey(BufferedReader br, TestVectorData data) throws IOException {
String line = br.readLine();
if (!line.startsWith(PUB_MODULUS))
throw new IOException("Public Key Modulus Missing");
data.pub_key_modulus = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PUB_EXPONENT))
throw new IOException("Public Key Exponent Missing");
data.pub_key_exponent = readBigInteger(br);
}
private void loadPrivateKey(BufferedReader br, TestVectorData data) throws IOException {
String line = br.readLine();
if (!line.startsWith(PRIV_MODULUS))
throw new IOException("Private Key Modulus Missing");
data.priv_key_modulus = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_PUBLIC_EXPONENT))
throw new IOException("Private Key Public Exponent Missing");
data.priv_key_public_exponent = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_EXPONENT))
throw new IOException("Private Key Exponent Missing");
data.priv_key_exponent = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_PRIME_1))
throw new IOException("Private Key Prime 1 Missing");
data.priv_key_prime_1 = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_PRIME_2))
throw new IOException("Private Key Prime 2 Missing");
data.priv_key_prime_2 = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_PRIME_EXPONENT_1))
throw new IOException("Private Key Prime Exponent 1 Missing");
data.priv_key_prime_exponent_1 = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_PRIME_EXPONENT_2))
throw new IOException("Private Key Prime Exponent 2 Missing");
data.priv_key_prime_exponent_2 = readBigInteger(br);
line = br.readLine();
if (!line.startsWith(PRIV_COEFFICIENT))
throw new IOException("Private Key Coefficient Missing");
data.priv_key_coefficient = readBigInteger(br);
}
private void loadMessage(BufferedReader br, TestVectorData data) throws IOException {
String line = br.readLine();
if (!line.startsWith(MESSAGE))
throw new IOException("Plaintext Missing");
data.plaintext = unhexlify(br.readLine());
line = br.readLine();
if (!line.startsWith(ENCRYPTION))
throw new IOException("Ciphertext Missing");
data.ciphertext = unhexlify(br.readLine());
}
}
public class VerifyRSAOAEPSHA2 {
public enum SHAHash {
SHA1, SHA224, SHA256, SHA384, SHA512
}
private SHAHash m_mgf1_hash;
private SHAHash m_alg_hash;
private Cipher m_cipher;
private PrivateKey m_private_key;
private AlgorithmParameters m_algo_param;
VerifyRSAOAEPSHA2(SHAHash mgf1_hash, SHAHash alg_hash, TestVectorData test_data) throws Exception {
m_mgf1_hash = mgf1_hash;
m_alg_hash = alg_hash;
MGF1ParameterSpec mgf1_spec = getMGF1ParameterSpec(m_mgf1_hash);
AlgorithmParameterSpec algo_param_spec = getAlgorithmParameterSpec(m_alg_hash, mgf1_spec);
m_algo_param = AlgorithmParameters.getInstance("OAEP");
m_algo_param.init(algo_param_spec);
m_private_key = loadPrivateKey(test_data);
m_cipher = getCipher(m_alg_hash);
}
private Cipher getCipher(SHAHash alg_hash) throws GeneralSecurityException {
Cipher cipher = null;
switch (alg_hash) {
case SHA1:
cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", "BC");
break;
case SHA224:
cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-224andMGF1Padding", "BC");
break;
case SHA256:
cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding", "BC");
break;
case SHA384:
cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-384andMGF1Padding", "BC");
break;
case SHA512:
cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-512andMGF1Padding", "BC");
break;
}
return cipher;
}
private MGF1ParameterSpec getMGF1ParameterSpec(SHAHash mgf1_hash) {
MGF1ParameterSpec mgf1 = null;
switch (mgf1_hash) {
case SHA1:
mgf1 = MGF1ParameterSpec.SHA1;
break;
case SHA224:
mgf1 = MGF1ParameterSpec.SHA224;
break;
case SHA256:
mgf1 = MGF1ParameterSpec.SHA256;
break;
case SHA384:
mgf1 = MGF1ParameterSpec.SHA384;
break;
case SHA512:
mgf1 = MGF1ParameterSpec.SHA512;
break;
}
return mgf1;
}
private AlgorithmParameterSpec getAlgorithmParameterSpec(SHAHash alg_hash, MGF1ParameterSpec mgf1_spec) {
OAEPParameterSpec oaep_spec = null;
switch (alg_hash) {
case SHA1:
oaep_spec = new OAEPParameterSpec("SHA1", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
break;
case SHA224:
oaep_spec = new OAEPParameterSpec("SHA-224", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
break;
case SHA256:
oaep_spec = new OAEPParameterSpec("SHA-256", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
break;
case SHA384:
oaep_spec = new OAEPParameterSpec("SHA-384", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
break;
case SHA512:
oaep_spec = new OAEPParameterSpec("SHA-512", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
break;
}
return oaep_spec;
}
private PrivateKey loadPrivateKey(TestVectorData test_data) throws Exception {
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(test_data.priv_key_modulus, test_data.priv_key_exponent);
return kf.generatePrivate(keySpec);
}
public void testDecrypt(byte[] plaintext, byte[] ciphertext) throws Exception {
System.out.println("Verifying OAEP with mgf1_hash: " + m_mgf1_hash + " alg_hash: " + m_alg_hash + " - "
+ ciphertext.length + " bytes ciphertext - "
+ plaintext.length + " bytes plaintext");
m_cipher.init(Cipher.DECRYPT_MODE, m_private_key, m_algo_param);
byte[] java_plaintext = m_cipher.doFinal(ciphertext);
if (Arrays.equals(java_plaintext, plaintext) == false) {
throw new Exception("Verification failure - plaintext does not match after decryption.");
}
}
public static void main(String[] args) {
Security.addProvider(new BouncyCastleProvider());
// assume current directory if no path given on command line
String vector_path = "./vectors/cryptography_vectors/asymmetric/RSA/oaep-custom";
if (args.length > 0) {
vector_path = args[0];
}
System.out.println("Vector file path: " + vector_path);
try {
// loop over each combination of hash loading the vector file
// to verify for each
for (SHAHash mgf1_hash : SHAHash.values()) {
for (SHAHash alg_hash : SHAHash.values()) {
if (mgf1_hash.name().toLowerCase().equals("sha1") &&
alg_hash.name().toLowerCase().equals("sha1")) {
continue;
}
String filename = "oaep-" + mgf1_hash.name().toLowerCase() +
"-" + alg_hash.name().toLowerCase() + ".txt";
System.out.println("Loading " + filename + "...");
TestVectorLoader loader = new TestVectorLoader();
loader.open(vector_path + filename);
TestVectorData test_data;
// load each test in the file and verify
while ((test_data = loader.loadNextTest()) != null) {
VerifyRSAOAEPSHA2 verify = new VerifyRSAOAEPSHA2(mgf1_hash, alg_hash, test_data);
verify.testDecrypt(test_data.plaintext, test_data.ciphertext);
}
System.out.println("Verifying " + filename + " completed successfully.");
}
}
System.out.println("All verification completed successfully");
} catch (Exception e) {
// if any exception is thrown the verification has failed
e.printStackTrace();
System.out.println("Verification Failed!");
}
}
}

View File

@ -0,0 +1,128 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import binascii
import itertools
import os
from cryptography.hazmat.backends.openssl.backend import backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from tests.utils import load_pkcs1_vectors, load_vectors_from_file
def build_vectors(mgf1alg, hashalg, filename):
vectors = load_vectors_from_file(filename, load_pkcs1_vectors)
output = []
for vector in vectors:
# RSA keys for this must be long enough to accommodate the length of
# the underlying hash function. This means we can't use the keys from
# the sha1 test vectors for sha512 tests because 1024-bit keys are too
# small. Instead we parse the vectors for the test cases, then
# generate our own 2048-bit keys for each.
private, _ = vector
skey = rsa.generate_private_key(65537, 2048, backend)
pn = skey.private_numbers()
examples = private["examples"]
output.append(b"# =============================================")
output.append(b"# Example")
output.append(b"# Public key")
output.append(b"# Modulus:")
output.append(format(pn.public_numbers.n, "x"))
output.append(b"# Exponent:")
output.append(format(pn.public_numbers.e, "x"))
output.append(b"# Private key")
output.append(b"# Modulus:")
output.append(format(pn.public_numbers.n, "x"))
output.append(b"# Public exponent:")
output.append(format(pn.public_numbers.e, "x"))
output.append(b"# Exponent:")
output.append(format(pn.d, "x"))
output.append(b"# Prime 1:")
output.append(format(pn.p, "x"))
output.append(b"# Prime 2:")
output.append(format(pn.q, "x"))
output.append(b"# Prime exponent 1:")
output.append(format(pn.dmp1, "x"))
output.append(b"# Prime exponent 2:")
output.append(format(pn.dmq1, "x"))
output.append(b"# Coefficient:")
output.append(format(pn.iqmp, "x"))
pkey = skey.public_key()
vectorkey = rsa.RSAPrivateNumbers(
p=private["p"],
q=private["q"],
d=private["private_exponent"],
dmp1=private["dmp1"],
dmq1=private["dmq1"],
iqmp=private["iqmp"],
public_numbers=rsa.RSAPublicNumbers(
e=private["public_exponent"],
n=private["modulus"]
)
).private_key(backend)
count = 1
for example in examples:
message = vectorkey.decrypt(
binascii.unhexlify(example["encryption"]),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
assert message == binascii.unhexlify(example["message"])
ct = pkey.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=mgf1alg),
algorithm=hashalg,
label=None
)
)
output.append(
b"# OAEP Example {0} alg={1} mgf1={2}".format(
count, hashalg.name, mgf1alg.name
)
)
count += 1
output.append(b"# Message:")
output.append(example["message"])
output.append(b"# Encryption:")
output.append(binascii.hexlify(ct))
return b"\n".join(output)
def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
oaep_path = os.path.join(
"asymmetric", "RSA", "pkcs-1v2-1d2-vec", "oaep-vect.txt"
)
hashalgs = [
hashes.SHA1(),
hashes.SHA224(),
hashes.SHA256(),
hashes.SHA384(),
hashes.SHA512(),
]
for hashtuple in itertools.product(hashalgs, hashalgs):
if (
isinstance(hashtuple[0], hashes.SHA1) and
isinstance(hashtuple[1], hashes.SHA1)
):
continue
write_file(
build_vectors(hashtuple[0], hashtuple[1], oaep_path),
"oaep-{0}-{1}.txt".format(hashtuple[0].name, hashtuple[1].name)
)

View File

@ -0,0 +1,32 @@
SECP256K1 vector creation
=========================
This page documents the code that was used to generate the SECP256K1 elliptic
curve test vectors as well as code used to verify them against another
implementation.
Creation
--------
The vectors are generated using a `pure Python ecdsa`_ implementation. The test
messages and combinations of algorithms are derived from the NIST vector data.
.. literalinclude:: /development/custom-vectors/secp256k1/generate_secp256k1.py
Download link: :download:`generate_secp256k1.py
</development/custom-vectors/secp256k1/generate_secp256k1.py>`
Verification
------------
``cryptography`` was modified to support the SECP256K1 curve. Then
the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/secp256k1/verify_secp256k1.py
Download link: :download:`verify_secp256k1.py
</development/custom-vectors/secp256k1/verify_secp256k1.py>`
.. _`pure Python ecdsa`: https://pypi.python.org/pypi/ecdsa

View File

@ -0,0 +1,90 @@
from __future__ import absolute_import, print_function
import hashlib
import os
from binascii import hexlify
from collections import defaultdict
from ecdsa import SECP256k1, SigningKey
from ecdsa.util import sigdecode_der, sigencode_der
from cryptography_vectors import open_vector_file
from tests.utils import (
load_fips_ecdsa_signing_vectors, load_vectors_from_file
)
HASHLIB_HASH_TYPES = {
"SHA-1": hashlib.sha1,
"SHA-224": hashlib.sha224,
"SHA-256": hashlib.sha256,
"SHA-384": hashlib.sha384,
"SHA-512": hashlib.sha512,
}
class TruncatedHash(object):
def __init__(self, hasher):
self.hasher = hasher
def __call__(self, data):
self.hasher.update(data)
return self
def digest(self):
return self.hasher.digest()[:256 // 8]
def build_vectors(fips_vectors):
vectors = defaultdict(list)
for vector in fips_vectors:
vectors[vector['digest_algorithm']].append(vector['message'])
for digest_algorithm, messages in vectors.items():
if digest_algorithm not in HASHLIB_HASH_TYPES:
continue
yield ""
yield "[K-256,{0}]".format(digest_algorithm)
yield ""
for message in messages:
# Make a hash context
hash_func = TruncatedHash(HASHLIB_HASH_TYPES[digest_algorithm]())
# Sign the message using warner/ecdsa
secret_key = SigningKey.generate(curve=SECP256k1)
public_key = secret_key.get_verifying_key()
signature = secret_key.sign(message, hashfunc=hash_func,
sigencode=sigencode_der)
r, s = sigdecode_der(signature, None)
yield "Msg = {0}".format(hexlify(message))
yield "d = {0:x}".format(secret_key.privkey.secret_multiplier)
yield "Qx = {0:x}".format(public_key.pubkey.point.x())
yield "Qy = {0:x}".format(public_key.pubkey.point.y())
yield "R = {0:x}".format(r)
yield "S = {0:x}".format(s)
yield ""
def write_file(lines, dest):
for line in lines:
print(line)
print(line, file=dest)
source_path = os.path.join("asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt")
dest_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt")
fips_vectors = load_vectors_from_file(
source_path,
load_fips_ecdsa_signing_vectors
)
with open_vector_file(dest_path, "w") as dest_file:
write_file(
build_vectors(fips_vectors),
dest_file
)

View File

@ -0,0 +1,59 @@
from __future__ import absolute_import, print_function
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import (
encode_dss_signature
)
from tests.utils import (
load_fips_ecdsa_signing_vectors, load_vectors_from_file
)
CRYPTOGRAPHY_HASH_TYPES = {
"SHA-1": hashes.SHA1,
"SHA-224": hashes.SHA224,
"SHA-256": hashes.SHA256,
"SHA-384": hashes.SHA384,
"SHA-512": hashes.SHA512,
}
def verify_one_vector(vector):
digest_algorithm = vector['digest_algorithm']
message = vector['message']
x = vector['x']
y = vector['y']
signature = encode_dss_signature(vector['r'], vector['s'])
numbers = ec.EllipticCurvePublicNumbers(
x, y,
ec.SECP256K1()
)
key = numbers.public_key(default_backend())
verifier = key.verifier(
signature,
ec.ECDSA(CRYPTOGRAPHY_HASH_TYPES[digest_algorithm]())
)
verifier.update(message)
return verifier.verify()
def verify_vectors(vectors):
for vector in vectors:
assert verify_one_vector(vector)
vector_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt")
secp256k1_vectors = load_vectors_from_file(
vector_path,
load_fips_ecdsa_signing_vectors
)
verify_vectors(secp256k1_vectors)

View File

@ -0,0 +1,32 @@
SEED vector creation
=====================
This page documents the code that was used to generate the SEED CFB and OFB
test vectors as well as the code used to verify them against another
implementation. The vectors were generated using OpenSSL and verified
with `Botan`_.
Creation
--------
``cryptography`` was modified to support SEED in CFB and OFB modes. Then
the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/seed/generate_seed.py
Download link: :download:`generate_seed.py
</development/custom-vectors/seed/generate_seed.py>`
Verification
------------
The following Python code was used to verify the vectors using the `Botan`_
project's Python bindings.
.. literalinclude:: /development/custom-vectors/seed/verify_seed.py
Download link: :download:`verify_seed.py
</development/custom-vectors/seed/verify_seed.py>`
.. _`Botan`: https://botan.randombit.net

View File

@ -0,0 +1,58 @@
import binascii
from cryptography.hazmat.backends.openssl.backend import backend
from cryptography.hazmat.primitives.ciphers import algorithms, base, modes
def encrypt(mode, key, iv, plaintext):
cipher = base.Cipher(
algorithms.SEED(binascii.unhexlify(key)),
mode(binascii.unhexlify(iv)),
backend
)
encryptor = cipher.encryptor()
ct = encryptor.update(binascii.unhexlify(plaintext))
ct += encryptor.finalize()
return binascii.hexlify(ct)
def build_vectors(mode, filename):
with open(filename, "r") as f:
vector_file = f.read().splitlines()
count = 0
output = []
key = None
iv = None
plaintext = None
for line in vector_file:
line = line.strip()
if line.startswith("KEY"):
if count != 0:
output.append("CIPHERTEXT = {0}".format(
encrypt(mode, key, iv, plaintext))
)
output.append("\nCOUNT = {0}".format(count))
count += 1
name, key = line.split(" = ")
output.append("KEY = {0}".format(key))
elif line.startswith("IV"):
name, iv = line.split(" = ")
output.append("IV = {0}".format(iv))
elif line.startswith("PLAINTEXT"):
name, plaintext = line.split(" = ")
output.append("PLAINTEXT = {0}".format(plaintext))
output.append("CIPHERTEXT = {0}".format(encrypt(mode, key, iv, plaintext)))
return "\n".join(output)
def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
OFB_PATH = "vectors/cryptography_vectors/ciphers/AES/OFB/OFBMMT128.rsp"
write_file(build_vectors(modes.OFB, OFB_PATH), "seed-ofb.txt")
CFB_PATH = "vectors/cryptography_vectors/ciphers/AES/CFB/CFB128MMT128.rsp"
write_file(build_vectors(modes.CFB, CFB_PATH), "seed-cfb.txt")

View File

@ -0,0 +1,35 @@
import binascii
import botan
from tests.utils import load_nist_vectors
def encrypt(mode, key, iv, plaintext):
encryptor = botan.Cipher("SEED/{0}/NoPadding".format(mode), "encrypt",
binascii.unhexlify(key))
cipher_text = encryptor.cipher(binascii.unhexlify(plaintext),
binascii.unhexlify(iv))
return binascii.hexlify(cipher_text)
def verify_vectors(mode, filename):
with open(filename, "r") as f:
vector_file = f.read().splitlines()
vectors = load_nist_vectors(vector_file)
for vector in vectors:
ct = encrypt(
mode,
vector["key"],
vector["iv"],
vector["plaintext"]
)
assert ct == vector["ciphertext"]
ofb_path = "vectors/cryptography_vectors/ciphers/SEED/seed-ofb.txt"
verify_vectors("OFB", ofb_path)
cfb_path = "vectors/cryptography_vectors/ciphers/SEED/seed-cfb.txt"
verify_vectors("CFB", cfb_path)

View File

@ -0,0 +1,130 @@
Getting started
===============
Development dependencies
------------------------
Working on ``cryptography`` requires the installation of a small number of
development dependencies in addition to the dependencies for
:doc:`/installation`. These are listed in ``dev-requirements.txt`` and they can
be installed in a `virtualenv`_ using `pip`_. Before you install them, follow
the **build** instructions in :doc:`/installation` (be sure to stop before
actually installing ``cryptography``). Once you've done that, install the
development dependencies, and then install ``cryptography`` in ``editable``
mode. For example:
.. code-block:: console
$ # Create a virtualenv and activate it
$ # Set up your cryptography build environment
$ pip install --requirement dev-requirements.txt
$ pip install --editable .
You will also need to install ``enchant`` using your system's package manager
to check spelling in the documentation.
.. note::
There is an upstream bug in ``enchant`` that prevents its installation on
Windows with 64-bit Python. See `this Github issue`_ for more information.
The easiest workaround is to use 32-bit Python for ``cryptography``
development, even on 64-bit Windows.
You are now ready to run the tests and build the documentation.
OpenSSL on OS X
~~~~~~~~~~~~~~~
You must have installed `OpenSSL`_ via `Homebrew`_ or `MacPorts`_ and must set
``CFLAGS`` and ``LDFLAGS`` environment variables before installing the
``dev-requirements.txt`` otherwise pip will fail with include errors.
For example, with `Homebrew`_:
.. code-block:: console
$ env LDFLAGS="-L$(brew --prefix openssl)/lib" \
CFLAGS="-I$(brew --prefix openssl)/include" \
pip install --requirement ./dev-requirements.txt
Alternatively for a static build you can specify
``CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=1`` and ensure ``LDFLAGS`` points to the
absolute path for the `OpenSSL`_ libraries before calling pip.
.. tip::
You will also need to set these values when `Building documentation`_.
Running tests
-------------
``cryptography`` unit tests are found in the ``tests/`` directory and are
designed to be run using `pytest`_. `pytest`_ will discover the tests
automatically, so all you have to do is:
.. code-block:: console
$ py.test
...
62746 passed in 220.43 seconds
This runs the tests with the default Python interpreter.
You can also verify that the tests pass on other supported Python interpreters.
For this we use `tox`_, which will automatically create a `virtualenv`_ for
each supported Python version and run the tests. For example:
.. code-block:: console
$ tox
...
ERROR: py26: InterpreterNotFound: python2.6
py27: commands succeeded
ERROR: pypy: InterpreterNotFound: pypy
py33: commands succeeded
docs: commands succeeded
pep8: commands succeeded
You may not have all the required Python versions installed, in which case you
will see one or more ``InterpreterNotFound`` errors.
Explicit backend selection
--------------------------
While testing you may want to run tests against a subset of the backends that
cryptography supports. Explicit backend selection can be done via the
``--backend`` flag. This flag should be passed to ``py.test`` with a comma
delimited list of backend names.
.. code-block:: console
$ tox -- --backend=openssl
$ py.test --backend=openssl,commoncrypto
Building documentation
----------------------
``cryptography`` documentation is stored in the ``docs/`` directory. It is
written in `reStructured Text`_ and rendered using `Sphinx`_.
Use `tox`_ to build the documentation. For example:
.. code-block:: console
$ tox -e docs
...
docs: commands succeeded
congratulations :)
The HTML documentation index can now be found at
``docs/_build/html/index.html``.
.. _`Homebrew`: http://brew.sh
.. _`MacPorts`: https://www.macports.org
.. _`OpenSSL`: https://www.openssl.org
.. _`pytest`: https://pypi.python.org/pypi/pytest
.. _`tox`: https://pypi.python.org/pypi/tox
.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv
.. _`pip`: https://pypi.python.org/pypi/pip
.. _`sphinx`: https://pypi.python.org/pypi/Sphinx
.. _`reStructured Text`: http://sphinx-doc.org/rest.html
.. _`this Github issue`: https://github.com/rfk/pyenchant/issues/42

View File

@ -0,0 +1,20 @@
Development
===========
As an open source project, ``cryptography`` welcomes contributions of all
forms. The sections below will help you get started.
File bugs and feature requests on our issue tracker on `GitHub`_. If it is a
bug check out `what to put in your bug report`_.
.. toctree::
:maxdepth: 2
getting-started
submitting-patches
reviewing-patches
test-vectors
c-bindings
.. _`GitHub`: https://github.com/pyca/cryptography
.. _`what to put in your bug report`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report

View File

@ -0,0 +1,60 @@
Reviewing and merging patches
=============================
Everyone is encouraged to review open pull requests. We only ask that you try
and think carefully, ask questions and are `excellent to one another`_. Code
review is our opportunity to share knowledge, design ideas and make friends.
When reviewing a patch try to keep each of these concepts in mind:
Architecture
------------
* Is the proposed change being made in the correct place? Is it a fix in a
backend when it should be in the primitives?
Intent
------
* What is the change being proposed?
* Do we want this feature or is the bug they're fixing really a bug?
Implementation
--------------
* Does the change do what the author claims?
* Are there sufficient tests?
* Has it been documented?
* Will this change introduce new bugs?
Grammar and style
-----------------
These are small things that are not caught by the automated style checkers.
* Does a variable need a better name?
* Should this be a keyword argument?
Merge requirements
------------------
Because cryptography is so complex, and the implications of getting it wrong so
devastating, ``cryptography`` has a strict merge policy for committers:
* Patches must *never* be pushed directly to ``master``, all changes (even the
most trivial typo fixes!) must be submitted as a pull request.
* A committer may *never* merge their own pull request, a second party must
merge their changes. If multiple people work on a pull request, it must be
merged by someone who did not work on it.
* A patch that breaks tests, or introduces regressions by changing or removing
existing tests should not be merged. Tests must always be passing on
``master``.
* If somehow the tests get into a failing state on ``master`` (such as by a
backwards incompatible release of a dependency) no pull requests may be
merged until this is rectified.
* All merged patches must have 100% test coverage.
The purpose of these policies is to minimize the chances we merge a change
that jeopardizes our users' security.
.. _`excellent to one another`: https://speakerdeck.com/ohrite/better-code-review

View File

@ -0,0 +1,161 @@
Submitting patches
==================
* Always make a new branch for your work.
* Patches should be small to facilitate easier review. `Studies have shown`_
that review quality falls off as patch size grows. Sometimes this will result
in many small PRs to land a single large feature.
* Larger changes should be discussed on `our mailing list`_ before submission.
* New features and significant bug fixes should be documented in the
:doc:`/changelog`.
* You must have legal permission to distribute any code you contribute to
``cryptography``, and it must be available under both the BSD and Apache
Software License Version 2.0 licenses.
If you believe you've identified a security issue in ``cryptography``, please
follow the directions on the :doc:`security page </security>`.
Code
----
When in doubt, refer to :pep:`8` for Python code. You can check if your code
meets our automated requirements by running ``flake8`` against it. If you've
installed the development requirements this will automatically use our
configuration. You can also run the ``tox`` job with ``tox -e pep8``.
`Write comments as complete sentences.`_
Class names which contains acronyms or initialisms should always be
capitalized. A class should be named ``HTTPClient``, not ``HttpClient``.
Every code file must start with the boilerplate licensing notice:
.. code-block:: python
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
Additionally, every Python code file must contain
.. code-block:: python
from __future__ import absolute_import, division, print_function
API considerations
~~~~~~~~~~~~~~~~~~
Most projects' APIs are designed with a philosophy of "make easy things easy,
and make hard things possible". One of the perils of writing cryptographic code
is that secure code looks just like insecure code, and its results are almost
always indistinguishable. As a result, ``cryptography`` has, as a design
philosophy: "make it hard to do insecure things". Here are a few strategies for
API design that should be both followed, and should inspire other API choices:
If it is necessary to compare a user provided value with a computed value (for
example, verifying a signature), there should be an API provided that performs
the verification in a secure way (for example, using a constant time
comparison), rather than requiring the user to perform the comparison
themselves.
If it is incorrect to ignore the result of a method, it should raise an
exception, and not return a boolean ``True``/``False`` flag. For example, a
method to verify a signature should raise ``InvalidSignature``, and not return
whether the signature was valid.
.. code-block:: python
# This is bad.
def verify(sig):
# ...
return is_valid
# Good!
def verify(sig):
# ...
if not is_valid:
raise InvalidSignature
Every recipe should include a version or algorithmic marker of some sort in its
output in order to allow transparent upgrading of the algorithms in use, as
the algorithms or parameters needed to achieve a given security margin evolve.
APIs at the :doc:`/hazmat/primitives/index` layer should always take an
explicit backend, APIs at the recipes layer should automatically use the
:func:`~cryptography.hazmat.backends.default_backend`, but optionally allow
specifying a different backend.
C bindings
~~~~~~~~~~
More information on C bindings can be found in :doc:`the dedicated
section of the documentation <c-bindings>`.
Tests
-----
All code changes must be accompanied by unit tests with 100% code coverage (as
measured by the combined metrics across our build matrix).
When implementing a new primitive or recipe ``cryptography`` requires that you
provide a set of test vectors. See :doc:`/development/test-vectors` for more
details.
Documentation
-------------
All features should be documented with prose in the ``docs`` section. To ensure
it builds and passes `doc8`_ style checks you can run ``tox -e docs``.
Because of the inherent challenges in implementing correct cryptographic
systems, we want to make our documentation point people in the right directions
as much as possible. To that end:
* When documenting a generic interface, use a strong algorithm in examples.
(e.g. when showing a hashing example, don't use
:class:`~cryptography.hazmat.primitives.hashes.MD5`)
* When giving prescriptive advice, always provide references and supporting
material.
* When there is real disagreement between cryptographic experts, represent both
sides of the argument and describe the trade-offs clearly.
When documenting a new module in the ``hazmat`` package, its documentation
should begin with the "Hazardous Materials" warning:
.. code-block:: rest
.. hazmat::
Always prefer terminology that is most broadly accepted. For example:
* When referring to class instances use "an instance of ``Foo``"
instead of "a ``Foo`` provider".
When referring to a hypothetical individual (such as "a person receiving an
encrypted message") use gender neutral pronouns (they/them/their).
Docstrings are typically only used when writing abstract classes, but should
be written like this if required:
.. code-block:: python
def some_function(some_arg):
"""
Does some things.
:param some_arg: Some argument.
"""
So, specifically:
* Always use three double quotes.
* Put the three double quotes on their own line.
* No blank line at the end.
* Use Sphinx parameter/attribute documentation `syntax`_.
.. _`Write comments as complete sentences.`: http://nedbatchelder.com/blog/201401/comments_should_be_sentences.html
.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists
.. _`Studies have shown`: https://smartbear.com/SmartBear/media/pdfs/11_Best_Practices_for_Peer_Code_Review.pdf
.. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`doc8`: https://github.com/openstack/doc8

View File

@ -0,0 +1,473 @@
Test vectors
============
Testing the correctness of the primitives implemented in each ``cryptography``
backend requires trusted test vectors. Where possible these vectors are
obtained from official sources such as `NIST`_ or `IETF`_ RFCs. When this is
not possible ``cryptography`` has chosen to create a set of custom vectors
using an official vector file as input to verify consistency between
implemented backends.
Vectors are kept in the `cryptography_vectors` package rather than within our
main test suite.
Sources
-------
Asymmetric ciphers
~~~~~~~~~~~~~~~~~~
* RSA PKCS #1 from the RSA FTP site (ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/
and ftp://ftp.rsa.com/pub/rsalabs/tmp/).
* RSA FIPS 186-2 and PKCS1 v1.5 vulnerability test vectors from `NIST CAVP`_.
* FIPS 186-2 and FIPS 186-3 DSA test vectors from `NIST CAVP`_.
* FIPS 186-2 and FIPS 186-3 ECDSA test vectors from `NIST CAVP`_.
* DH and ECDH and ECDH+KDF(17.4) test vectors from `NIST CAVP`_.
* Ed25519 test vectors from the `Ed25519 website_`.
* OpenSSL PEM RSA serialization vectors from the `OpenSSL example key`_ and
`GnuTLS key parsing tests`_.
* OpenSSL PEM DSA serialization vectors from the `GnuTLS example keys`_.
* PKCS #8 PEM serialization vectors from
* GnuTLS: `enc-rsa-pkcs8.pem`_, `enc2-rsa-pkcs8.pem`_,
`unenc-rsa-pkcs8.pem`_, `pkcs12_s2k_pem.c`_. The contents of
`enc2-rsa-pkcs8.pem`_ was re-encrypted using a stronger PKCS#8 cipher.
* `Botan's ECC private keys`_.
* `asymmetric/public/PKCS1/dsa.pub.pem`_ is a PKCS1 DSA public key from the
Ruby test suite.
Custom asymmetric vectors
~~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 1
custom-vectors/secp256k1
custom-vectors/rsa-oaep-sha2
* ``asymmetric/PEM_Serialization/ec_private_key.pem`` and
``asymmetric/DER_Serialization/ec_private_key.der`` - Contains an Elliptic
Curve key generated by OpenSSL from the curve ``secp256r1``.
* ``asymmetric/PEM_Serialization/ec_private_key_encrypted.pem`` and
``asymmetric/DER_Serialization/ec_private_key_encrypted.der``- Contains the
same Elliptic Curve key as ``ec_private_key.pem``, except that it is
encrypted with AES-128 with the password "123456".
* ``asymmetric/PEM_Serialization/ec_public_key.pem`` and
``asymmetric/DER_Serialization/ec_public_key.der``- Contains the public key
corresponding to ``ec_private_key.pem``, generated using OpenSSL.
* ``asymmetric/PEM_Serialization/rsa_private_key.pem`` - Contains an RSA 2048
bit key generated using OpenSSL, protected by the secret "123456" with DES3
encryption.
* ``asymmetric/PEM_Serialization/rsa_public_key.pem`` and
``asymmetric/DER_Serialization/rsa_public_key.der``- Contains an RSA 2048
bit public generated using OpenSSL from ``rsa_private_key.pem``.
* ``asymmetric/PEM_Serialization/dsaparam.pem`` - Contains 2048-bit DSA
parameters generated using OpenSSL; contains no keys.
* ``asymmetric/PEM_Serialization/dsa_private_key.pem`` - Contains a DSA 2048
bit key generated using OpenSSL from the parameters in ``dsaparam.pem``,
protected by the secret "123456" with DES3 encryption.
* ``asymmetric/PEM_Serialization/dsa_public_key.pem`` and
``asymmetric/DER_Serialization/dsa_public_key.der`` - Contains a DSA 2048 bit
key generated using OpenSSL from ``dsa_private_key.pem``.
* ``asymmetric/PKCS8/unenc-dsa-pkcs8.pem`` and
``asymmetric/DER_Serialization/unenc-dsa-pkcs8.der`` - Contains a DSA 1024
bit key generated using OpenSSL.
* ``asymmetric/PKCS8/unenc-dsa-pkcs8.pub.pem`` and
``asymmetric/DER_Serialization/unenc-dsa-pkcs8.pub.der`` - Contains a DSA
2048 bit public key generated using OpenSSL from ``unenc-dsa-pkcs8.pem``.
* DER conversions of the `GnuTLS example keys`_ for DSA as well as the
`OpenSSL example key`_ for RSA.
* DER conversions of `enc-rsa-pkcs8.pem`_, `enc2-rsa-pkcs8.pem`_, and
`unenc-rsa-pkcs8.pem`_.
* ``asymmetric/public/PKCS1/rsa.pub.pem`` and
``asymmetric/public/PKCS1/rsa.pub.der`` are PKCS1 conversions of the public
key from ``asymmetric/PKCS8/unenc-rsa-pkcs8.pem`` using PEM and DER encoding.
Key exchange
~~~~~~~~~~~~
* ``vectors/cryptography_vectors/asymmetric/DH/RFC5114.txt`` contains
Diffie-Hellman examples from appendix A.1, A.2 and A.3 of :rfc:`5114`.
* ``vectors/cryptography_vectors/asymmetric/DH/vec.txt`` contains
Diffie-Hellman examples from `botan`_.
* ``vectors/cryptography_vectors/asymmetric/DH/bad_exchange.txt`` contains
Diffie-Hellman vector pairs that were generated using OpenSSL
DH_generate_parameters_ex and DH_generate_key.
X.509
~~~~~
* PKITS test suite from `NIST PKI Testing`_.
* ``v1_cert.pem`` from the OpenSSL source tree (`testx509.pem`_).
* ``ecdsa_root.pem`` - `DigiCert Global Root G3`_, a ``secp384r1`` ECDSA root
certificate.
* ``verisign-md2-root.pem`` - A legacy Verisign public root signed using the
MD2 algorithm. This is a PEM conversion of the `root data`_ in the NSS source
tree.
* ``cryptography.io.pem`` - A leaf certificate issued by RapidSSL for the
cryptography website.
* ``rapidssl_sha256_ca_g3.pem`` - The intermediate CA that issued the
``cryptography.io.pem`` certificate.
* ``wildcard_san.pem`` - A leaf certificate issued by a public CA for
``langui.sh`` that contains wildcard entries in the SAN extension.
* ``san_edipartyname.der`` - A DSA certificate from a `Mozilla bug`_
containing a SAN extension with an ``ediPartyName`` general name.
* ``san_x400address.der`` - A DSA certificate from a `Mozilla bug`_ containing
a SAN extension with an ``x400Address`` general name.
* ``department-of-state-root.pem`` - The intermediary CA for the Department of
State, issued by the United States Federal Government's Common Policy CA.
Notably has a ``critical`` policy constraints extensions.
* ``e-trust.ru.der`` - A certificate from a `Russian CA`_ signed using the GOST
cipher and containing numerous unusual encodings such as NUMERICSTRING in
the subject DN.
* ``alternate-rsa-sha1-oid.pem`` - A certificate from an
`unknown signature OID`_ Mozilla bug that uses an alternate signature OID for
RSA with SHA1.
Custom X.509 Vectors
~~~~~~~~~~~~~~~~~~~~
* ``invalid_version.pem`` - Contains an RSA 2048 bit certificate with the
X.509 version field set to ``0x7``.
* ``post2000utctime.pem`` - Contains an RSA 2048 bit certificate with the
``notBefore`` and ``notAfter`` fields encoded as post-2000 ``UTCTime``.
* ``dsa_selfsigned_ca.pem`` - Contains a DSA self-signed CA certificate
generated using OpenSSL.
* ``ec_no_named_curve.pem`` - Contains an ECDSA certificate that does not have
an embedded OID defining the curve.
* ``all_supported_names.pem`` - An RSA 2048 bit certificate generated using
OpenSSL that contains a subject and issuer that have two of each supported
attribute type from :rfc:`5280`.
* ``unsupported_subject_name.pem`` - An RSA 2048 bit self-signed CA certificate
generated using OpenSSL that contains the unsupported "initials" name.
* ``utf8_common_name.pem`` - An RSA 2048 bit self-signed CA certificate
generated using OpenSSL that contains a UTF8String common name with the value
"We heart UTF8!™".
* ``two_basic_constraints.pem`` - An RSA 2048 bit self-signed certificate
containing two basic constraints extensions.
* ``basic_constraints_not_critical.pem`` - An RSA 2048 bit self-signed
certificate containing a basic constraints extension that is not marked as
critical.
* ``bc_path_length_zero.pem`` - An RSA 2048 bit self-signed
certificate containing a basic constraints extension with a path length of
zero.
* ``unsupported_extension.pem`` - An RSA 2048 bit self-signed certificate
containing an unsupported extension type. The OID was encoded as
"1.2.3.4" with an ``extnValue`` of "value".
* ``unsupported_extension_2.pem`` - A ``secp256r1`` certificate
containing two unsupported extensions. The OIDs are ``1.3.6.1.4.1.41482.2``
with an ``extnValue`` of ``1.3.6.1.4.1.41482.1.2`` and
``1.3.6.1.4.1.45724.2.1.1`` with an ``extnValue`` of ``\x03\x02\x040``
* ``unsupported_extension_critical.pem`` - An RSA 2048 bit self-signed
certificate containing an unsupported extension type marked critical. The OID
was encoded as "1.2.3.4" with an ``extnValue`` of "value".
* ``san_email_dns_ip_dirname_uri.pem`` - An RSA 2048 bit self-signed
certificate containing a subject alternative name extension with the
following general names: ``rfc822Name``, ``dNSName``, ``iPAddress``,
``directoryName``, and ``uniformResourceIdentifier``.
* ``san_empty_hostname.pem`` - An RSA 2048 bit self-signed certificate
containing a subject alternative extension with an empty ``dNSName``
general name.
* ``san_other_name.pem`` - An RSA 2048 bit self-signed certificate containing
a subject alternative name extension with the ``otherName`` general name.
* ``san_registered_id.pem`` - An RSA 1024 bit certificate containing a
subject alternative name extension with the ``registeredID`` general name.
* ``all_key_usages.pem`` - An RSA 2048 bit self-signed certificate containing
a key usage extension with all nine purposes set to true.
* ``extended_key_usage.pem`` - An RSA 2048 bit self-signed certificate
containing an extended key usage extension with eight usages.
* ``san_idna_names.pem`` - An RSA 2048 bit self-signed certificate containing
a subject alternative name extension with ``rfc822Name``, ``dNSName``, and
``uniformResourceIdentifier`` general names with IDNA (:rfc:`5895`) encoding.
* ``san_wildcard_idna.pem`` - An RSA 2048 bit self-signed certificate
containing a subject alternative name extension with a ``dNSName`` general
name with a wildcard IDNA (:rfc:`5895`) domain.
* ``san_idna2003_dnsname.pem`` - An RSA 2048 bit self-signed certificate
containing a subject alternative name extension with an IDNA 2003
(:rfc:`3490`) ``dNSName``.
* ``san_rfc822_names.pem`` - An RSA 2048 bit self-signed certificate containing
a subject alternative name extension with various ``rfc822Name`` values.
* ``san_rfc822_idna.pem`` - An RSA 2048 bit self-signed certificate containing
a subject alternative name extension with an IDNA ``rfc822Name``.
* ``san_uri_with_port.pem`` - An RSA 2048 bit self-signed certificate
containing a subject alternative name extension with various
``uniformResourceIdentifier`` values.
* ``san_ipaddr.pem`` - An RSA 2048 bit self-signed certificate containing a
subject alternative name extension with an ``iPAddress`` value.
* ``san_dirname.pem`` - An RSA 2048 bit self-signed certificate containing a
subject alternative name extension with a ``directoryName`` value.
* ``inhibit_any_policy_5.pem`` - An RSA 2048 bit self-signed certificate
containing an inhibit any policy extension with the value 5.
* ``inhibit_any_policy_negative.pem`` - An RSA 2048 bit self-signed certificate
containing an inhibit any policy extension with the value -1.
* ``authority_key_identifier.pem`` - An RSA 2048 bit self-signed certificate
containing an authority key identifier extension with key identifier,
authority certificate issuer, and authority certificate serial number fields.
* ``authority_key_identifier_no_keyid.pem`` - An RSA 2048 bit self-signed
certificate containing an authority key identifier extension with authority
certificate issuer and authority certificate serial number fields.
* ``aia_ocsp_ca_issuers.pem`` - An RSA 2048 bit self-signed certificate
containing an authority information access extension with two OCSP and one
CA issuers entry.
* ``aia_ocsp.pem`` - An RSA 2048 bit self-signed certificate
containing an authority information access extension with an OCSP entry.
* ``aia_ca_issuers.pem`` - An RSA 2048 bit self-signed certificate
containing an authority information access extension with a CA issuers entry.
* ``cdp_empty_hostname.pem`` - An RSA 2048 bit self-signed certificate
containing a CRL distribution point extension with ``fullName`` URI without
a hostname.
* ``cdp_fullname_reasons_crl_issuer.pem`` - An RSA 1024 bit certificate
containing a CRL distribution points extension with ``fullName``,
``cRLIssuer``, and ``reasons`` data.
* ``cdp_crl_issuer.pem`` - An RSA 1024 bit certificate containing a CRL
distribution points extension with ``cRLIssuer`` data.
* ``cdp_all_reasons.pem`` - An RSA 1024 bit certificate containing a CRL
distribution points extension with all ``reasons`` bits set.
* ``cdp_reason_aa_compromise.pem`` - An RSA 1024 bit certificate containing a
CRL distribution points extension with the ``AACompromise`` ``reasons`` bit
set.
* ``nc_permitted_excluded.pem`` - An RSA 2048 bit self-signed certificate
containing a name constraints extension with both permitted and excluded
elements. Contains ``IPv4`` and ``IPv6`` addresses with network mask as well
as ``dNSName`` with a leading period.
* ``nc_permitted_excluded_2.pem`` - An RSA 2048 bit self-signed certificate
containing a name constraints extension with both permitted and excluded
elements. Unlike ``nc_permitted_excluded.pem``, the general names do not
contain any name constraints specific values.
* ``nc_permitted.pem`` - An RSA 2048 bit self-signed certificate containing a
name constraints extension with permitted elements.
* ``nc_permitted_2.pem`` - An RSA 2048 bit self-signed certificate containing a
name constraints extension with permitted elements that do not contain any
name constraints specific values.
* ``nc_excluded.pem`` - An RSA 2048 bit self-signed certificate containing a
name constraints extension with excluded elements.
* ``nc_invalid_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate
containing a name constraints extension with a permitted element that has an
``IPv6`` IP and an invalid network mask.
* ``nc_single_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate
containing a name constraints extension with a permitted element that has two
IPs with ``/32`` and ``/128`` network masks.
* ``cp_user_notice_with_notice_reference.pem`` - An RSA 2048 bit self-signed
certificate containing a certificate policies extension with a
notice reference in the user notice.
* ``cp_user_notice_with_explicit_text.pem`` - An RSA 2048 bit self-signed
certificate containing a certificate policies extension with explicit
text and no notice reference.
* ``cp_cps_uri.pem`` - An RSA 2048 bit self-signed certificate containing a
certificate policies extension with a CPS URI and no user notice.
* ``cp_user_notice_no_explicit_text.pem`` - An RSA 2048 bit self-signed
certificate containing a certificate policies extension with a user notice
with no explicit text.
* ``cp_invalid.pem`` - An RSA 2048 bit self-signed certificate containing a
certificate policies extension with invalid data.
* ``ian_uri.pem`` - An RSA 2048 bit certificate containing an issuer
alternative name extension with a ``URI`` general name.
* ``ocsp_nocheck.pem`` - An RSA 2048 bit self-signed certificate containing
an ``OCSPNoCheck`` extension.
* ``pc_inhibit_require.pem`` - An RSA 2048 bit self-signed certificate
containing a policy constraints extension with both inhibit policy mapping
and require explicit policy elements.
* ``pc_inhibit.pem`` - An RSA 2048 bit self-signed certificate containing a
policy constraints extension with an inhibit policy mapping element.
* ``pc_require.pem`` - An RSA 2048 bit self-signed certificate containing a
policy constraints extension with a require explicit policy element.
* ``unsupported_subject_public_key_info.pem`` - A certificate whose public key
is an unknown OID (``1.3.6.1.4.1.8432.1.1.2``).
* ``policy_constraints_explicit.pem`` - A self-signed certificate containing
a ``policyConstraints`` extension with a ``requireExplicitPolicy`` value.
Custom X.509 Request Vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``dsa_sha1.pem`` and ``dsa_sha1.der`` - Contain a certificate request using
1024-bit DSA parameters and SHA1 generated using OpenSSL.
* ``rsa_md4.pem`` and ``rsa_md4.der`` - Contain a certificate request using
2048 bit RSA and MD4 generated using OpenSSL.
* ``rsa_sha1.pem`` and ``rsa_sha1.der`` - Contain a certificate request using
2048 bit RSA and SHA1 generated using OpenSSL.
* ``rsa_sha256.pem`` and ``rsa_sha256.der`` - Contain a certificate request
using 2048 bit RSA and SHA256 generated using OpenSSL.
* ``ec_sha256.pem`` and ``ec_sha256.der`` - Contain a certificate request
using EC (``secp384r1``) and SHA256 generated using OpenSSL.
* ``san_rsa_sha1.pem`` and ``san_rsa_sha1.der`` - Contain a certificate
request using RSA and SHA1 with a subject alternative name extension
generated using OpenSSL.
* ``two_basic_constraints.pem`` - A certificate signing request
for an RSA 2048 bit key containing two basic constraints extensions.
* ``unsupported_extension.pem`` - A certificate signing request
for an RSA 2048 bit key containing containing an unsupported
extension type. The OID was encoded as "1.2.3.4" with an
``extnValue`` of "value".
* ``unsupported_extension_critical.pem`` - A certificate signing
request for an RSA 2048 bit key containing containing an unsupported
extension type marked critical. The OID was encoded as "1.2.3.4"
with an ``extnValue`` of "value".
* ``basic_constraints.pem`` - A certificate signing request for an RSA
2048 bit key containing a basic constraints extension marked as
critical.
* ``invalid_signature.pem`` - A certificate signing request for an RSA
1024 bit key containing an invalid signature with correct padding.
Custom X.509 Certificate Revocation List Vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``crl_all_reasons.pem`` - Contains a CRL with 12 revoked certificates, whose
serials match their list position. It includes one revocation without
any entry extensions, 10 revocations with every supported reason code and one
revocation with an unsupported, non-critical entry extension with the OID
value set to "1.2.3.4".
* ``crl_dup_entry_ext.pem`` - Contains a CRL with one revocation which has a
duplicate entry extension.
* ``crl_md2_unknown_crit_entry_ext.pem`` - Contains a CRL with one revocation
which contains an unsupported critical entry extension with the OID value set
to "1.2.3.4". The CRL uses an unsupported MD2 signature algorithm.
* ``crl_unsupported_reason.pem`` - Contains a CRL with one revocation which has
an unsupported reason code.
* ``crl_inval_cert_issuer_entry_ext.pem`` - Contains a CRL with one revocation
which has one entry extension for certificate issuer with an empty value.
* ``crl_empty.pem`` - Contains a CRL with no revoked certificates.
* ``crl_ian_aia_aki.pem`` - Contains a CRL with ``IssuerAlternativeName``,
``AuthorityInformationAccess``, ``AuthorityKeyIdentifier`` and ``CRLNumber``
extensions.
Hashes
~~~~~~
* MD5 from :rfc:`1321`.
* RIPEMD160 from the `RIPEMD website`_.
* SHA1 from `NIST CAVP`_.
* SHA2 (224, 256, 384, 512) from `NIST CAVP`_.
* Whirlpool from the `Whirlpool website`_.
* Blake2s and Blake2b from OpenSSL `test/evptests.txt`_.
HMAC
~~~~
* HMAC-MD5 from :rfc:`2202`.
* HMAC-SHA1 from :rfc:`2202`.
* HMAC-RIPEMD160 from :rfc:`2286`.
* HMAC-SHA2 (224, 256, 384, 512) from :rfc:`4231`.
Key derivation functions
~~~~~~~~~~~~~~~~~~~~~~~~
* HKDF (SHA1, SHA256) from :rfc:`5869`.
* PBKDF2 (HMAC-SHA1) from :rfc:`6070`.
* scrypt from the `draft RFC`_.
* X9.63 KDF from `NIST CAVP`_.
* SP 800-108 Counter Mode KDF (HMAC-SHA1, HMAC-SHA224, HMAC-SHA256,
HMAC-SHA384, HMAC-SHA512) from `NIST CAVP`_.
Key wrapping
~~~~~~~~~~~~
* AES key wrap (AESKW) and 3DES key wrap test vectors from `NIST CAVP`_.
Recipes
~~~~~~~
* Fernet from its `specification repository`_.
Symmetric ciphers
~~~~~~~~~~~~~~~~~
* AES (CBC, CFB, ECB, GCM, OFB) from `NIST CAVP`_.
* AES CTR from :rfc:`3686`.
* 3DES (CBC, CFB, ECB, OFB) from `NIST CAVP`_.
* ARC4 (KEY-LENGTH: 40, 56, 64, 80, 128, 192, 256) from :rfc:`6229`.
* ARC4 (KEY-LENGTH: 160) generated by this project.
See: :doc:`/development/custom-vectors/arc4`
* Blowfish (CBC, CFB, ECB, OFB) from `Bruce Schneier's vectors`_.
* Camellia (ECB) from NTT's `Camellia page`_ as linked by `CRYPTREC`_.
* Camellia (CBC, CFB, OFB) from `OpenSSL's test vectors`_.
* CAST5 (ECB) from :rfc:`2144`.
* CAST5 (CBC, CFB, OFB) generated by this project.
See: :doc:`/development/custom-vectors/cast5`
* IDEA (ECB) from the `NESSIE IDEA vectors`_ created by `NESSIE`_.
* IDEA (CBC, CFB, OFB) generated by this project.
See: :doc:`/development/custom-vectors/idea`
* SEED (ECB) from :rfc:`4269`.
* SEED (CBC) from :rfc:`4196`.
* SEED (CFB, OFB) generated by this project.
See: :doc:`/development/custom-vectors/seed`
Two factor authentication
~~~~~~~~~~~~~~~~~~~~~~~~~
* HOTP from :rfc:`4226`
* TOTP from :rfc:`6238` (Note that an `errata`_ for the test vectors in RFC
6238 exists)
CMAC
~~~~
* AES-128, AES-192, AES-256, 3DES from `NIST SP-800-38B`_
Creating test vectors
---------------------
When official vectors are unavailable ``cryptography`` may choose to build
its own using existing vectors as source material.
Custom Symmetric Vectors
~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 1
custom-vectors/arc4
custom-vectors/cast5
custom-vectors/idea
custom-vectors/seed
If official test vectors appear in the future the custom generated vectors
should be discarded.
Any vectors generated by this method must also be prefixed with the following
header format (substituting the correct information):
.. code-block:: python
# CAST5 CBC vectors built for https://github.com/pyca/cryptography
# Derived from the AESVS MMT test data for CBC
# Verified against the CommonCrypto and Go crypto packages
# Key Length : 128
.. _`NIST`: https://www.nist.gov/
.. _`IETF`: https://www.ietf.org/
.. _`NIST CAVP`: http://csrc.nist.gov/groups/STM/cavp/
.. _`Bruce Schneier's vectors`: https://www.schneier.com/code/vectors.txt
.. _`Camellia page`: https://info.isl.ntt.co.jp/crypt/eng/camellia/
.. _`CRYPTREC`: https://www.cryptrec.go.jp
.. _`OpenSSL's test vectors`: https://github.com/openssl/openssl/blob/97cf1f6c2854a3a955fd7dd3a1f113deba00c9ef/crypto/evp/evptests.txt#L232
.. _`RIPEMD website`: http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
.. _`Whirlpool website`: http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html
.. _`draft RFC`: https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01
.. _`Specification repository`: https://github.com/fernet/spec
.. _`errata`: https://www.rfc-editor.org/errata_search.php?rfc=6238
.. _`OpenSSL example key`: https://github.com/openssl/openssl/blob/d02b48c63a58ea4367a0e905979f140b7d090f86/test/testrsa.pem
.. _`GnuTLS key parsing tests`: https://gitlab.com/gnutls/gnutls/commit/f16ef39ef0303b02d7fa590a37820440c466ce8d
.. _`enc-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/encpkcs8.pem
.. _`enc2-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/enc2pkcs8.pem
.. _`unenc-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/unencpkcs8.pem
.. _`pkcs12_s2k_pem.c`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs12_s2k_pem.c
.. _`Botan's ECC private keys`: https://github.com/randombit/botan/tree/4917f26a2b154e841cd27c1bcecdd41d2bdeb6ce/src/tests/data/ecc
.. _`GnuTLS example keys`: https://gitlab.com/gnutls/gnutls/commit/ad2061deafdd7db78fd405f9d143b0a7c579da7b
.. _`NESSIE IDEA vectors`: https://www.cosic.esat.kuleuven.be/nessie/testvectors/bc/idea/Idea-128-64.verified.test-vectors
.. _`NESSIE`: https://en.wikipedia.org/wiki/NESSIE
.. _`Ed25519 website`: http://ed25519.cr.yp.to/software.html
.. _`NIST SP-800-38B`: http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf
.. _`NIST PKI Testing`: http://csrc.nist.gov/groups/ST/crypto_apps_infra/pki/pkitesting.html
.. _`testx509.pem`: https://github.com/openssl/openssl/blob/master/test/testx509.pem
.. _`DigiCert Global Root G3`: http://cacerts.digicert.com/DigiCertGlobalRootG3.crt
.. _`root data`: https://hg.mozilla.org/projects/nss/file/25b2922cc564/security/nss/lib/ckfw/builtins/certdata.txt#l2053
.. _`asymmetric/public/PKCS1/dsa.pub.pem`: https://github.com/ruby/ruby/blob/4ccb387f3bc436a08fc6d72c4931994f5de95110/test/openssl/test_pkey_dsa.rb#L53
.. _`Mozilla bug`: https://bugzilla.mozilla.org/show_bug.cgi?id=233586
.. _`Russian CA`: https://e-trust.gosuslugi.ru/MainCA
.. _`test/evptests.txt`: https://github.com/openssl/openssl/blob/2d0b44126763f989a4cbffbffe9d0c7518158bb7/test/evptests.txt
.. _`unknown signature OID`: https://bugzilla.mozilla.org/show_bug.cgi?id=405966
.. _`botan`: https://github.com/randombit/botan/blob/57789bdfc55061002b2727d0b32587612829a37c/src/tests/data/pubkey/dh.vec

91
docs/doing-a-release.rst Normal file
View File

@ -0,0 +1,91 @@
Doing a release
===============
Doing a release of ``cryptography`` requires a few steps.
Verifying and upgrading OpenSSL version
---------------------------------------
The release process uses a static build for Windows and OS X wheels. Check that
the Windows and OS X Jenkins builders have the latest version of OpenSSL
installed before performing the release. If they do not:
Upgrading Windows
~~~~~~~~~~~~~~~~~
Run the ``openssl-release`` Jenkins job, then copy the resulting artifacts to
the Windows builders and unzip them in the root of the file system.
Upgrading OS X
~~~~~~~~~~~~~~
``brew update`` and then ``brew upgrade openssl --universal --build-bottle`` to
build a universal library (32-bit and 64-bit) compatible with all Intel Macs.
This can be confirmed by using
``lipo -info /usr/local/opt/openssl/lib/libssl.dylib`` to see the available
architectures.
Bumping the version number
--------------------------
The next step in doing a release is bumping the version number in the
software.
* Update the version number in ``src/cryptography/__about__.py``.
* Update the version number in ``vectors/cryptography_vectors/__about__.py``.
* Set the release date in the :doc:`/changelog`.
* Do a commit indicating this.
* Send a pull request with this.
* Wait for it to be merged.
Performing the release
----------------------
The commit that merged the version number bump is now the official release
commit for this release. You will need to have ``gpg`` installed and a ``gpg``
key in order to do a release. Once this has happened:
* Run ``invoke release {version}``.
The release should now be available on PyPI and a tag should be available in
the repository.
Verifying the release
---------------------
You should verify that ``pip install cryptography`` works correctly:
.. code-block:: pycon
>>> import cryptography
>>> cryptography.__version__
'...'
>>> import cryptography_vectors
>>> cryptography_vectors.__version__
'...'
Verify that this is the version you just released.
For the Windows wheels check the builds for the ``cryptography-wheel-builder``
job and verify that the final output for each build shows it loaded and linked
the expected OpenSSL version.
Post-release tasks
------------------
* Update the version number to the next major (e.g. ``0.5.dev1``) in
``cryptography/__about__.py`` and
``vectors/cryptography_vectors/__about__.py``.
* Close the `milestone`_ for the previous release on GitHub.
* Add new :doc:`/changelog` entry with next version and note that it is under
active development
* Send a pull request with these items
* Check for any outstanding code undergoing a deprecation cycle by looking in
``cryptography.utils`` for ``DeprecatedIn**`` definitions. If any exist open
a ticket to increment them for the next release.
* Send an email to the `mailing list`_ and `python-announce`_ announcing the
release.
.. _`milestone`: https://github.com/pyca/cryptography/milestones
.. _`mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
.. _`python-announce`: https://mail.python.org/mailman/listinfo/python-announce-list

39
docs/exceptions.rst Normal file
View File

@ -0,0 +1,39 @@
Exceptions
==========
.. currentmodule:: cryptography.exceptions
.. class:: UnsupportedAlgorithm
Raised when the requested algorithm, or combination of algorithms is not
supported.
.. class:: AlreadyFinalized
This is raised when a context is used after being finalized.
.. class:: InvalidSignature
This is raised when signature verification fails. This can occur with
HMAC or asymmetric key signature validation.
.. class:: NotYetFinalized
This is raised when the AEAD tag property is accessed on a context
before it is finalized.
.. class:: AlreadyUpdated
This is raised when additional data is added to a context after update
has already been called.
.. class:: InvalidKey
This is raised when the verify method of a key derivation function's
computed key does not match the expected key.

68
docs/faq.rst Normal file
View File

@ -0,0 +1,68 @@
Frequently asked questions
==========================
How does ``cryptography`` compare to NaCl (Networking and Cryptography Library)?
--------------------------------------------------------------------------------
While ``cryptography`` and `NaCl`_ both share the goal of making cryptography
easier, and safer, to use for developers, ``cryptography`` is designed to be a
general purpose library, interoperable with existing systems, while NaCl
features a collection of hand selected algorithms.
``cryptography``'s :ref:`recipes <cryptography-layout>` layer has similar goals
to NaCl.
If you prefer NaCl's design, we highly recommend `PyNaCl`_.
Compiling ``cryptography`` on OS X produces a ``fatal error: 'openssl/aes.h' file not found`` error
---------------------------------------------------------------------------------------------------
This happens because OS X 10.11 no longer includes a copy of OpenSSL.
``cryptography`` now provides wheels which include a statically linked copy of
OpenSSL. You're seeing this error because your copy of pip is too old to find
our wheel files. Upgrade your copy of pip with ``pip install -U pip`` and then
try install ``cryptography`` again.
Starting ``cryptography`` using ``mod_wsgi`` produces an ``InternalError`` during a call in ``_register_osrandom_engine``
-------------------------------------------------------------------------------------------------------------------------
This happens because ``mod_wsgi`` uses sub-interpreters, which can cause a
problem during initialization of the OpenSSL backend. To resolve this set the
`WSGIApplicationGroup`_ to ``%{GLOBAL}`` in the ``mod_wsgi`` configuration.
``cryptography`` raised an ``InternalError`` and I'm not sure what to do?
-------------------------------------------------------------------------
Frequently ``InternalError`` is raised when there are errors on the OpenSSL
error stack that were placed there by other libraries that are also using
OpenSSL. Try removing the other libraries and see if the problem persists.
If you have no other libraries using OpenSSL in your process, or they do not
appear to be at fault, it's possible that this is a bug in ``cryptography``.
Please file an `issue`_ with instructions on how to reproduce it.
Importing cryptography causes a ``RuntimeError`` about OpenSSL 1.0.0
--------------------------------------------------------------------
The OpenSSL project has dropped support for the 1.0.0 release series. Since it
is no longer receiving security patches from upstream, ``cryptography`` is also
dropping support for it. To fix this issue you should upgrade to a newer
version of OpenSSL (1.0.1 or later). This may require you to upgrade to a newer
operating system.
For the 1.7 release, you can set the ``CRYPTOGRAPHY_ALLOW_OPENSSL_100``
environment variable. Please note that this is *temporary* and will be removed
in ``cryptography`` 1.8.
Installing cryptography with OpenSSL 0.9.8 fails
------------------------------------------------
The OpenSSL project has dropped support for the 0.9.8 release series. Since it
is no longer receiving security patches from upstream, ``cryptography`` is also
dropping support for it. To fix this issue you should upgrade to a newer
version of OpenSSL (1.0.1 or later). This may require you to upgrade to a newer
operating system.
.. _`NaCl`: https://nacl.cr.yp.to/
.. _`PyNaCl`: https://pynacl.readthedocs.io
.. _`WSGIApplicationGroup`: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIApplicationGroup.html
.. _`issue`: https://github.com/pyca/cryptography/issues

169
docs/fernet.rst Normal file
View File

@ -0,0 +1,169 @@
Fernet (symmetric encryption)
=============================
.. currentmodule:: cryptography.fernet
Fernet guarantees that a message encrypted using it cannot be
manipulated or read without the key. `Fernet`_ is an implementation of
symmetric (also known as "secret key") authenticated cryptography. Fernet also
has support for implementing key rotation via :class:`MultiFernet`.
.. class:: Fernet(key)
This class provides both encryption and decryption facilities.
.. doctest::
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"my deep dark secret")
>>> token
'...'
>>> f.decrypt(token)
'my deep dark secret'
:param bytes key: A URL-safe base64-encoded 32-byte key. This **must** be
kept secret. Anyone with this key is able to create and
read messages.
.. classmethod:: generate_key()
Generates a fresh fernet key. Keep this some place safe! If you lose it
you'll no longer be able to decrypt messages; if anyone else gains
access to it, they'll be able to decrypt all of your messages, and
they'll also be able forge arbitrary messages that will be
authenticated and decrypted.
.. method:: encrypt(data)
:param bytes data: The message you would like to encrypt.
:returns bytes: A secure message that cannot be read or altered
without the key. It is URL-safe base64-encoded. This is
referred to as a "Fernet token".
:raises TypeError: This exception is raised if ``data`` is not
``bytes``.
.. note::
The encrypted message contains the current time when it was
generated in *plaintext*, the time a message was created will
therefore be visible to a possible attacker.
.. method:: decrypt(token, ttl=None)
:param bytes token: The Fernet token. This is the result of calling
:meth:`encrypt`.
:param int ttl: Optionally, the number of seconds old a message may be
for it to be valid. If the message is older than
``ttl`` seconds (from the time it was originally
created) an exception will be raised. If ``ttl`` is not
provided (or is ``None``), the age of the message is
not considered.
:returns bytes: The original plaintext.
:raises cryptography.fernet.InvalidToken: If the ``token`` is in any
way invalid, this exception
is raised. A token may be
invalid for a number of
reasons: it is older than the
``ttl``, it is malformed, or
it does not have a valid
signature.
:raises TypeError: This exception is raised if ``token`` is not
``bytes``.
.. class:: MultiFernet(fernets)
.. versionadded:: 0.7
This class implements key rotation for Fernet. It takes a ``list`` of
:class:`Fernet` instances, and implements the same API:
.. doctest::
>>> from cryptography.fernet import Fernet, MultiFernet
>>> key1 = Fernet(Fernet.generate_key())
>>> key2 = Fernet(Fernet.generate_key())
>>> f = MultiFernet([key1, key2])
>>> token = f.encrypt(b"Secret message!")
>>> token
'...'
>>> f.decrypt(token)
'Secret message!'
MultiFernet performs all encryption options using the *first* key in the
``list`` provided. MultiFernet attempts to decrypt tokens with each key in
turn. A :class:`cryptography.fernet.InvalidToken` exception is raised if
the correct key is not found in the ``list`` provided.
Key rotation makes it easy to replace old keys. You can add your new key at
the front of the list to start encrypting new messages, and remove old keys
as they are no longer needed.
.. class:: InvalidToken
See :meth:`Fernet.decrypt` for more information.
Using passwords with Fernet
---------------------------
It is possible to use passwords with Fernet. To do this, you need to run the
password through a key derivation function such as
:class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC`, bcrypt or
scrypt.
.. doctest::
>>> import base64
>>> import os
>>> from cryptography.fernet import Fernet
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
>>> password = b"password"
>>> salt = os.urandom(16)
>>> kdf = PBKDF2HMAC(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... iterations=100000,
... backend=default_backend()
... )
>>> key = base64.urlsafe_b64encode(kdf.derive(password))
>>> f = Fernet(key)
>>> token = f.encrypt(b"Secret message!")
>>> token
'...'
>>> f.decrypt(token)
'Secret message!'
In this scheme, the salt has to be stored in a retrievable location in order
to derive the same key from the password in the future.
The iteration count used should be adjusted to be as high as your server can
tolerate. A good default is at least 100,000 iterations which is what Django
`recommends`_ in 2014.
Implementation
--------------
Fernet is built on top of a number of standard cryptographic primitives.
Specifically it uses:
* :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` in
:class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode with a
128-bit key for encryption; using
:class:`~cryptography.hazmat.primitives.padding.PKCS7` padding.
* :class:`~cryptography.hazmat.primitives.hmac.HMAC` using
:class:`~cryptography.hazmat.primitives.hashes.SHA256` for authentication.
* Initialization vectors are generated using ``os.urandom()``.
For complete details consult the `specification`_.
.. _`Fernet`: https://github.com/fernet/spec/
.. _`specification`: https://github.com/fernet/spec/blob/master/Spec.md
.. _`recommends`: https://github.com/django/django/blob/master/django/utils/crypto.py#L148

74
docs/glossary.rst Normal file
View File

@ -0,0 +1,74 @@
Glossary
========
.. glossary::
:sorted:
plaintext
User-readable data you care about.
ciphertext
The encoded data, it's not user readable. Potential attackers are able
to see this.
encryption
The process of converting plaintext to ciphertext.
decryption
The process of converting ciphertext to plaintext.
key
Secret data is encoded with a function using this key. Sometimes
multiple keys are used. These **must** be kept secret, if a key is
exposed to an attacker, any data encrypted with it will be exposed.
symmetric cryptography
Cryptographic operations where encryption and decryption use the same
key.
public-key cryptography
asymmetric cryptography
Cryptographic operations where encryption and decryption use different
keys. There are separate encryption and decryption keys. Typically
encryption is performed using a :term:`public key`, and it can then be
decrypted using a :term:`private key`. Asymmetric cryptography can also
be used to create signatures, which can be generated with a
:term:`private key` and verified with a :term:`public key`.
public key
This is one of two keys involved in :term:`public-key cryptography`. It
can be used to encrypt messages for someone possessing the
corresponding :term:`private key` and to verify signatures created with
the corresponding :term:`private key`. This can be distributed
publicly, hence the name.
private key
This is one of two keys involved in :term:`public-key cryptography`. It
can be used to decrypt messages which were encrypted with the
corresponding :term:`public key`, as well as to create signatures,
which can be verified with the corresponding :term:`public key`. These
**must** be kept secret, if they are exposed, all encrypted messages
are compromised, and an attacker will be able to forge signatures.
authentication
The process of verifying that a message was created by a specific
individual (or program). Like encryption, authentication can be either
symmetric or asymmetric. Authentication is necessary for effective
encryption.
ciphertext indistinguishability
This is a property of encryption systems whereby two encrypted messages
aren't distinguishable without knowing the encryption key. This is
considered a basic, necessary property for a working encryption system.
text
This type corresponds to ``unicode`` on Python 2 and ``str`` on Python
3. This is equivalent to ``six.text_type``.
nonce
A nonce is a **n**\ umber used **once**. Nonces are used in many
cryptographic protocols. Generally, a nonce does not have to be secret
or unpredictable, but it must be unique. A nonce is often a random
or pseudo-random number (see :doc:`Random number generation
</random-numbers>`). Since a nonce does not have to be unpredictable,
it can also take a form of a counter.

View File

@ -0,0 +1,30 @@
.. 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/content/documentation/Security/Conceptual/cryptoservices/GeneralPurposeCrypto/GeneralPurposeCrypto.html#//apple_ref/doc/uid/TP40011172-CH9-SW10

View File

@ -0,0 +1,36 @@
.. hazmat::
Backends
========
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.
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()
:returns: An object that provides at least
:class:`~interfaces.CipherBackend`, :class:`~interfaces.HashBackend`, and
:class:`~interfaces.HMACBackend`.
Individual backends
-------------------
.. toctree::
:maxdepth: 1
openssl
commoncrypto
multibackend
interfaces

View File

@ -0,0 +1,706 @@
.. hazmat::
Backend interfaces
==================
.. currentmodule:: cryptography.hazmat.backends.interfaces
Backend implementations may provide a number of interfaces to support
operations such as :doc:`/hazmat/primitives/symmetric-encryption`,
:doc:`/hazmat/primitives/cryptographic-hashes`, and
:doc:`/hazmat/primitives/mac/hmac`.
A specific ``backend`` may provide one or more of these interfaces.
.. class:: CipherBackend
A backend that provides methods for using ciphers for encryption
and decryption.
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
: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``
.. method:: create_symmetric_encryption_ctx(cipher, mode)
Create a
:class:`~cryptography.hazmat.primitives.ciphers.CipherContext` that
can be used for encrypting data with the symmetric ``cipher`` using
the given ``mode``.
: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`
:raises ValueError: When tag is not None in an AEAD mode
.. method:: create_symmetric_decryption_ctx(cipher, mode)
Create a
:class:`~cryptography.hazmat.primitives.ciphers.CipherContext` that
can be used for decrypting data with the symmetric ``cipher`` using
the given ``mode``.
: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`
:raises ValueError: When tag is None in an AEAD mode
.. class:: HashBackend
A backend with methods for using cryptographic hash functions.
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
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:returns: ``True`` if the specified ``algorithm`` is supported by this
backend, otherwise ``False``.
.. method:: create_hash_ctx(algorithm)
Create a
:class:`~cryptography.hazmat.primitives.hashes.HashContext` that
uses the specified ``algorithm`` to calculate a message digest.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.hashes.HashContext`
.. class:: HMACBackend
A backend with methods for using cryptographic hash functions as message
authentication codes.
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
: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(key, algorithm)
Create a
:class:`~cryptography.hazmat.primitives.hashes.HashContext` that
uses the specified ``algorithm`` to calculate a hash-based message
authentication code.
: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`
.. class:: CMACBackend
.. versionadded:: 0.4
A backend with methods for using CMAC
.. method:: cmac_algorithm_supported(algorithm)
: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
uses the specified ``algorithm`` to calculate a message authentication code.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.interfaces.MACContext`
.. class:: PBKDF2HMACBackend
.. versionadded:: 0.2
A backend with methods for using PBKDF2 using HMAC as a PRF.
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
: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
: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``
:param bytes salt: A salt.
: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.
:param bytes key_material: The key material to use as a basis for
the derived key. This is typically a password.
:return bytes: Derived key.
.. class:: RSABackend
.. versionadded:: 0.2
A backend with methods for using RSA.
.. method:: generate_rsa_private_key(public_exponent, key_size)
:param int public_exponent: The public exponent of the new key.
Often one of the small Fermat primes 3, 5, 17, 257 or 65537.
:param int key_size: The length in bits of the modulus. Should be
at least 2048.
:return: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`.
:raises ValueError: If the public_exponent is not valid.
.. method:: rsa_padding_supported(padding)
Check if the specified ``padding`` is supported by the backend.
: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``.
.. method:: generate_rsa_parameters_supported(public_exponent, key_size)
Check if the specified parameters are supported for key generation by
the backend.
:param int public_exponent: The public exponent.
:param int key_size: The bit length of the generated modulus.
.. method:: load_rsa_private_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`.
:raises ValueError: This is raised when the values of ``p``, ``q``,
``private_exponent``, ``public_exponent``, or ``modulus`` do not
match the bounds specified in :rfc:`3447`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
.. method:: load_rsa_public_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`.
:raises ValueError: This is raised when the values of
``public_exponent`` or ``modulus`` do not match the bounds
specified in :rfc:`3447`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
.. class:: DSABackend
.. versionadded:: 0.4
A backend with methods for using DSA.
.. method:: generate_dsa_parameters(key_size)
: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.
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.
:return: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`.
.. method:: generate_dsa_private_key(parameters)
:param parameters: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`.
: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.
.. method:: generate_dsa_private_key_and_parameters(key_size)
: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.
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.
: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
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:returns: ``True`` if the specified ``algorithm`` is supported by this
backend, otherwise ``False``.
.. method:: dsa_parameters_supported(p, q, g)
:param int p: The p value of a DSA key.
:param int q: The q value of a DSA key.
:param int g: The g value of a DSA key.
:returns: ``True`` if the given values of ``p``, ``q``, and ``g`` are
supported by this backend, otherwise ``False``.
.. method:: load_dsa_parameter_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
.. method:: load_dsa_private_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
.. method:: load_dsa_public_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised
when any backend specific criteria are not met.
.. class:: EllipticCurveBackend
.. versionadded:: 0.5
.. method:: elliptic_curve_supported(curve)
: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
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurveSignatureAlgorithm`.
: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
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`.
.. method:: load_elliptic_curve_private_numbers(numbers)
:param numbers: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateNumbers`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`.
.. method:: load_elliptic_curve_public_numbers(numbers)
: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)
: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
.. versionadded:: 0.6
A backend with methods for working with any PEM encoded keys.
.. method:: load_pem_private_key(data, password)
:param bytes data: PEM data to load.
:param bytes password: The password to use if the data is encrypted.
Should be ``None`` if the data is not encrypted.
:return: A new instance of the appropriate type of private key that the
serialized data contains.
:raises ValueError: If the data could not be deserialized.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the data is
encrypted with an unsupported algorithm.
.. method:: load_pem_public_key(data)
:param bytes data: PEM data to load.
:return: A new instance of the appropriate type of public key
serialized data contains.
:raises ValueError: If the data could not be deserialized.
.. class:: DERSerializationBackend
.. versionadded:: 0.8
A backend with methods for working with DER encoded keys.
.. method:: load_der_private_key(data, password)
:param bytes data: DER data to load.
:param bytes password: The password to use if the data is encrypted.
Should be ``None`` if the data is not encrypted.
:return: A new instance of the appropriate type of private key that the
serialized data contains.
:raises ValueError: If the data could not be deserialized.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the data is
encrypted with an unsupported algorithm.
.. method:: load_der_public_key(data)
:param bytes data: DER data to load.
:return: A new instance of the appropriate type of public key
serialized data contains.
:raises ValueError: If the data could not be deserialized.
.. class:: X509Backend
.. versionadded:: 0.7
A backend with methods for working with X.509 objects.
.. method:: load_pem_x509_certificate(data)
:param bytes data: PEM formatted certificate data.
:returns: An instance of :class:`~cryptography.x509.Certificate`.
.. method:: load_der_x509_certificate(data)
:param bytes data: DER formatted certificate data.
:returns: An instance of :class:`~cryptography.x509.Certificate`.
.. method:: load_pem_x509_csr(data)
.. versionadded:: 0.9
:param bytes data: PEM formatted certificate signing request data.
:returns: An instance of
:class:`~cryptography.x509.CertificateSigningRequest`.
.. method:: load_der_x509_csr(data)
.. versionadded:: 0.9
:param bytes data: DER formatted certificate signing request data.
:returns: An instance of
:class:`~cryptography.x509.CertificateSigningRequest`.
.. method:: create_x509_csr(builder, private_key, algorithm)
.. versionadded:: 1.0
:param builder: An instance of
:class:`~cryptography.x509.CertificateSigningRequestBuilder`.
: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 request. When the request is
signed by a certificate authority, the private key's associated
public key will be stored in the resulting certificate.
:param algorithm: The
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
that will be used to generate the request signature.
: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
.. versionadded:: 0.9
A backend with methods for doing Diffie-Hellman key exchange.
.. 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
: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: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
:return: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
.. 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
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
:raises ValueError: If ``key_size`` is not at least 512.
.. method:: load_dh_private_numbers(numbers)
:param numbers: A
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`
instance.
: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.
.. method:: load_dh_public_numbers(numbers)
:param numbers: A
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`
instance.
: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.
.. method:: load_dh_parameter_numbers(numbers)
:param numbers: A
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`
instance.
: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)
: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``.
.. 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.

View File

@ -0,0 +1,45 @@
.. 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.

View File

@ -0,0 +1,110 @@
.. hazmat::
OpenSSL backend
===============
The `OpenSSL`_ C library. Cryptography supports OpenSSL version ``1.0.0`` and
greater.
.. data:: cryptography.hazmat.backends.openssl.backend
This is the exposed API for the OpenSSL backend.
It implements the following interfaces:
* :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`
* :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
* :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`
* :class:`~cryptography.hazmat.backends.interfaces.RSABackend`
* :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:: 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.
OS random engine
----------------
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
compromise the security of the system.
The approach this project has chosen to mitigate this vulnerability is to
include an engine that replaces the OpenSSL default CSPRNG with one that
sources its entropy from ``/dev/urandom`` on UNIX-like operating systems and
uses ``CryptGenRandom`` on Windows. This method of pulling from the system pool
allows us to avoid potential issues with `initializing the RNG`_ as well as
protecting us from the ``fork()`` weakness.
This engine is **active** by default when importing the OpenSSL backend. When
active this engine will be used to generate all the random data OpenSSL
requests.
When importing only the binding it is added to the engine list but
**not activated**.
OS random sources
-----------------
On OS X and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random`` and
utilizes the `Yarrow`_ algorithm.
On Windows the implementation of ``CryptGenRandom`` depends on which version of
the operation system you are using. See the `Microsoft documentation`_ for more
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.4.17 with working | ``getrandom(GRND_NONBLOCK)`` |
| ``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
.. _`Yarrow`: https://en.wikipedia.org/wiki/Yarrow_algorithm
.. _`Microsoft documentation`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx

View File

@ -0,0 +1,30 @@
.. 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.io
.. _`CommonCrypto`: https://developer.apple.com/library/content/documentation/Security/Conceptual/cryptoservices/GeneralPurposeCrypto/GeneralPurposeCrypto.html#//apple_ref/doc/uid/TP40011172-CH9-SW10

View File

@ -0,0 +1,23 @@
.. hazmat::
Bindings
========
.. module:: cryptography.hazmat.bindings
``cryptography`` aims to provide low-level CFFI based bindings to multiple
native C libraries. These provide no automatic initialization of the library
and may not provide complete wrappers for its API.
Using these functions directly is likely to require you to be careful in
managing memory allocation, locking and other resources.
Individual bindings
-------------------
.. toctree::
:maxdepth: 1
openssl
commoncrypto

View File

@ -0,0 +1,48 @@
.. hazmat::
OpenSSL binding
===============
.. currentmodule:: cryptography.hazmat.bindings.openssl.binding
These are `CFFI`_ bindings to the `OpenSSL`_ C library. Cryptography supports
OpenSSL version ``1.0.0`` and greater.
.. class:: cryptography.hazmat.bindings.openssl.binding.Binding()
This is the exposed API for the OpenSSL bindings. It has two public
attributes:
.. attribute:: ffi
This is a ``cffi.FFI`` instance. It can be used to allocate and
otherwise manipulate OpenSSL structures.
.. attribute:: lib
This is a ``cffi`` library. It can be used to call OpenSSL functions,
and access constants.
.. classmethod:: init_static_locks
Enables the best available locking callback for OpenSSL.
See :ref:`openssl-threading`.
.. _openssl-threading:
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.io
.. _`OpenSSL`: https://www.openssl.org/
.. _`thread safety facilities`: https://www.openssl.org/docs/man1.0.2/crypto/threads.html

View File

@ -0,0 +1,238 @@
.. hazmat::
Diffie-Hellman key exchange
===========================
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.dh
`Diffie-Hellman key exchange`_ (DH) is a method that allows two parties
to jointly agree on a shared secret using an insecure channel.
Exchange Algorithm
~~~~~~~~~~~~~~~~~~
For most applications the ``shared_key`` should be passed to a key
derivation function.
.. code-block:: pycon
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.asymmetric import dh
>>> parameters = dh.generate_parameters(generator=2, key_size=2048,
... backend=default_backend())
>>> private_key = parameters.generate_private_key()
>>> peer_public_key = parameters.generate_private_key().public_key()
>>> shared_key = private_key.exchange(peer_public_key)
DHE (or EDH), the ephemeral form of this exchange, is **strongly
preferred** over simple DH and provides `forward secrecy`_ when used.
You must generate a new private key using :func:`~DHParameters.generate_private_key` for
each :meth:`~DHPrivateKeyWithSerialization.exchange` when performing an DHE key
exchange.
To assemble a :class:`~DHParameters` and a :class:`~DHPublicKey` from
primitive integers, you must first create the
:class:`~DHParameterNumbers` and :class:`~DHPublicNumbers` objects. For
example if **p**, **g**, and **y** are :class:`int` objects received from a
peer::
pn = dh.DHParameterNumbers(p, g)
parameters = pn.parameters(default_backend())
peer_public_numbers = dh.DHPublicNumbers(y, pn)
peer_public_key = peer_public_numbers.public_key(default_backend())
See also the :class:`~cryptography.hazmat.backends.interfaces.DHBackend`
API for additional functionality.
Group parameters
~~~~~~~~~~~~~~~~
.. function:: generate_parameters(generator, key_size, backend)
.. versionadded:: 0.9
Generate a new DH parameter group for use with ``backend``.
:param generator: The :class:`int` to use as a generator. Must be
2 or 5.
:param key_size: The bit length of the prime modulus to generate.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.DHBackend`
instance.
:returns: DH parameters as a new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
:raises ValueError: If ``key_size`` is not at least 512.
.. class:: DHParameters
.. versionadded:: 0.9
.. method:: generate_private_key()
.. versionadded:: 0.9
Generate a DH private key. This method can be used to generate many
new private keys from a single set of parameters.
:return: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
.. class:: DHParametersWithSerialization
.. versionadded:: 0.9
Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
.. method:: parameter_numbers()
Return the numbers that make up this set of parameters.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameterNumbers`.
Key interfaces
~~~~~~~~~~~~~~
.. class:: DHPrivateKey
.. versionadded:: 0.9
.. attribute:: key_size
The bit length of the prime modulus.
.. method:: public_key()
Return the public key associated with this private key.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
.. method:: parameters()
Return the parameters associated with this private key.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
.. class:: DHPrivateKeyWithSerialization
.. versionadded:: 0.9
Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`.
.. method:: private_numbers()
Return the numbers that make up this private key.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateNumbers`.
.. method:: exchange(peer_public_key)
.. versionadded:: 1.7
:param DHPublicKeyWithSerialization peer_public_key: The public key for the
peer.
:return bytes: The agreed key. The bytes are ordered in 'big' endian.
.. class:: DHPublicKey
.. versionadded:: 0.9
.. attribute:: key_size
The bit length of the prime modulus.
.. method:: parameters()
Return the parameters associated with this private key.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`.
.. class:: DHPublicKeyWithSerialization
.. versionadded:: 0.9
Inherits from :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`.
.. method:: public_numbers()
Return the numbers that make up this public key.
:return: A :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicNumbers`.
Numbers
~~~~~~~
.. class:: DHParameterNumbers(p, g)
.. versionadded:: 0.8
The collection of integers that define a Diffie-Hellman group.
.. attribute:: p
:type: int
The prime modulus value.
.. attribute:: g
:type: int
The generator value. Must be 2 or 5.
.. class:: DHPrivateNumbers(x, public_numbers)
.. versionadded:: 0.8
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.
.. 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.
.. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
.. _`forward secrecy`: https://en.wikipedia.org/wiki/Forward_secrecy

View File

@ -0,0 +1,462 @@
.. hazmat::
DSA
===
.. module:: cryptography.hazmat.primitives.asymmetric.dsa
`DSA`_ is a `public-key`_ algorithm for signing messages.
Generation
~~~~~~~~~~
.. function:: generate_private_key(key_size, backend)
.. versionadded:: 0.5
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
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: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
: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
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`
.. function:: generate_parameters(key_size, backend)
.. versionadded:: 0.5
Generate DSA parameters using the provided ``backend``.
: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: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
: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
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`
Signing
~~~~~~~
Using a :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`
instance.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.asymmetric import dsa
>>> private_key = dsa.generate_private_key(
... 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()
There is a shortcut to sign sufficiently short messages directly:
.. doctest::
>>> data = b"this is some data I'd like to sign"
>>> signature = private_key.sign(
... data,
... hashes.SHA256()
... )
The ``signature`` is a ``bytes`` object, whose contents is DER encoded as
described in :rfc:`3279`. This can be decoded using
:func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`.
Verification
~~~~~~~~~~~~
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()
There is a shortcut to verify sufficiently short messages directly:
.. doctest::
>>> public_key.verify(
... signature,
... data,
... hashes.SHA256()
... )
``verifier()`` takes the signature in the same format as is returned by
``signer.finalize()``.
``verify()`` will raise an :class:`~cryptography.exceptions.InvalidSignature`
exception if the signature isn't valid.
Numbers
~~~~~~~
.. class:: DSAParameterNumbers(p, q, g)
.. versionadded:: 0.5
The collection of integers that make up a set of DSA parameters.
.. attribute:: p
:type: int
The public modulus.
.. attribute:: q
:type: int
The sub-group order.
.. attribute:: g
:type: int
The generator.
.. method:: parameters(backend)
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
:returns: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`.
.. class:: DSAPublicNumbers(y, parameter_numbers)
.. versionadded:: 0.5
The collection of integers that make up a DSA public key.
.. attribute:: y
:type: int
The public value ``y``.
.. attribute:: parameter_numbers
:type: :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`
The :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`
associated with the public key.
.. method:: public_key(backend)
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
:returns: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`.
.. class:: DSAPrivateNumbers(x, public_numbers)
.. versionadded:: 0.5
The collection of integers that make up a DSA private key.
.. warning::
Revealing the value of ``x`` will compromise the security of any
cryptographic operations performed.
.. attribute:: x
:type: int
The private value ``x``.
.. attribute:: public_numbers
:type: :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`
The :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`
associated with the private key.
.. method:: private_key(backend)
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
:returns: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`.
Key interfaces
~~~~~~~~~~~~~~
.. class:: DSAParameters
.. versionadded:: 0.3
`DSA`_ parameters.
.. method:: generate_private_key()
.. versionadded:: 0.5
Generate a DSA private key. This method can be used to generate many
new private keys from a single set of parameters.
:return: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`.
.. class:: DSAParametersWithNumbers
.. versionadded:: 0.5
Extends :class:`DSAParameters`.
.. method:: parameter_numbers()
Create a
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`
object.
:returns: A
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers`
instance.
.. class:: DSAPrivateKey
.. versionadded:: 0.3
A `DSA`_ private key.
.. method:: public_key()
:return: :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`
An DSA public key object corresponding to the values of the private key.
.. method:: parameters()
:return: :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`
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:`3279`.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext`
.. attribute:: key_size
:type: int
The bit length of :attr:`~DSAParameterNumbers.q`.
.. method:: sign(data, algorithm)
.. versionadded:: 1.5
.. versionchanged:: 1.6
:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`
can now be used as an ``algorithm``.
Sign one block of data which can be verified later by others using the
public key.
:param bytes data: The message string to sign.
: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.
:return bytes: Signature.
.. class:: DSAPrivateKeyWithSerialization
.. versionadded:: 0.8
Extends :class:`DSAPrivateKey`.
.. method:: private_numbers()
Create a
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers`
object.
:returns: A
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateNumbers`
instance.
.. method:: private_bytes(encoding, format, encryption_algorithm)
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.TraditionalOpenSSL`
or
:attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`)
and encryption algorithm (such as
:class:`~cryptography.hazmat.primitives.serialization.BestAvailableEncryption`
or :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PrivateFormat`
enum.
:param encryption_algorithm: An instance of an object conforming to the
:class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption`
interface.
:return bytes: Serialized key.
.. class:: DSAPublicKey
.. versionadded:: 0.3
A `DSA`_ public key.
.. attribute:: key_size
:type: int
The bit length of :attr:`~DSAParameterNumbers.q`.
.. method:: parameters()
:return: :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameters`
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:`3279`.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DSABackend`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext`
.. method:: public_numbers()
Create a
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`
object.
:returns: A
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers`
instance.
.. method:: public_bytes(encoding, format)
Allows serialization of the key to bytes. Encoding (
:attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or
:attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and
format (
:attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum.
:return bytes: Serialized key.
.. 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

View File

@ -0,0 +1,648 @@
.. hazmat::
Elliptic curve cryptography
===========================
.. module:: cryptography.hazmat.primitives.asymmetric.ec
.. function:: generate_private_key(curve, backend)
.. versionadded:: 0.5
Generate a new private key on ``curve`` for use with ``backend``.
: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`.
.. 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
-----------------------------------
.. class:: ECDSA(algorithm)
.. versionadded:: 0.5
The ECDSA signature algorithm first standardized in NIST publication
`FIPS 186-3`_, and later in `FIPS 186-4`_.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.asymmetric import ec
>>> 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()
There is a shortcut to sign sufficiently short messages directly:
.. doctest::
>>> 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 is DER encoded as
described in :rfc:`3279`. This can be decoded using
:func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`.
Verification requires the public key, the signature itself, the signed data, and knowledge of the hashing algorithm that was used when producing the signature:
>>> public_key = private_key.public_key()
>>> verifier = public_key.verifier(signature, ec.ECDSA(hashes.SHA256()))
>>> verifier.update(b"this is some data I'd like")
>>> verifier.update(b" to sign")
>>> verifier.verify()
True
The last call will either return ``True`` or raise an :class:`~cryptography.exceptions.InvalidSignature` exception.
.. 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)
.. versionadded:: 0.5
The collection of integers that make up an EC private key.
.. attribute:: public_numbers
:type: :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers`
The :class:`EllipticCurvePublicNumbers` which makes up the EC public
key associated with this EC private key.
.. attribute:: private_value
:type: int
The private value.
.. method:: private_key(backend)
Convert a collection of numbers into a private key suitable for doing
actual cryptographic operations.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`.
:returns: A new instance of :class:`EllipticCurvePrivateKey`.
.. class:: EllipticCurvePublicNumbers(x, y, curve)
.. versionadded:: 0.5
The collection of integers that make up an EC public key.
.. attribute:: curve
:type: :class:`EllipticCurve`
The elliptic curve for this key.
.. attribute:: x
:type: int
The affine x component of the public point used for verifying.
.. attribute:: y
:type: int
The affine y component of the public point used for verifying.
.. method:: public_key(backend)
Convert a collection of numbers into a public key suitable for doing
actual cryptographic operations.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`.
:returns: A new instance of :class:`EllipticCurvePublicKey`.
.. method:: encode_point()
.. 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
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.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.asymmetric import ec
>>> private_key = ec.generate_private_key(
... ec.SECP384R1(), default_backend()
... )
>>> peer_public_key = ec.generate_private_key(
... ec.SECP384R1(), default_backend()
... ).public_key()
>>> shared_key = private_key.exchange(ec.ECDH(), peer_public_key)
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.
Elliptic Curves
---------------
Elliptic curves provide equivalent security at much smaller key sizes than
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.
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
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 instances of :class:`EllipticCurve`.
.. class:: SECT571K1
.. versionadded:: 0.5
SECG curve ``sect571k1``. Also called NIST K-571.
.. class:: SECT409K1
.. versionadded:: 0.5
SECG curve ``sect409k1``. Also called NIST K-409.
.. class:: SECT283K1
.. versionadded:: 0.5
SECG curve ``sect283k1``. Also called NIST K-283.
.. class:: SECT233K1
.. versionadded:: 0.5
SECG curve ``sect233k1``. Also called NIST K-233.
.. class:: SECT163K1
.. versionadded:: 0.5
SECG curve ``sect163k1``. Also called NIST K-163.
.. class:: SECT571R1
.. versionadded:: 0.5
SECG curve ``sect571r1``. Also called NIST B-571.
.. class:: SECT409R1
.. versionadded:: 0.5
SECG curve ``sect409r1``. Also called NIST B-409.
.. class:: SECT283R1
.. versionadded:: 0.5
SECG curve ``sect283r1``. Also called NIST B-283.
.. class:: SECT233R1
.. versionadded:: 0.5
SECG curve ``sect233r1``. Also called NIST B-233.
.. class:: SECT163R2
.. versionadded:: 0.5
SECG curve ``sect163r2``. Also called NIST B-163.
.. class:: SECP521R1
.. versionadded:: 0.5
SECG curve ``secp521r1``. Also called NIST P-521.
.. class:: SECP384R1
.. versionadded:: 0.5
SECG curve ``secp384r1``. Also called NIST P-384.
.. class:: SECP256R1
.. versionadded:: 0.5
SECG curve ``secp256r1``. Also called NIST P-256.
.. class:: SECT224R1
.. versionadded:: 0.5
SECG curve ``secp224r1``. Also called NIST P-224.
.. class:: SECP192R1
.. versionadded:: 0.5
SECG curve ``secp192r1``. Also called NIST P-192.
.. class:: SECP256K1
.. versionadded:: 0.9
SECG curve ``secp256k1``.
Key Interfaces
~~~~~~~~~~~~~~
.. class:: EllipticCurve
.. versionadded:: 0.5
A named elliptic curve.
.. attribute:: name
:type: string
The name of the curve. Usually the name used for the ASN.1 OID such as
``secp256k1``.
.. attribute:: key_size
:type: int
Size (in 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` or
:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`
The digest algorithm to be used with the signature scheme.
.. class:: EllipticCurvePrivateKey
.. versionadded:: 0.5
An elliptic curve private key for use with an algorithm such as `ECDSA`_ or
`EdDSA`_.
.. method:: signer(signature_algorithm)
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:`3279`.
:param signature_algorithm: An instance of
:class:`EllipticCurveSignatureAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext`
.. method:: exchange(algorithm, peer_public_key)
.. versionadded:: 1.1
Perform's a key exchange operation using the provided algorithm with
the peer's public key.
For most applications the result should be passed to a key derivation
function.
: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()
:return: :class:`EllipticCurvePublicKey`
The EllipticCurvePublicKey object for this private key.
.. method:: sign(data, signature_algorithm)
.. versionadded:: 1.5
Sign one block of data which can be verified later by others using the
public key.
:param bytes data: The message string to sign.
:param signature_algorithm: An instance of
:class:`EllipticCurveSignatureAlgorithm`, such as :class:`ECDSA`.
:return bytes: Signature.
.. class:: EllipticCurvePrivateKeyWithSerialization
.. versionadded:: 0.8
Extends :class:`EllipticCurvePrivateKey`.
.. method:: private_numbers()
Create a :class:`EllipticCurvePrivateNumbers` object.
:returns: An :class:`EllipticCurvePrivateNumbers` instance.
.. method:: private_bytes(encoding, format, encryption_algorithm)
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.TraditionalOpenSSL`
or
:attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`)
and encryption algorithm (such as
:class:`~cryptography.hazmat.primitives.serialization.BestAvailableEncryption`
or :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` enum.
:param encryption_algorithm: An instance of an object conforming to the
:class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption`
interface.
:return bytes: Serialized key.
.. class:: EllipticCurvePublicKey
.. versionadded:: 0.5
An elliptic curve public key.
.. method:: verifier(signature, signature_algorithm)
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:`3279`.
:param signature_algorithm: An instance of
:class:`EllipticCurveSignatureAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext`
.. attribute:: curve
:type: :class:`EllipticCurve`
The elliptic curve for this key.
.. method:: public_numbers()
Create a :class:`EllipticCurvePublicNumbers` object.
:returns: An :class:`EllipticCurvePublicNumbers` instance.
.. method:: public_bytes(encoding, format)
Allows serialization of the key to bytes. Encoding (
:attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or
:attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and
format (
:attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum.
:return bytes: Serialized key.
.. method:: verify(signature, data, signature_algorithm)
.. versionadded:: 1.5
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 signature_algorithm: An instance of
:class:`EllipticCurveSignatureAlgorithm`.
:raises cryptography.exceptions.InvalidSignature: If the signature does
not validate.
.. class:: EllipticCurvePublicKeyWithSerialization
.. versionadded:: 0.6
Alias for :class:`EllipticCurvePublicKey`.
Serialization
~~~~~~~~~~~~~
This sample demonstrates how to generate a private key and serialize it.
.. 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 import serialization
>>> 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]
'-----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]
'-----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,
... password=b'testpassword', # or password=None, if in plain text
... backend=default_backend()
... )
.. _`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
.. _`800-56A`: http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
.. _`800-56Ar2`: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
.. _`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
.. _`elliptic curve diffie-hellman is faster than diffie-hellman`: http://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`: http://www.secg.org/sec1-v2.pdf

View File

@ -0,0 +1,38 @@
.. hazmat::
Asymmetric algorithms
=====================
Asymmetric cryptography is a branch of cryptography where a secret key can be
divided into two parts, a :term:`public key` and a :term:`private key`. The
public key can be given to anyone, trusted or not, while the private key must
be kept secret (just like the key in symmetric cryptography).
Asymmetric cryptography has two primary use cases: authentication and
confidentiality. Using asymmetric cryptography, messages can be signed with a
private key, and then anyone with the public key is able to verify that the
message was created by someone possessing the corresponding private key. This
can be combined with a `proof of identity`_ system to know what entity (person
or group) actually owns that private key, providing authentication.
Encryption with asymmetric cryptography works in a slightly different way from
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
ec
rsa
dh
serialization
interfaces
utils
.. _`proof of identity`: https://en.wikipedia.org/wiki/Public-key_infrastructure

View File

@ -0,0 +1,32 @@
.. 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.

View File

@ -0,0 +1,745 @@
.. hazmat::
RSA
===
.. module:: cryptography.hazmat.primitives.asymmetric.rsa
`RSA`_ is a `public-key`_ algorithm for encrypting and signing messages.
Generation
~~~~~~~~~~
Unlike symmetric cryptography, where the key is typically just a random series
of bytes, RSA keys have a complex internal structure with `specific
mathematical properties`_.
.. function:: generate_private_key(public_exponent, key_size, backend)
.. 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
new keys. The ``public_exponent`` indicates what one mathematical property
of the key generation will be, ``65537`` should almost always be used.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> private_key = rsa.generate_private_key(
... public_exponent=65537,
... key_size=2048,
... backend=default_backend()
... )
:param int public_exponent: The public exponent of the new key.
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
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 implements
:class:`~cryptography.hazmat.backends.interfaces.RSABackend`.
:return: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if
the provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.RSABackend`
Key loading
~~~~~~~~~~~
If you already have an on-disk key in the PEM format (which are recognizable by
the distinctive ``-----BEGIN {format}-----`` and ``-----END {format}-----``
markers), you can load it:
.. code-block:: pycon
>>> from cryptography.hazmat.primitives import serialization
>>> with open("path/to/key.pem", "rb") as key_file:
... private_key = serialization.load_pem_private_key(
... key_file.read(),
... password=None,
... backend=default_backend()
... )
Serialized keys may optionally be encrypted on disk using a password. In this
example we loaded an unencrypted key, and therefore we did not provide a
password. If the key is encrypted we can pass a ``bytes`` object as the
``password`` argument.
There is also support for :func:`loading public keys in the SSH format
<cryptography.hazmat.primitives.serialization.load_ssh_public_key>`.
Key serialization
~~~~~~~~~~~~~~~~~
If you have a private key that you've loaded or generated which implements the
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
interface you can use
:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`
to serialize the key.
.. doctest::
>>> from cryptography.hazmat.primitives import serialization
>>> pem = private_key.private_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PrivateFormat.PKCS8,
... encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword')
... )
>>> pem.splitlines()[0]
'-----BEGIN ENCRYPTED PRIVATE KEY-----'
It is also possible to serialize without encryption using
:class:`~cryptography.hazmat.primitives.serialization.NoEncryption`.
.. doctest::
>>> pem = private_key.private_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PrivateFormat.TraditionalOpenSSL,
... encryption_algorithm=serialization.NoEncryption()
... )
>>> pem.splitlines()[0]
'-----BEGIN RSA PRIVATE KEY-----'
For public keys you can use
:meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.public_bytes`
to serialize the key.
.. doctest::
>>> from cryptography.hazmat.primitives import serialization
>>> public_key = private_key.public_key()
>>> pem = public_key.public_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PublicFormat.SubjectPublicKeyInfo
... )
>>> pem.splitlines()[0]
'-----BEGIN PUBLIC KEY-----'
Signing
~~~~~~~
A private key can be used to sign a message. This allows anyone with the public
key to verify that the message was created by someone who possesses the
corresponding private key. RSA signatures require a specific hash function, and
padding to be used. Here is an example of signing ``message`` using RSA, with a
secure hash function and padding:
.. doctest::
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.asymmetric import padding
>>> signer = private_key.signer(
... 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()
There is a shortcut to sign sufficiently short messages directly:
.. doctest::
>>> 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()
... )
Valid paddings for signatures are
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` and
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`. ``PSS``
is the recommended choice for any new protocols or applications, ``PKCS1v15``
should only be used to support legacy protocols.
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, 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(
... signature,
... 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.
There is a shortcut to verify sufficiently short messages directly:
.. doctest::
>>> public_key.verify(
... signature,
... message,
... padding.PSS(
... mgf=padding.MGF1(hashes.SHA256()),
... salt_length=padding.PSS.MAX_LENGTH
... ),
... hashes.SHA256()
... )
Encryption
~~~~~~~~~~
RSA encryption is interesting because encryption is performed using the
**public** key, meaning anyone can encrypt data. The data is then decrypted
using the **private** key.
Like signatures, RSA supports encryption with several different padding
options. Here's an example using a secure padding and hash function:
.. doctest::
>>> message = b"encrypted data"
>>> ciphertext = public_key.encrypt(
... message,
... padding.OAEP(
... mgf=padding.MGF1(algorithm=hashes.SHA1()),
... algorithm=hashes.SHA1(),
... label=None
... )
... )
Valid paddings for encryption are
:class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP` and
:class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`. ``OAEP``
is the recommended choice for any new protocols or applications, ``PKCS1v15``
should only be used to support legacy protocols.
Decryption
~~~~~~~~~~
Once you have an encrypted message, it can be decrypted using the private key:
.. doctest::
>>> plaintext = private_key.decrypt(
... ciphertext,
... padding.OAEP(
... mgf=padding.MGF1(algorithm=hashes.SHA1()),
... algorithm=hashes.SHA1(),
... label=None
... )
... )
>>> plaintext == message
True
Padding
~~~~~~~
.. module:: cryptography.hazmat.primitives.asymmetric.padding
.. class:: AsymmetricPadding
.. versionadded:: 0.2
.. attribute:: name
.. class:: PSS(mgf, salt_length)
.. versionadded:: 0.3
.. versionchanged:: 0.4
Added ``salt_length`` parameter.
PSS (Probabilistic Signature Scheme) is a signature scheme defined in
:rfc:`3447`. It is more complex than PKCS1 but possesses a `security proof`_.
This is the `recommended padding algorithm`_ for RSA signatures. It cannot
be used with RSA encryption.
:param mgf: A mask generation function object. At this time the only
supported MGF is :class:`MGF1`.
:param int salt_length: The length of the salt. It is recommended that this
be set to ``PSS.MAX_LENGTH``.
.. attribute:: MAX_LENGTH
Pass this attribute to ``salt_length`` to get the maximum salt length
available.
.. class:: OAEP(mgf, algorithm, label)
.. versionadded:: 0.4
OAEP (Optimal Asymmetric Encryption Padding) is a padding scheme defined in
:rfc:`3447`. It provides probabilistic encryption and is `proven secure`_
against several attack types. This is the `recommended padding algorithm`_
for RSA encryption. It cannot be used with RSA signing.
: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.
.. class:: PKCS1v15()
.. versionadded:: 0.3
PKCS1 v1.5 (also known as simply PKCS1) is a simple padding scheme
developed for use with RSA keys. It is defined in :rfc:`3447`. This padding
can be used for signing and encryption.
It is not recommended that ``PKCS1v15`` be used for new applications,
: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
-------------------------
.. class:: MGF1(algorithm)
.. versionadded:: 0.3
.. versionchanged:: 0.6
Removed the deprecated ``salt_length`` parameter.
MGF1 (Mask Generation Function 1) is used as the mask generation function
in :class:`PSS` and :class:`OAEP` padding. It takes a hash algorithm.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
Numbers
~~~~~~~
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.rsa
These classes hold the constituent components of an RSA key. They are useful
only when more traditional :doc:`/hazmat/primitives/asymmetric/serialization`
is unavailable.
.. class:: RSAPublicNumbers(e, n)
.. versionadded:: 0.5
The collection of integers that make up an RSA public key.
.. attribute:: n
:type: int
The public modulus.
.. attribute:: e
:type: int
The public exponent.
.. method:: public_key(backend)
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.RSABackend`.
:returns: A new instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`.
.. class:: RSAPrivateNumbers(p, q, d, dmp1, dmq1, iqmp, public_numbers)
.. versionadded:: 0.5
The collection of integers that make up an RSA private key.
.. warning::
With the exception of the integers contained in the
:class:`RSAPublicNumbers` all attributes of this class must be kept
secret. Revealing them will compromise the security of any
cryptographic operations performed with a key loaded from them.
.. attribute:: public_numbers
:type: :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers`
The :class:`RSAPublicNumbers` which makes up the RSA public key
associated with this RSA private key.
.. attribute:: p
:type: int
``p``, one of the two primes composing ``n``.
.. attribute:: q
:type: int
``q``, one of the two primes composing ``n``.
.. attribute:: d
:type: int
The private exponent.
.. attribute:: dmp1
:type: int
A `Chinese remainder theorem`_ coefficient used to speed up RSA
operations. Calculated as: d mod (p-1)
.. attribute:: dmq1
:type: int
A `Chinese remainder theorem`_ coefficient used to speed up RSA
operations. Calculated as: d mod (q-1)
.. attribute:: iqmp
:type: int
A `Chinese remainder theorem`_ coefficient used to speed up RSA
operations. Calculated as: q\ :sup:`-1` mod p
.. method:: private_key(backend)
:param backend: A new instance of
:class:`~cryptography.hazmat.backends.interfaces.RSABackend`.
:returns: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`.
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
the ``iqmp``, ``dmp1`` or ``dmq1`` parameters.
The following functions are provided for users who want to work with keys like
this without having to do the math themselves.
.. function:: rsa_crt_iqmp(p, q)
.. versionadded:: 0.4
Computes the ``iqmp`` (also known as ``qInv``) parameter from the RSA
primes ``p`` and ``q``.
.. function:: rsa_crt_dmp1(private_exponent, p)
.. versionadded:: 0.4
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 (``d``) and
prime ``q``.
.. function:: rsa_recover_prime_factors(n, e, d)
.. versionadded:: 0.8
Computes the prime factors ``(p, q)`` given the modulus, public exponent,
and private exponent.
.. note::
When recovering prime factors this algorithm will always return ``p``
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)``
Key interfaces
~~~~~~~~~~~~~~
.. class:: RSAPrivateKey
.. versionadded:: 0.2
An `RSA`_ private key.
.. method:: signer(padding, algorithm)
.. versionadded:: 0.3
Get signer to sign data which can be verified later by others using
the public key.
:param padding: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricSignatureContext`
.. method:: decrypt(ciphertext, padding)
.. versionadded:: 0.4
Decrypt data that was encrypted with the public key.
:param bytes ciphertext: The ciphertext to decrypt.
:param padding: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`.
:return bytes: Decrypted data.
.. method:: public_key()
:return: :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`
An RSA public key object corresponding to the values of the private key.
.. attribute:: key_size
:type: int
The bit length of the modulus.
.. method:: sign(data, padding, algorithm)
.. versionadded:: 1.4
.. versionchanged:: 1.6
:class:`~cryptography.hazmat.primitives.asymmetric.utils.Prehashed`
can now be used as an ``algorithm``.
Sign one block of data which can be verified later by others using the
public key.
:param bytes data: The message string to sign.
: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 sign has already been hashed.
:return bytes: Signature.
.. class:: RSAPrivateKeyWithSerialization
.. versionadded:: 0.8
Extends :class:`RSAPrivateKey`.
.. method:: private_numbers()
Create a
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`
object.
:returns: An
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers`
instance.
.. method:: private_bytes(encoding, format, encryption_algorithm)
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.TraditionalOpenSSL`
or
:attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`)
and encryption algorithm (such as
:class:`~cryptography.hazmat.primitives.serialization.BestAvailableEncryption`
or :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PrivateFormat`
enum.
:param encryption_algorithm: An instance of an object conforming to the
:class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption`
interface.
:return bytes: Serialized key.
.. class:: RSAPublicKey
.. versionadded:: 0.2
An `RSA`_ public key.
.. method:: verifier(signature, padding, algorithm)
.. versionadded:: 0.3
Get verifier to 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
:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`.
:param algorithm: An instance of
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`.
:returns:
:class:`~cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext`
.. method:: encrypt(plaintext, padding)
.. versionadded:: 0.4
Encrypt data with the public key.
:param bytes plaintext: The plaintext to encrypt.
:param padding: An instance of
:class:`~cryptography.hazmat.primitives.asymmetric.padding.AsymmetricPadding`.
:return bytes: Encrypted data.
.. attribute:: key_size
:type: int
The bit length of the modulus.
.. method:: public_numbers()
Create a
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers`
object.
:returns: An
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicNumbers`
instance.
.. method:: public_bytes(encoding, format)
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`
or
:attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.PKCS1`)
are chosen to define the exact serialization.
:param encoding: A value from the
:class:`~cryptography.hazmat.primitives.serialization.Encoding` enum.
:param format: A value from the
:class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum.
:return bytes: Serialized key.
.. 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 sign 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
.. _`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`: https://eprint.iacr.org/2001/062.pdf
.. _`recommended padding algorithm`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html
.. _`proven secure`: https://cseweb.ucsd.edu/~mihir/papers/oae.pdf

View File

@ -0,0 +1,438 @@
.. hazmat::
Key Serialization
=================
.. module:: cryptography.hazmat.primitives.serialization
.. testsetup::
import base64
pem_data = b"""
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDn09PV9KPE7Q+N5K5UtNLT1DLl8z/pKM2pP5tXqWx2OsEw00lC
kDHdHESwzS050s/8rtkERKKyusCzCm9+vC1pQzUlmtibfF4PQAQc1pJL6KHqlidg
Hw49atYmnC25CaeXt65pAYXoIacOZ8k5X7FW3Eagex8nG0iMw4ObOtg6CwIDAQAB
AoGBAL31l/4YYN1rNrSZLrQgGyUSGsbLxJHEKolFon95R3O1fzoH117gkstQb4TE
Cwv3jw/JIfBaYUq8tku/AE9D2Jx51x7kYaCuQIMTavKIgkXKfxTQCQDjSEfkvXMW
4WOIj5sYdSCNbzLbaeFsWG32bSsBTy/sSheDIlCEFnqDuqwBAkEA+wYfJEMDf5nS
VCQd9VKGM4HVeTWBioaWBFCflFdhc1Vb65dsNDp8iIMZgAHC2LEX5dMUmgqXk7AT
lwFlIeW4CwJBAOxsSfuIVMuPKyx1xQ6ebpC7zeVxIOdswcM8ain91MSGDdKZw6pF
ioFh3kUbKHw4yqqHbdRmUDAJ1mcgGJQOxgECQQCmQaGylKfmhWymyd0FtIip6J4I
z4ViyEznwrZOu6kRiEF/QiUqWmpMx/fFrmTsvC5Fy43jkIxgBsiSxRvEXa+NAkB+
5m0bhwTEslchKSGZhC6inzuYAQ4BSh4C1mXBnk5bIf0/Ymtk9KiwY8CzZS1o5+7Y
c5LfI/+8mTss5UxsBDYBAkEA6NqhcsNWndIJZiWUU4u+RjFUQXqH8WCyJmEDCNxs
7SGRS1DTUGX4Y70m9dQpguy6Zg+gpHC+o+ERZR06uEQr+w==
-----END RSA PRIVATE KEY-----
""".strip()
public_pem_data = b"""
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDn09PV9KPE7Q+N5K5UtNLT1DLl
8z/pKM2pP5tXqWx2OsEw00lCkDHdHESwzS050s/8rtkERKKyusCzCm9+vC1pQzUl
mtibfF4PQAQc1pJL6KHqlidgHw49atYmnC25CaeXt65pAYXoIacOZ8k5X7FW3Eag
ex8nG0iMw4ObOtg6CwIDAQAB
-----END PUBLIC KEY-----
""".strip()
der_data = base64.b64decode(
b"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALskegl+DrI3Msw5Z63x"
b"nj1rgoPR0KykwBi+jZgAwHv/B0TJyhy6NuEnaf+x442L7lepOqoWQzlUGXyuaSQU9mT/"
b"vHTGZ2xM8QJJaccr4eGho0MU9HePyNCFWjWVrGKpwSEAd6CLlzC0Wiy4kC9IoAUoS/IP"
b"jeyLTQNCddatgcARAgMBAAECgYAA/LlKJgeJUStTcpHgGD6mXjHvnAwWJELQKDP5+tA8"
b"VAQGwBX1G5qzJDGrPGtHQ7DSqdwF4YFZtgTpZmGq1wsAjz3lv6L4XiVsHiIPtP1B4gMx"
b"X9ogxcDzVQ7hyezXPioMAcp7Isus9Csn8HhftcL56BRabn6GvWqbIAy6zJcgEQJBAMlZ"
b"nymKW5/jKth+wkCfqEXlPhGNPO1uq87QZUbYxwdjtSM09J9+HMfH+WXR9ARCOL46DJ0I"
b"JfyjcdmuDDlh9IkCQQDt76up1Tmc7lkb/89IRBu2MudGJPMEf96VCG11nmcXulyk1OLi"
b"TXfO62YpxZbgYrvlrNxEYlSG7WQMztBgA51JAkBU2RhyJ+S+drsaaigvlVgSxCyotszi"
b"/Q0XZMgY18bfPUwanvkqsLkuEv3sw1HB7an9t3aTQdjIIpQad/acw8OJAkEAjvmnCK21"
b"KgTbjQShtQYgNNLPwImxcjG4OYvP4o6l2k9FHlNCZsQwSymOwWkXKYyK5g+CaKFBs7Zw"
b"mXWpJxjk6QJBAInqbm1w3yVfGD9I2mMQi/6oDJQP3pdWU4mU4h4sdDyRgTQLpkD4yypg"
b"jOACt4mTzxifSVT9fT+a79SkT8FFmZE="
)
public_der_data = base64.b64decode(
b"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7JHoJfg6yNzLMOWet8Z49a4KD0dCs"
b"pMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkkFPZk/7x0xmdsTPEC"
b"SWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAvSKAFKEvyD43si00DQnXW"
b"rYHAEQIDAQAB"
)
message = b""
def sign_with_rsa_key(key, message):
return b""
def sign_with_dsa_key(key, message):
return b""
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.
Many serialization formats support multiple different types of asymmetric keys
and will return an instance of the appropriate type. You should check that
the returned key matches the type your application expects when using these
methods.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.asymmetric import dsa, rsa
>>> from cryptography.hazmat.primitives.serialization import load_pem_private_key
>>> key = load_pem_private_key(pem_data, password=None, backend=default_backend())
>>> if isinstance(key, rsa.RSAPrivateKey):
... signature = sign_with_rsa_key(key, message)
... elif isinstance(key, dsa.DSAPrivateKey):
... signature = sign_with_dsa_key(key, message)
... 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
bytes 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
~~~
PEM is an encapsulation format, meaning keys in it can actually be any of
several different key types. However these are all self-identifying, so you
don't need to worry about this detail. PEM keys are recognizable because they
all begin with ``-----BEGIN {format}-----`` and end with ``-----END
{format}-----``.
.. note::
A PEM block which starts with ``-----BEGIN CERTIFICATE-----`` is not a
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>`.
.. function:: load_pem_private_key(data, password, backend)
.. versionadded:: 0.6
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 bytes password: The password to use to decrypt the data. Should
be ``None`` if the private key is not encrypted.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`.
:returns: One of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`,
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.
:raises TypeError: If a ``password`` was given and the private key was
not encrypted. Or if the key was encrypted but no
password was supplied.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key
is of a type that is not supported by the backend or if the key is
encrypted with a symmetric cipher that is not supported by the backend.
.. function:: load_pem_public_key(data, backend)
.. versionadded:: 0.6
Deserialize a public key from PEM encoded data to one of the supported
asymmetric public key types. The PEM encoded data is typically a
``subjectPublicKeyInfo`` payload as specified in :rfc:`5280`.
.. doctest::
>>> from cryptography.hazmat.primitives.serialization import load_pem_public_key
>>> key = load_pem_public_key(public_pem_data, backend=default_backend())
>>> isinstance(key, rsa.RSAPublicKey)
True
:param bytes data: The PEM encoded key data.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`.
:returns: One of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
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.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key
is of a type that is not supported by the backend.
DER
~~~
DER is an ASN.1 encoding type. There are no encapsulation boundaries and the
data is binary. DER keys may be in a variety of formats, but as long as you
know whether it is a public or private key the loading functions will handle
the rest.
.. function:: load_der_private_key(data, password, backend)
.. versionadded:: 0.8
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 bytes password: The password to use to decrypt the data. Should
be ``None`` if the private key is not encrypted.
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`.
:returns: One of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`,
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.
:raises TypeError: If a ``password`` was given and the private key was
not encrypted. Or if the key was encrypted but no
password was supplied.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that
is not supported by the backend or if the key is encrypted with a
symmetric cipher that is not supported by the backend.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> from cryptography.hazmat.primitives.serialization import load_der_private_key
>>> key = load_der_private_key(der_data, password=None, backend=default_backend())
>>> isinstance(key, rsa.RSAPrivateKey)
True
.. function:: load_der_public_key(data, backend)
.. versionadded:: 0.8
Deserialize a public key from DER encoded data to one of the supported
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: An instance of
:class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`.
:returns: One of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
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.
: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 rsa
>>> from cryptography.hazmat.primitives.serialization import load_der_public_key
>>> key = load_der_public_key(public_der_data, backend=default_backend())
>>> isinstance(key, rsa.RSAPublicKey)
True
OpenSSH Public Key
~~~~~~~~~~~~~~~~~~
The format used by OpenSSH to store public keys, as specified in :rfc:`4253`.
An example RSA key in OpenSSH format (line breaks added for formatting
purposes)::
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk
FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll
PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK
vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f
sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy
///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX
2MzHvnbv testkey@localhost
DSA keys look almost identical but begin with ``ssh-dss`` rather than
``ssh-rsa``. ECDSA keys have a slightly different format, they begin with
``ecdsa-sha2-{curve}``.
.. function:: load_ssh_public_key(data, backend)
.. versionadded:: 0.7
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 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: One of
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`,
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`,
or
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
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.
:raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized
key is of a type that is not supported.
Serialization Formats
~~~~~~~~~~~~~~~~~~~~~
.. class:: PrivateFormat
.. versionadded:: 0.8
An enumeration for private key formats. Used with the ``private_bytes``
method available on
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`
and
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`.
.. attribute:: TraditionalOpenSSL
Frequently known as PKCS#1 format. Still a widely used format, but
generally considered legacy.
.. attribute:: PKCS8
A more modern format for serializing keys which allows for better
encryption. Choose this unless you have explicit legacy compatibility
requirements.
.. class:: PublicFormat
.. versionadded:: 0.8
An enumeration for public key formats. Used with the ``public_bytes``
method available on
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`
,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`
, and
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`.
.. attribute:: SubjectPublicKeyInfo
This is the typical public key format. It consists of an algorithm
identifier and the public key as a bit string. Choose this unless
you have specific needs.
.. attribute:: PKCS1
Just the public key elements (without the algorithm identifier). This
format is RSA only, but is used by some older systems.
.. 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``).
Serialization Encodings
~~~~~~~~~~~~~~~~~~~~~~~
.. class:: Encoding
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`
and
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`
as well as ``public_bytes`` on
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`
and
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`.
.. 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.
Serialization Encryption Types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. class:: KeySerializationEncryption
Objects with this interface are usable as encryption types with methods
like ``private_bytes`` available on
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`
,
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`
and
:class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`.
All other classes in this section represent the available choices for
encryption and have this interface. They are used with
:class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization.private_bytes`.
.. class:: BestAvailableEncryption(password)
Encrypt using the best available encryption for a given key's backend.
This is a curated encryption choice and the algorithm may change over
time.
:param bytes password: The password to use for encryption.
.. class:: NoEncryption
Do not encrypt.

View File

@ -0,0 +1,88 @@
.. hazmat::
Asymmetric Utilities
====================
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.utils
.. function:: decode_dss_signature(signature)
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.
:returns: The decoded tuple ``(r, s)``.
:raises ValueError: Raised if the signature is malformed.
.. function:: encode_dss_signature(r, s)
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())
... )

View File

@ -0,0 +1,43 @@
.. hazmat::
Constant time functions
=======================
.. currentmodule:: cryptography.hazmat.primitives.constant_time
This module contains functions for operating with secret data in a way that
does not leak information about that data through how long it takes to perform
the operation. These functions should be used whenever operating on secret data
along with data that is user supplied.
An example would be comparing a HMAC signature received from a client to the
one generated by the server code for authentication purposes.
For more information about this sort of issue, see `Coda Hale's blog post`_
about the timing attacks on KeyCzar and Java's ``MessageDigest.isEqual()``.
.. function:: bytes_eq(a, b)
Compares ``a`` and ``b`` with one another. If ``a`` and ``b`` have
different lengths, this returns ``False`` immediately. Otherwise it
compares them in a way that takes the same amount of time, regardless of
how many characters are the same between the two.
.. doctest::
>>> from cryptography.hazmat.primitives import constant_time
>>> constant_time.bytes_eq(b"foo", b"foo")
True
>>> constant_time.bytes_eq(b"foo", b"bar")
False
:param bytes a: The left-hand side.
:param bytes b: The right-hand side.
:returns bool: ``True`` if ``a`` has the same bytes as ``b``, otherwise
``False``.
:raises TypeError: This exception is raised if ``a`` or ``b`` is not
``bytes``.
.. _`Coda Hale's blog post`: https://codahale.com/a-lesson-in-timing-attacks/

View File

@ -0,0 +1,229 @@
.. hazmat::
Message digests
===============
.. module:: cryptography.hazmat.primitives.hashes
.. class:: Hash(algorithm, backend)
A cryptographic hash function takes an arbitrary block of data and
calculates a fixed-size bit string (a digest), such that different data
results (with a high probability) in different digests.
This is an implementation of
:class:`~cryptography.hazmat.primitives.hashes.HashContext` meant to
be used with
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
implementations to provide an incremental interface to calculating
various message digests.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes
>>> digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
>>> 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'
If the backend doesn't support the requested ``algorithm`` an
:class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be
raised.
Keep in mind that attacks against cryptographic hashes only get stronger
with time, and that often algorithms that were once thought to be strong,
become broken. Because of this it's important to include a plan for
upgrading the hash algorithm you use over time. For more information, see
`Lifetimes of cryptographic hash functions`_.
:param algorithm: A
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
instance such as those described in
:ref:`below <cryptographic-hash-algorithms>`.
:param backend: A
: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`
.. method:: update(data)
:param bytes data: The bytes to be hashed.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
:raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: copy()
Copy this :class:`Hash` instance, usually so that you may call
:meth:`finalize` to get an intermediate digest value while we continue
to call :meth:`update` on the original instance.
:return: A new instance of :class:`Hash` that can be updated
and finalized independently of the original instance.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
.. method:: finalize()
Finalize the current context and return the message digest as bytes.
After ``finalize`` has been called this object can no longer be used
and :meth:`update`, :meth:`copy`, and :meth:`finalize` will raise an
:class:`~cryptography.exceptions.AlreadyFinalized` exception.
:return bytes: The message digest as bytes.
.. _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. Cryptanalysis of SHA-1 has demonstrated that it is
vulnerable to practical collision attacks, though no actual collisions are
publicly known.
SHA-2 family
~~~~~~~~~~~~
.. class:: SHA224()
SHA-224 is a cryptographic hash function from the SHA-2 family and is
standardized by NIST. It produces a 224-bit message digest.
.. class:: SHA256()
SHA-256 is a cryptographic hash function from the SHA-2 family and is
standardized by NIST. It produces a 256-bit message digest.
.. class:: SHA384()
SHA-384 is a cryptographic hash function from the SHA-2 family and is
standardized by NIST. It produces a 384-bit message digest.
.. class:: SHA512()
SHA-512 is a cryptographic hash function from the SHA-2 family and is
standardized by NIST. It produces a 512-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.
RIPEMD160
~~~~~~~~~
.. class:: RIPEMD160()
RIPEMD160 is a cryptographic hash function that is part of ISO/IEC
10118-3:2004. It produces a 160-bit message digest.
Whirlpool
~~~~~~~~~
.. class:: Whirlpool()
Whirlpool is a cryptographic hash function that is part of ISO/IEC
10118-3:2004. It produces a 512-bit message digest.
MD5
~~~
.. warning::
MD5 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:: MD5()
MD5 is a deprecated cryptographic hash function. It produces a 128-bit
message digest and has practical known collision attacks.
Interfaces
~~~~~~~~~~
.. class:: HashAlgorithm
.. attribute:: name
:type: str
The standard name for the hash algorithm, for example: ``"sha256"`` or
``"whirlpool"``.
.. attribute:: digest_size
:type: int
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
.. attribute:: algorithm
A :class:`HashAlgorithm` that will be used by this context.
.. method:: update(data)
:param bytes data: The data you want to hash.
.. method:: finalize()
:return: The final digest as bytes.
.. method:: copy()
:return: A :class:`HashContext` that is a copy of the current context.
.. _`Lifetimes of cryptographic hash functions`: http://valerieaurora.org/hash.html
.. _`BLAKE2`: https://blake2.net
.. _`length-extension attacks`: https://en.wikipedia.org/wiki/Length_extension_attack

View File

@ -0,0 +1,18 @@
.. hazmat::
Primitives
==========
.. toctree::
:maxdepth: 1
cryptographic-hashes
mac/index
symmetric-encryption
padding
key-derivation-functions
keywrap
asymmetric/index
constant-time
interfaces
twofactor

View File

@ -0,0 +1,80 @@
.. 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

View File

@ -0,0 +1,909 @@
.. hazmat::
Key derivation functions
========================
.. module:: cryptography.hazmat.primitives.kdf
Key derivation functions derive bytes suitable for cryptographic operations
from passwords or other data sources using a pseudo-random function (PRF).
Different KDFs are suitable for different tasks such as:
* Cryptographic key derivation
Deriving a key suitable for use as input to an encryption algorithm.
Typically this means taking a password and running it through an algorithm
such as :class:`~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC` or
:class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`.
This process is typically known as `key stretching`_.
* Password storage
When storing passwords you want to use an algorithm that is computationally
intensive. Legitimate users will only need to compute it once (for example,
taking the user's password, running it through the KDF, then comparing it
to the stored value), while attackers will need to do it billions of times.
Ideal password storage KDFs will be demanding on both computational and
memory resources.
.. currentmodule:: cryptography.hazmat.primitives.kdf.pbkdf2
.. class:: PBKDF2HMAC(algorithm, length, salt, iterations, backend)
.. versionadded:: 0.2
`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
:class:`~cryptography.hazmat.primitives.kdf.scrypt.Scrypt` is generally
considered a better solution.
This class conforms to the
:class:`~cryptography.hazmat.primitives.kdf.KeyDerivationFunction`
interface.
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> salt = os.urandom(16)
>>> # derive
>>> kdf = PBKDF2HMAC(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... iterations=100000,
... backend=backend
... )
>>> key = kdf.derive(b"my great password")
>>> # verify
>>> kdf = PBKDF2HMAC(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... iterations=100000,
... backend=backend
... )
>>> kdf.verify(b"my great password", key)
: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``.
:param bytes salt: A salt. `NIST SP 800-132`_ recommends 128-bits or
longer.
: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: An instance of
:class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`
:raises TypeError: This exception is raised if ``salt`` is not ``bytes``.
.. method:: derive(key_material)
:param bytes key_material: The input key material. For PBKDF2 this
should be a password.
:return bytes: the derived key.
:raises cryptography.exceptions.AlreadyFinalized: This is raised when
:meth:`derive` or
:meth:`verify` is
called more than
once.
:raises TypeError: This exception is raised if ``key_material`` is not
``bytes``.
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.
.. currentmodule:: cryptography.hazmat.primitives.kdf.hkdf
.. class:: HKDF(algorithm, length, salt, info, backend)
.. versionadded:: 0.2
`HKDF`_ (HMAC-based Extract-and-Expand Key Derivation Function) is suitable
for deriving keys of a fixed size used for other cryptographic operations.
.. warning::
HKDF should not be used for password storage.
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF
>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> salt = os.urandom(16)
>>> info = b"hkdf-example"
>>> hkdf = HKDF(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... info=info,
... backend=backend
... )
>>> key = hkdf.derive(b"input key")
>>> hkdf = HKDF(
... algorithm=hashes.SHA256(),
... length=32,
... salt=salt,
... info=info,
... backend=backend
... )
>>> hkdf.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. 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
level of the hash: often that means cryptographically random and 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
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: 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 exception is raised if ``salt`` or ``info`` is not
``bytes``.
.. method:: derive(key_material)
:param bytes key_material: The input key material.
:return bytes: The derived key.
:raises TypeError: This exception is raised if ``key_material`` is not
``bytes``.
Derives a new key from the input key material by performing both the
extract and expand operations.
.. 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.
.. class:: HKDFExpand(algorithm, length, info, backend)
.. versionadded:: 0.5
HKDF consists of two stages, extract and expand. This class exposes an
expand only version of HKDF that is suitable when the key material is
already cryptographically strong.
.. warning::
HKDFExpand should only be used if the key material is
cryptographically strong. You should use
:class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF` if
you are unsure.
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.hkdf import HKDFExpand
>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> info = b"hkdf-example"
>>> key_material = os.urandom(16)
>>> hkdf = HKDFExpand(
... algorithm=hashes.SHA256(),
... length=32,
... info=info,
... backend=backend
... )
>>> key = hkdf.derive(key_material)
>>> hkdf = HKDFExpand(
... algorithm=hashes.SHA256(),
... length=32,
... info=info,
... backend=backend
... )
>>> hkdf.verify(key_material, key)
: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 bytes info: Application specific context information. If ``None``
is explicitly passed an empty byte string will be used.
: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)
: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``.
Derives a new key from the input key material by performing both the
extract and expand operations.
.. 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.
:raises TypeError: This is raised if the provided ``key_material`` is
a unicode object
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.concatkdf
.. class:: ConcatKDFHash(algorithm, length, otherinfo, backend)
.. versionadded:: 1.0
ConcatKDFHash (Concatenation Key Derivation Function) is defined by the
NIST Special Publication `NIST SP 800-56Ar2`_ document, to be used to
derive keys for use after a Key Exchange negotiation operation.
.. warning::
ConcatKDFHash should not be used for password storage.
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash
>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> otherinfo = b"concatkdf-example"
>>> ckdf = ConcatKDFHash(
... algorithm=hashes.SHA256(),
... length=256,
... otherinfo=otherinfo,
... backend=backend
... )
>>> key = ckdf.derive(b"input key")
>>> ckdf = ConcatKDFHash(
... algorithm=hashes.SHA256(),
... length=256,
... otherinfo=otherinfo,
... backend=backend
... )
>>> ckdf.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 otherinfo: Application specific context information.
If ``None`` is explicitly passed an empty byte string will be used.
: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
:class:`~cryptography.hazmat.backends.interfaces.HashBackend`
:raises TypeError: This exception is raised if ``otherinfo`` is not
``bytes``.
.. method:: derive(key_material)
:param bytes key_material: The input key material.
:return bytes: The derived key.
:raises TypeError: This exception is raised if ``key_material`` is
not ``bytes``.
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.
.. class:: ConcatKDFHMAC(algorithm, length, salt, otherinfo, backend)
.. versionadded:: 1.0
Similar to ConcatKFDHash but uses an HMAC function instead.
.. warning::
ConcatKDFHMAC should not be used for password storage.
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHMAC
>>> from cryptography.hazmat.backends import default_backend
>>> backend = default_backend()
>>> salt = os.urandom(16)
>>> otherinfo = b"concatkdf-example"
>>> ckdf = ConcatKDFHMAC(
... algorithm=hashes.SHA256(),
... length=256,
... salt=salt,
... otherinfo=otherinfo,
... backend=backend
... )
>>> key = ckdf.derive(b"input key")
>>> ckdf = ConcatKDFHMAC(
... algorithm=hashes.SHA256(),
... length=256,
... salt=salt,
... otherinfo=otherinfo,
... backend=backend
... )
>>> ckdf.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 salt: A salt. Randomizes the KDF's output. Optional, but
highly recommended. Ideally as many bits of entropy as the security
level of the hash: often that means cryptographically random and as
long as the hash output. Does not have to be secret, but may cause
stronger security guarantees if secret; If ``None`` is explicitly
passed a default salt of ``algorithm.block_size`` null bytes will be
used.
:param bytes otherinfo: Application specific context information.
If ``None`` is explicitly passed an empty byte string will be used.
: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 exception is raised if ``salt`` or ``otherinfo``
is not ``bytes``.
.. method:: derive(key_material)
:param bytes key_material: The input key material.
:return bytes: The derived key.
:raises TypeError: This exception is raised if ``key_material`` is not
``bytes``.
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=256,
... sharedinfo=sharedinfo,
... backend=backend
... )
>>> key = xkdf.derive(b"input key")
>>> xkdf = X963KDF(
... algorithm=hashes.SHA256(),
... length=256,
... 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 bytes key_material: The input key material.
:return bytes: The derived key.
:raises TypeError: This exception is raised if ``key_material`` is
not ``bytes``.
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=256,
... 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=256,
... 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.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 ``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 bytes key_material: The input key material.
:return bytes: The derived key.
:raises TypeError: This exception is raised if ``key_material`` is
not ``bytes``.
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.
.. 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.
.. code-block:: python
>>> 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=64,
... n=2**14,
... r=8,
... p=1,
... backend=backend
... )
>>> key = kdf.derive(b"my great password")
>>> # verify
>>> kdf = Scrypt(
... salt=salt,
... length=64,
... 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.
: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.
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).
:param backend: An instance of
:class:`~cryptography.hazmat.backends.interfaces.ScryptBackend`.
: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 bytes key_material: The input key material.
: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
~~~~~~~~~
.. currentmodule:: cryptography.hazmat.primitives.kdf
.. class:: KeyDerivationFunction
.. versionadded:: 0.2
.. method:: derive(key_material)
:param bytes key_material: The input key material. Depending on what
key derivation function you are using this
could be either random bytes, or a user
supplied password.
:return: The new key.
: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 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. This can be used for
something like checking whether a user's password attempt matches the
stored derived key.
.. _`NIST SP 800-132`: http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
.. _`NIST SP 800-108`: http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf
.. _`NIST SP 800-56Ar2`: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf
.. _`ANSI X9.63:2001`: https://webstore.ansi.org
.. _`SEC 1 v2.0`: http://www.secg.org/sec1-v2.pdf
.. _`Password Storage Cheat Sheet`: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
.. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2
.. _`key stretching`: https://en.wikipedia.org/wiki/Key_stretching
.. _`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

View File

@ -0,0 +1,59 @@
.. 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.
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.

View File

@ -0,0 +1,110 @@
.. hazmat::
Cipher-based message authentication code
========================================
.. currentmodule:: cryptography.hazmat.primitives.cmac
.. testsetup::
import binascii
key = binascii.unhexlify(b"0" * 32)
`Cipher-based message authentication codes`_ (or CMACs) are a tool for
calculating message authentication codes using a block cipher coupled with a
secret key. You can use an CMAC to verify both the integrity and authenticity
of a message.
A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`.
.. class:: CMAC(algorithm, backend)
.. versionadded:: 0.4
CMAC objects take a
:class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` instance.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import cmac
>>> from cryptography.hazmat.primitives.ciphers import algorithms
>>> 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'
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.ciphers.BlockCipherAlgorithm`
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:
.. doctest::
>>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend())
>>> c.update(b"message to authenticate")
>>> c.verify(b"an incorrect signature")
Traceback (most recent call last):
...
cryptography.exceptions.InvalidSignature: Signature did not match digest.
: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
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.CMACBackend`
.. method:: update(data)
:param bytes data: The bytes to hash and authenticate.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: copy()
Copy this :class:`CMAC` instance, usually so that we may call
:meth:`finalize` to get an intermediate value while we continue
to call :meth:`update` on the original instance.
:return: A new instance of :class:`CMAC` that can be updated
and finalized independently of the original instance.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
.. method:: verify(signature)
Finalize the current context and securely compare the MAC to
``signature``.
:param bytes signature: The bytes to compare the current CMAC
against.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises cryptography.exceptions.InvalidSignature: If signature does not
match digest
:raises TypeError: This exception is raised if ``signature`` 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:`copy`, :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:
.. _`Cipher-based message authentication codes`: https://en.wikipedia.org/wiki/CMAC

View File

@ -0,0 +1,109 @@
.. hazmat::
Hash-based message authentication codes
=======================================
.. currentmodule:: cryptography.hazmat.primitives.hmac
.. testsetup::
import binascii
key = binascii.unhexlify(b"0" * 32)
Hash-based message authentication codes (or HMACs) are a tool for calculating
message authentication codes using a cryptographic hash function coupled with a
secret key. You can use an HMAC to verify both the integrity and authenticity
of a message.
.. class:: HMAC(key, algorithm, backend)
HMAC objects take a ``key`` and a
: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.
This is an implementation of :rfc:`2104`.
.. doctest::
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import hashes, hmac
>>> 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'
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` 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:
.. doctest::
>>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend())
>>> h.update(b"message to hash")
>>> h.verify(b"an incorrect signature")
Traceback (most recent call last):
...
cryptography.exceptions.InvalidSignature: Signature did not match digest.
:param bytes key: Secret key as ``bytes``.
:param algorithm: An
:class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
instance such as those described in
:ref:`Cryptographic Hashes <cryptographic-hash-algorithms>`.
:param backend: An
: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`
.. method:: update(msg)
:param bytes msg: The bytes to hash and authenticate.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises TypeError: This exception is raised if ``msg`` is not ``bytes``.
.. method:: copy()
Copy this :class:`HMAC` instance, usually so that we may call
:meth:`finalize` to get an intermediate digest value while we continue
to call :meth:`update` on the original instance.
:return: A new instance of :class:`HMAC` that can be updated
and finalized independently of the original instance.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
.. method:: verify(signature)
Finalize the current context and securely compare digest to
``signature``.
:param bytes signature: The bytes to compare the current digest
against.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises cryptography.exceptions.InvalidSignature: If signature does not
match digest
:raises TypeError: This exception is raised if ``signature`` is not
``bytes``.
.. method:: finalize()
Finalize the current context and return the message digest as bytes.
After ``finalize`` has been called this object can no longer be used
and :meth:`update`, :meth:`copy`, :meth:`verify` and :meth:`finalize`
will raise an :class:`~cryptography.exceptions.AlreadyFinalized`
exception.
:return bytes: The message digest as bytes.
:raises cryptography.exceptions.AlreadyFinalized:

View File

@ -0,0 +1,18 @@
.. hazmat::
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.
For more information on why HMAC is preferred, see `Use cases for CMAC vs.
HMAC?`_
.. _`Use cases for CMAC vs. HMAC?`: https://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac
.. toctree::
:maxdepth: 1
cmac
hmac

View File

@ -0,0 +1,129 @@
.. hazmat::
Padding
=======
.. module:: cryptography.hazmat.primitives.padding
Padding is a way to take data that may or may not be a multiple of the block
size for a cipher and extend it out so that it is. This is required for many
block cipher modes as they require the data to be encrypted to be an exact
multiple of the block size.
.. class:: PKCS7(block_size)
PKCS7 padding is a generalization of PKCS5 padding (also known as standard
padding). PKCS7 padding works by appending ``N`` bytes 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::
>>> from cryptography.hazmat.primitives import padding
>>> padder = padding.PKCS7(128).padder()
>>> padded_data = padder.update(b"11111111111111112222222222")
>>> padded_data
'1111111111111111'
>>> padded_data += padder.finalize()
>>> padded_data
'11111111111111112222222222\x06\x06\x06\x06\x06\x06'
>>> unpadder = padding.PKCS7(128).unpadder()
>>> data = unpadder.update(padded_data)
>>> data
'1111111111111111'
>>> data + unpadder.finalize()
'11111111111111112222222222'
:param block_size: The size of the block in 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:: 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
'1111111111111111'
>>> padded_data += padder.finalize()
>>> padded_data
'11111111111111112222222222\x00\x00\x00\x00\x00\x06'
>>> unpadder = padding.ANSIX923(128).unpadder()
>>> data = unpadder.update(padded_data)
>>> data
'1111111111111111'
>>> data + unpadder.finalize()
'11111111111111112222222222'
:param block_size: The size of the block in 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
When calling ``padder()`` or ``unpadder()`` the result will conform to the
``PaddingContext`` interface. You can then call ``update(data)`` with data
until you have fed everything into the context. Once that is done call
``finalize()`` to finish the operation and obtain the remainder of the
data.
.. method:: update(data)
:param bytes data: The data you wish to pass into the context.
:return bytes: Returns the data that was padded or unpadded.
:raises TypeError: Raised if data is not bytes.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
:raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: finalize()
Finalize the current context and return the rest of the data.
After ``finalize`` has been called this object can no longer be used;
:meth:`update` and :meth:`finalize` will raise an
:class:`~cryptography.exceptions.AlreadyFinalized` exception.
:return bytes: Returns the remainder of the data.
: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_X.923

View File

@ -0,0 +1,616 @@
.. hazmat:: /fernet
Symmetric encryption
====================
.. module:: cryptography.hazmat.primitives.ciphers
Symmetric encryption is a way to `encrypt`_ or hide the contents of material
where the sender and receiver both use the same secret key. Note that symmetric
encryption is **not** sufficient for most applications because it only
provides secrecy but not authenticity. That means an attacker can't see the
message but an attacker can create bogus messages and force the application to
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`_.
.. class:: Cipher(algorithm, mode, backend)
Cipher objects combine an algorithm such as
:class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` with a
mode like
:class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` or
:class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`. A simple
example of encrypting and then decrypting content with AES is:
.. 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()
>>> ct = encryptor.update(b"a secret message") + encryptor.finalize()
>>> decryptor = cipher.decryptor()
>>> decryptor.update(ct) + decryptor.finalize()
'a secret message'
:param algorithms: A
:class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm`
instance such as those described
:ref:`below <symmetric-encryption-algorithms>`.
:param mode: A :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode`
instance such as those described
:ref:`below <symmetric-encryption-modes>`.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.CipherBackend`
instance.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.CipherBackend`
.. method:: encryptor()
:return: An encrypting
:class:`~cryptography.hazmat.primitives.ciphers.CipherContext`
instance.
If the backend doesn't support the requested combination of ``cipher``
and ``mode`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm`
exception will be raised.
.. method:: decryptor()
:return: A decrypting
:class:`~cryptography.hazmat.primitives.ciphers.CipherContext`
instance.
If the backend doesn't support the requested combination of ``cipher``
and ``mode`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm`
exception will be raised.
.. _symmetric-encryption-algorithms:
Algorithms
~~~~~~~~~~
.. currentmodule:: cryptography.hazmat.primitives.ciphers.algorithms
.. class:: AES(key)
AES (Advanced Encryption Standard) is a block cipher standardized by NIST.
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.
.. class:: Camellia(key)
Camellia is a block cipher approved for use by `CRYPTREC`_ and ISO/IEC.
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.
.. 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, 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.
.. class:: CAST5(key)
.. versionadded:: 0.2
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.
:param bytes key: The secret key, This must be kept secret. 40 to 128 bits
in length in increments of 8 bits.
.. class:: SEED(key)
.. versionadded:: 0.4
SEED is a block cipher developed by the Korea Information Security Agency
(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.
Weak ciphers
------------
.. warning::
These ciphers are considered weak for a variety of reasons. New
applications should avoid their use and existing applications should
strongly consider migrating away.
.. class:: Blowfish(key)
Blowfish is a block cipher developed by Bruce Schneier. It is known to be
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.
.. class:: ARC4(key)
ARC4 (Alleged RC4) is a stream cipher with serious weaknesses in its
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.
.. doctest::
>>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
>>> from cryptography.hazmat.backends import default_backend
>>> algorithm = algorithms.ARC4(key)
>>> cipher = Cipher(algorithm, mode=None, backend=default_backend())
>>> encryptor = cipher.encryptor()
>>> ct = encryptor.update(b"a secret message")
>>> decryptor = cipher.decryptor()
>>> decryptor.update(ct)
'a secret message'
.. class:: IDEA(key)
IDEA (`International Data Encryption Algorithm`_) is a block cipher created
in 1991. It is an optional component of the `OpenPGP`_ standard. This cipher
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.
.. _symmetric-encryption-modes:
Modes
~~~~~
.. module:: cryptography.hazmat.primitives.ciphers.modes
.. class:: CBC(initialization_vector)
CBC (Cipher Block Chaining) is a mode of operation for block ciphers. It is
considered cryptographically strong.
**Padding is required when using this mode.**
:param bytes 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``.
A good construction looks like:
.. doctest::
>>> import os
>>> from cryptography.hazmat.primitives.ciphers.modes import CBC
>>> iv = os.urandom(16)
>>> mode = CBC(iv)
While the following is bad and will leak information:
.. doctest::
>>> from cryptography.hazmat.primitives.ciphers.modes import CBC
>>> iv = "a" * 16
>>> mode = CBC(iv)
.. class:: CTR(nonce)
.. warning::
Counter mode is not recommended for use with block ciphers that have a
block size of less than 128-bits.
CTR (Counter) is a mode of operation for block ciphers. It is considered
cryptographically strong. It transforms a block cipher into a stream
cipher.
**This mode does not require padding.**
:param bytes 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.
.. class:: OFB(initialization_vector)
OFB (Output Feedback) is a mode of operation for block ciphers. It
transforms a block cipher into a stream cipher.
**This mode does not require padding.**
:param bytes 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``.
.. class:: CFB(initialization_vector)
CFB (Cipher Feedback) is a mode of operation for block ciphers. It
transforms a block cipher into a stream cipher.
**This mode does not require padding.**
:param bytes 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``.
.. class:: CFB8(initialization_vector)
CFB (Cipher Feedback) is a mode of operation for block ciphers. It
transforms a block cipher into a stream cipher. The CFB8 variant uses an
8-bit shift register.
**This mode does not require padding.**
:param bytes 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``.
.. class:: GCM(initialization_vector, tag=None, min_tag_length=16)
.. danger::
When using this mode you **must** not use the decrypted data until
:meth:`~cryptography.hazmat.primitives.ciphers.CipherContext.finalize`
has been called. GCM provides **no** guarantees of ciphertext integrity
until decryption is complete.
GCM (Galois Counter Mode) is a mode of operation for block ciphers. An
AEAD (authenticated encryption with additional data) mode is a type of
block cipher mode that simultaneously encrypts the message as well as
authenticating it. Additional unencrypted data may also be authenticated.
Additional means of verifying integrity such as
:doc:`HMAC </hazmat/primitives/mac/hmac>` are not necessary.
**This mode does not require padding.**
:param bytes 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``.
.. 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.
.. versionchanged:: 0.5
The ``min_tag_length`` parameter was added in ``0.5``, previously
truncation down to ``4`` bytes was always allowed.
:param bytes tag: The tag bytes to verify during decryption. When
encrypting this must be ``None``.
:param bytes 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``.
An example of securely encrypting and decrypting data with ``AES`` in the
``GCM`` mode looks like:
.. testcode::
import os
from cryptography.hazmat.primitives.ciphers import (
Cipher, algorithms, modes
)
def encrypt(key, plaintext, associated_data):
# Generate a random 96-bit IV.
iv = os.urandom(12)
# Construct an AES-GCM Cipher object with the given key and a
# randomly generated IV.
encryptor = Cipher(
algorithms.AES(key),
modes.GCM(iv),
backend=default_backend()
).encryptor()
# associated_data will be authenticated but not encrypted,
# it must also be passed in on decryption.
encryptor.authenticate_additional_data(associated_data)
# Encrypt the plaintext and get the associated ciphertext.
# GCM does not require padding.
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
return (iv, ciphertext, encryptor.tag)
def decrypt(key, associated_data, iv, ciphertext, tag):
# Construct a Cipher object, with the key, iv, and additionally the
# GCM tag used for authenticating the message.
decryptor = Cipher(
algorithms.AES(key),
modes.GCM(iv, tag),
backend=default_backend()
).decryptor()
# We put associated_data back in or the tag will fail to verify
# when we finalize the decryptor.
decryptor.authenticate_additional_data(associated_data)
# Decryption gets us the authenticated plaintext.
# If the tag does not match an InvalidTag exception will be raised.
return decryptor.update(ciphertext) + decryptor.finalize()
iv, ciphertext, tag = encrypt(
key,
b"a secret message!",
b"authenticated but not encrypted payload"
)
print(decrypt(
key,
b"authenticated but not encrypted payload",
iv,
ciphertext,
tag
))
.. testoutput::
a secret message!
Insecure modes
--------------
.. warning::
These modes are insecure. New applications should never make use of them,
and existing applications should strongly consider migrating away.
.. class:: ECB()
ECB (Electronic Code Book) is the simplest mode of operation for block
ciphers. Each block of data is encrypted in the same way. This means
identical plaintext blocks will always result in identical ciphertext
blocks, which can leave `significant patterns in the output`_.
**Padding is required when using this mode.**
Interfaces
----------
.. currentmodule:: cryptography.hazmat.primitives.ciphers
.. class:: CipherContext
When calling ``encryptor()`` or ``decryptor()`` on a ``Cipher`` object
the result will conform to the ``CipherContext`` interface. You can then
call ``update(data)`` with data until you have fed everything into the
context. Once that is done call ``finalize()`` to finish the operation and
obtain the remainder of the data.
Block ciphers require that the plaintext or ciphertext always be a multiple
of their block size. Because of that **padding** is sometimes required to
make a message the correct size. ``CipherContext`` will not automatically
apply any padding; you'll need to add your own. For block ciphers the
recommended padding is
:class:`~cryptography.hazmat.primitives.padding.PKCS7`. If you are using a
stream cipher mode (such as
:class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`) you don't have
to worry about this.
.. method:: update(data)
:param bytes data: The data you wish to pass into the context.
:return bytes: Returns the data that was encrypted or decrypted.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
When the ``Cipher`` was constructed in a mode that turns it into a
stream cipher (e.g.
:class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`), this will
return bytes immediately, however in other modes it will return chunks
whose size is determined by the cipher's block size.
.. method:: finalize()
: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.
Once ``finalize`` is called this object can no longer be used and
:meth:`update` and :meth:`finalize` will raise an
:class:`~cryptography.exceptions.AlreadyFinalized` exception.
.. class:: AEADCipherContext
When calling ``encryptor`` or ``decryptor`` on a ``Cipher`` object
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`` instance. ``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::
In AEAD modes all data passed to ``update()`` will be both encrypted
and authenticated. Do not pass encrypted data to the
``authenticate_additional_data()`` method. It is meant solely for
additional data you may want to authenticate but leave unencrypted.
.. method:: authenticate_additional_data(data)
:param bytes data: Any data you wish to authenticate but not encrypt.
:raises: :class:`~cryptography.exceptions.AlreadyFinalized`
.. class:: AEADEncryptionContext
When creating an encryption context using ``encryptor`` on a ``Cipher``
object with an AEAD mode such as
:class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` an object
conforming to both the ``AEADEncryptionContext`` and ``AEADCipherContext``
interfaces will be returned. This interface provides one
additional attribute ``tag``. ``tag`` can only be obtained after
``finalize`` has been called.
.. attribute:: tag
:return bytes: Returns the tag value as bytes.
:raises: :class:`~cryptography.exceptions.NotYetFinalized` if called
before the context is finalized.
.. class:: CipherAlgorithm
A named symmetric encryption algorithm.
.. attribute:: name
:type: str
The standard name for the mode, for example, "AES", "Camellia", or
"Blowfish".
.. attribute:: key_size
:type: int
The number of bits in the key being used.
.. class:: BlockCipherAlgorithm
A block cipher algorithm.
.. attribute:: block_size
:type: int
The number of bits in a block.
Interfaces used by the symmetric cipher modes described in
:ref:`Symmetric Encryption Modes <symmetric-encryption-modes>`.
.. currentmodule:: cryptography.hazmat.primitives.ciphers.modes
.. class:: Mode
A named cipher mode.
.. attribute:: name
:type: str
This should be the standard shorthand name for the mode, for example
Cipher-Block Chaining mode is "CBC".
The name may be used by a backend to influence the operation of a
cipher in conjunction with the algorithm's name.
.. method:: validate_for_algorithm(algorithm)
:param cryptography.hazmat.primitives.ciphers.CipherAlgorithm algorithm:
Checks that the combination of this mode with the provided algorithm
meets any necessary invariants. This should raise an exception if they
are not met.
For example, the
:class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode uses
this method to check that the provided initialization vector's length
matches the block size of the algorithm.
.. class:: ModeWithInitializationVector
A cipher mode with an initialization vector.
.. attribute:: initialization_vector
:type: bytes
Exact requirements of the initialization are described by the
documentation of individual modes.
.. class:: ModeWithNonce
A cipher mode with a nonce.
.. attribute:: nonce
:type: bytes
Exact requirements of the nonce are described by the documentation of
individual modes.
.. class:: ModeWithAuthenticationTag
A cipher mode with an authentication tag.
.. attribute:: tag
:type: bytes
Exact requirements of the tag are described by the documentation of
individual modes.
.. _`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
.. _`Communications Security Establishment`: https://www.cse-cst.gc.ca
.. _`encrypt`: https://ssd.eff.org/en/module/what-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_.28ECB.29
.. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm
.. _`OpenPGP`: http://openpgp.org

View File

@ -0,0 +1,244 @@
.. hazmat::
Two-factor authentication
=========================
.. currentmodule:: cryptography.hazmat.primitives.twofactor
This module contains algorithms related to two-factor authentication.
Currently, it contains an algorithm for generating and verifying
one time password values based on Hash-based message authentication
codes (HMAC).
.. class:: InvalidToken
This is raised when the verify method of a one time password function's
computed token does not match the expected token.
.. currentmodule:: cryptography.hazmat.primitives.twofactor.hotp
.. 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.
This is an implementation of :rfc:`4226`.
.. doctest::
>>> import os
>>> 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(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 int length: Length of generated one time password as ``int``.
:param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A
:class:`~cryptography.hazmat.primitives.hashes`
instance.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
instance.
:param enforce_key_length: A boolean flag defaulting to True that toggles
whether a minimum key length of 128 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.
:raises TypeError: This is raised if the provided ``algorithm`` is not
:class:`~cryptography.hazmat.primitives.hashes.SHA1()`,
:class:`~cryptography.hazmat.primitives.hashes.SHA256()` or
:class:`~cryptography.hazmat.primitives.hashes.SHA512()` or if the
``length`` parameter is not an integer.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
.. method:: generate(counter)
:param int counter: The counter value used to generate the one time
password.
:return bytes: A one time password value.
.. method:: verify(hotp, counter)
:param bytes hotp: The one time password value to validate.
:param int counter: The counter value to validate against.
:raises cryptography.hazmat.primitives.twofactor.InvalidToken: This
is raised when the supplied HOTP does not match the expected HOTP.
.. 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`
:param issuer: The optional display name of issuer. This is typically
the provider or service the user wants to access using the OTP
token.
:type issuer: :term:`text` or `None`
:param int counter: The current value of counter.
:return: A URI string.
Throttling
~~~~~~~~~~
Due to the fact that the HOTP algorithm generates rather short tokens that are
6 - 8 digits long, brute force attacks are possible. It is highly recommended
that the server that validates the token implement a throttling scheme that
locks out the account for a period of time after a number of failed attempts.
The number of allowed attempts should be as low as possible while still
ensuring that usability is not significantly impacted.
Re-synchronization of the counter
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The server's counter value should only be incremented on a successful HOTP
authentication. However, the counter on the client is incremented every time a
new HOTP value is requested. This can lead to the counter value being out of
synchronization between the client and server.
Due to this, it is highly recommended that the server sets a look-ahead window
that allows the server to calculate the next ``x`` HOTP values and check them
against the supplied HOTP value. This can be accomplished with something
similar to the following code.
.. code-block:: python
def verify(hotp, counter, look_ahead):
assert look_ahead >= 0
correct_counter = None
otp = HOTP(key, 6, default_backend())
for count in range(counter, counter + look_ahead):
try:
otp.verify(hotp, count)
correct_counter = count
except InvalidToken:
pass
return correct_counter
.. currentmodule:: cryptography.hazmat.primitives.twofactor.totp
.. 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
</random-numbers>` and is recommended to be as long as your hash function's
output (e.g 256-bit for SHA256). The ``length`` parameter controls the
length of the generated one time password and must be >= 6 and <= 8.
This is an implementation of :rfc:`6238`.
.. doctest::
>>> import os
>>> import time
>>> 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(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 int length: Length of generated one time password as ``int``.
:param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A
:class:`~cryptography.hazmat.primitives.hashes`
instance.
:param int time_step: The time step size. The recommended size is 30.
:param backend: A
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
instance.
:param enforce_key_length: A boolean flag defaulting to True that toggles
whether a minimum key length of 128 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.
:raises TypeError: This is raised if the provided ``algorithm`` is not
:class:`~cryptography.hazmat.primitives.hashes.SHA1()`,
:class:`~cryptography.hazmat.primitives.hashes.SHA256()` or
:class:`~cryptography.hazmat.primitives.hashes.SHA512()` or if the
``length`` parameter is not an integer.
:raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
.. method:: generate(time)
:param int time: The time value used to generate the one time password.
:return bytes: A one time password value.
.. method:: verify(totp, time)
:param bytes totp: The one time password value to validate.
:param int time: The time value to validate against.
:raises cryptography.hazmat.primitives.twofactor.InvalidToken: This
is raised when the supplied TOTP does not match the expected TOTP.
.. 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`
:param issuer: The optional display name of issuer. This is typically
the provider or service the user wants to access using the OTP
token.
:type issuer: :term:`text` or `None`
:return: A URI string.
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.
For generating a provisioning URI, you could use the ``get_provisioning_uri``
method of HOTP/TOTP instances.
.. code-block:: python
counter = 5
account_name = 'alice@example.com'
issuer_name = 'Example Inc'
hotp_uri = hotp.get_provisioning_uri(account_name, counter, issuer_name)
totp_uri = totp.get_provisioning_uri(account_name, issuer_name)
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
.. _`Issue #2915`: https://github.com/pyca/cryptography/issues/2915

104
docs/index.rst Normal file
View File

@ -0,0 +1,104 @@
Welcome to ``cryptography``
===========================
``cryptography`` is a Python library which exposes cryptographic recipes and
primitives. Our goal is for it to be your "cryptographic standard library". If
you are interested in learning more about the field of cryptography, we
recommend `Crypto 101, by Laurens Van Houtven`_.
Installation
------------
You can install ``cryptography`` with ``pip``:
.. code-block:: console
$ pip install cryptography
See :doc:`Installation <installation>` for more information.
Why a new crypto library for Python?
------------------------------------
If you've done cryptographic work in Python before, you've probably seen some
other libraries in Python, such as *M2Crypto*, *PyCrypto*, or *PyOpenSSL*. In
building ``cryptography`` we wanted to address a few issues we observed in the
existing libraries:
* Lack of PyPy and Python 3 support.
* Lack of maintenance.
* Use of poor implementations of algorithms (i.e. ones with known side-channel
attacks).
* Lack of high level, "Cryptography for humans", APIs.
* Absence of algorithms such as
:class:`AES-GCM <cryptography.hazmat.primitives.ciphers.modes.GCM>` and
:class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF`.
* Poor introspectability, and thus poor testability.
* Extremely error prone APIs, and bad defaults.
.. _cryptography-layout:
Layout
------
``cryptography`` is broadly divided into two levels. One with safe
cryptographic recipes, "cryptography for humans" if you will. These are safe
and easy to use and don't require developers to make many decisions.
The other level is low-level cryptographic primitives. These are often
dangerous and can be used incorrectly. They require making decisions and having
an in-depth knowledge of the cryptographic concepts at work. Because of the
potential danger in working at this level, this is referred to as the
"hazardous materials" or "hazmat" layer. These live in the
``cryptography.hazmat`` package, and their documentation will always contain an
admonition at the top.
We recommend using the recipes layer whenever possible, and falling back to the
hazmat layer only when necessary.
The recipes layer
~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
fernet
x509/index
random-numbers
exceptions
faq
glossary
The hazardous materials layer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
hazmat/primitives/index
hazmat/backends/index
hazmat/bindings/index
The ``cryptography`` open source project
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. toctree::
:maxdepth: 2
installation
development/index
security
limitations
api-stability
doing-a-release
changelog
community
.. note::
``cryptography`` has not been subjected to an external audit of its code or
documentation. If you're interested in discussing an audit please
:doc:`get in touch </community>`.
.. _`Crypto 101, by Laurens Van Houtven`: https://www.crypto101.io/

277
docs/installation.rst Normal file
View File

@ -0,0 +1,277 @@
Installation
============
You can install ``cryptography`` with ``pip``:
.. code-block:: console
$ pip install cryptography
Supported platforms
-------------------
Currently we test ``cryptography`` on Python 2.6, 2.7, 3.3, 3.4, 3.5, and PyPy
2.6+ on these operating systems.
* x86-64 CentOS 7.x, 6.4
* x86-64 FreeBSD 10
* OS X 10.12 Sierra, 10.11 El Capitan, 10.10 Yosemite, 10.9 Mavericks,
10.8 Mountain Lion, and 10.7 Lion
* x86-64 Ubuntu 12.04 LTS and Ubuntu 14.04 LTS
* x86-64 Debian Wheezy (7.x), Jessie (8.x), and Debian Sid (unstable)
* 32-bit and 64-bit Python on 64-bit Windows Server 2012
.. warning::
Python 2.6 is no longer supported by the Python core team. A future version
of cryptography will drop support for this version.
We test compiling with ``clang`` as well as ``gcc`` and use the following
OpenSSL releases:
* ``OpenSSL 1.0.0-fips`` (``RHEL/CentOS 6.4``)
* ``OpenSSL 1.0.1``
* ``OpenSSL 1.0.1e-fips`` (``RHEL/CentOS 7``)
* ``OpenSSL 1.0.1j-freebsd``
* ``OpenSSL 1.0.1f``
* ``OpenSSL 1.0.2-latest``
* ``OpenSSL 1.1.0``
.. warning::
Cryptography 1.7 has dropped support for OpenSSL 1.0.0, see the
:doc:`FAQ </faq>` for more details
Building cryptography on Windows
--------------------------------
The wheel package on Windows is a statically linked build (as of 0.5) so all
dependencies are included. To install ``cryptography``, you will typically
just run
.. code-block:: console
$ pip install cryptography
If you prefer to compile it yourself you'll need to have OpenSSL installed.
You can compile OpenSSL yourself as well or use the binaries we build for our
release infrastructure (`openssl-release`_). Be sure to download the proper
version for your architecture and Python (2010 works for Python 2.6, 2.7, 3.3,
and 3.4 while 2015 is required for 3.5). Wherever you place your copy
of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE`` environment variables
to include the proper locations. For example:
.. code-block:: console
C:\> \path\to\vcvarsall.bat x86_amd64
C:\> set LIB=C:\OpenSSL-win64\lib;%LIB%
C:\> set INCLUDE=C:\OpenSSL-win64\include;%INCLUDE%
C:\> pip install cryptography
If you need to rebuild ``cryptography`` for any reason be sure to clear the
local `wheel cache`_.
.. _build-on-linux:
Building cryptography on Linux
------------------------------
``cryptography`` should build very easily on Linux provided you have a C
compiler, headers for Python (if you're not using ``pypy``), and headers for
the OpenSSL and ``libffi`` libraries available on your system.
For Debian and Ubuntu, the following command will ensure that the required
dependencies are installed:
.. code-block:: console
$ sudo apt-get install build-essential libssl-dev libffi-dev python-dev
For Fedora and RHEL-derivatives, the following command will ensure that the
required dependencies are installed:
.. code-block:: console
$ sudo yum install gcc libffi-devel python-devel openssl-devel
You should now be able to build and install cryptography with the usual
.. code-block:: console
$ pip install cryptography
Using your own OpenSSL on Linux
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Python links to OpenSSL for its own purposes and this can sometimes cause
problems when you wish to use a different version of OpenSSL with cryptography.
If you want to use cryptography with your own build of OpenSSL you will need to
make sure that the build is configured correctly so that your version of
OpenSSL doesn't conflict with Python's.
The options you need to add allow the linker to identify every symbol correctly
even when multiple versions of the library are linked into the same program. If
you are using your distribution's source packages these will probably be
patched in for you already, otherwise you'll need to use options something like
this when configuring OpenSSL:
.. code-block:: console
$ ./config -Wl,--version-script=openssl.ld -Wl,-Bsymbolic-functions -fPIC shared
You'll also need to generate your own ``openssl.ld`` file. For example::
OPENSSL_1.0.1F_CUSTOM {
global:
*;
};
You should replace the version string on the first line as appropriate for your
build.
Static Wheels
~~~~~~~~~~~~~
Cryptography ships statically-linked wheels for OS X and Windows, ensuring that
these platforms can always use the most-recent OpenSSL, regardless of what is
shipped by default on those platforms. As a result of various difficulties
around Linux binary linking, Cryptography cannot do the same on Linux.
However, you can build your own statically-linked wheels that will work on your
own systems. This will allow you to continue to use relatively old Linux
distributions (such as LTS releases), while making sure you have the most
recent OpenSSL available to your Python programs.
To do so, you should find yourself a machine that is as similar as possible to
your target environment (e.g. your production environment): for example, spin
up a new cloud server running your target Linux distribution. On this machine,
install the Cryptography dependencies as mentioned in :ref:`build-on-linux`.
Please also make sure you have `virtualenv`_ installed: this should be
available from your system package manager.
Then, paste the following into a shell script. You'll need to populate the
``OPENSSL_VERSION`` variable. To do that, visit `openssl.org`_ and find the
latest non-FIPS release version number, then set the string appropriately. For
example, for OpenSSL 1.0.2d, use ``OPENSSL_VERSION="1.0.2d"``.
When this shell script is complete, you'll find a collection of wheel files in
a directory called ``wheelhouse``. These wheels can be installed by a
sufficiently-recent version of ``pip``. The Cryptography wheel in this
directory contains a statically-linked OpenSSL binding, which ensures that you
have access to the most-recent OpenSSL releases without corrupting your system
dependencies.
.. code-block:: console
set -e
OPENSSL_VERSION="VERSIONGOESHERE"
CWD=$(pwd)
virtualenv env
. env/bin/activate
pip install -U setuptools
pip install -U wheel pip
curl -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
tar xvf openssl-${OPENSSL_VERSION}.tar.gz
cd openssl-${OPENSSL_VERSION}
./config no-shared no-ssl2 -fPIC --prefix=${CWD}/openssl
make && make install
cd ..
CFLAGS="-I${CWD}/openssl/include" LDFLAGS="-L${CWD}/openssl/lib" pip wheel --no-use-wheel cryptography
Building cryptography on OS X
-----------------------------
.. note::
If installation gives a ``fatal error: 'openssl/aes.h' file not found``
see the :doc:`FAQ </faq>` for information about how to fix this issue.
The wheel package on OS X is a statically linked build (as of 1.0.1) so for
users with pip 8 or above you only need one step:
.. code-block:: console
$ pip install cryptography
If you want to build cryptography yourself or are on an older OS X version,
cryptography requires the presence of a C compiler, development headers, and
the proper libraries. On OS X much of this is provided by Apple's Xcode
development tools. To install the Xcode command line tools (on OS X 10.9+)
open a terminal window and run:
.. code-block:: console
$ xcode-select --install
This will install a compiler (clang) along with (most of) the required
development headers.
You'll also need OpenSSL, which you can obtain from `Homebrew`_ or `MacPorts`_.
Cryptography does **not** support Apple's deprecated OpenSSL distribution.
To build cryptography and dynamically link it:
`Homebrew`_
.. code-block:: console
$ brew install openssl
$ env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" pip install cryptography
`MacPorts`_:
.. code-block:: console
$ sudo port install openssl
$ env LDFLAGS="-L/opt/local/lib" CFLAGS="-I/opt/local/include" pip install cryptography
You can also build cryptography statically:
`Homebrew`_
.. code-block:: console
$ brew install openssl
$ env CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=1 LDFLAGS="$(brew --prefix openssl)/lib/libssl.a $(brew --prefix openssl)/lib/libcrypto.a" CFLAGS="-I$(brew --prefix openssl)/include" pip install cryptography
`MacPorts`_:
.. code-block:: console
$ sudo port install openssl
$ env CRYPTOGRAPHY_OSX_NO_LINK_FLAGS=1 LDFLAGS="/opt/local/lib/libssl.a /opt/local/lib/libcrypto.a" CFLAGS="-I/opt/local/include" pip install cryptography
If you need to rebuild ``cryptography`` for any reason be sure to clear the
local `wheel cache`_.
Building cryptography with conda
--------------------------------
Because of a bug in conda, attempting to install cryptography out of the box
will result in an error. This can be resolved by setting the library path
environment variable for your platform.
On OS X:
.. code-block:: console
$ env DYLD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography
and on Linux:
.. code-block:: console
$ env LD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography
You will need to set this variable every time you start Python. For more
information, consult `Greg Wilson's blog post`_ on the subject.
.. _`Homebrew`: http://brew.sh
.. _`MacPorts`: https://www.macports.org
.. _`openssl-release`: https://jenkins.cryptography.io/job/openssl-release/
.. _`Greg Wilson's blog post`: https://software-carpentry.org/blog/2014/04/mr-biczo-was-right.html
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
.. _openssl.org: https://www.openssl.org/source/
.. _`wheel cache`: https://pip.pypa.io/en/stable/reference/pip_install/#caching

19
docs/limitations.rst Normal file
View File

@ -0,0 +1,19 @@
Known security limitations
--------------------------
Lack of secure memory wiping
============================
`Memory wiping`_ is used to protect secret data or key material from attackers
with access to uninitialized memory. This can be either because the attacker
has some kind of local user access or because of how other software uses
uninitialized memory.
Python exposes no API for us to implement this reliably and as such almost all
software in Python is potentially vulnerable to this attack. The
`CERT secure coding guidelines`_ assesses this issue as "Severity: medium,
Likelihood: unlikely, Remediation Cost: expensive to repair" and we do not
consider this a high risk for most users.
.. _`Memory wiping`: https://blogs.msdn.microsoft.com/oldnewthing/20130529-00/?p=4223/
.. _`CERT secure coding guidelines`: https://www.securecoding.cert.org/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources

190
docs/make.bat Normal file
View File

@ -0,0 +1,190 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Cryptography.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Cryptography.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

32
docs/random-numbers.rst Normal file
View File

@ -0,0 +1,32 @@
Random number generation
========================
When generating random data for use in cryptographic operations, such as an
initialization vector for encryption in
:class:`~cryptography.hazmat.primitives.ciphers.modes.CBC` mode, you do not
want to use the standard :mod:`random` module APIs. This is because they do not
provide a cryptographically secure random number generator, which can result in
major security issues depending on the algorithms in use.
Therefore, it is our recommendation to `always use your operating system's
provided random number generator`_, which is available as :func:`os.urandom`.
For example, if you need 16 bytes of random data for an initialization vector,
you can obtain them with:
.. doctest::
>>> import os
>>> iv = os.urandom(16)
This will use ``/dev/urandom`` on UNIX platforms, and ``CryptGenRandom`` on
Windows.
If you need your random number as an integer (for example, for
:meth:`~cryptography.x509.CertificateBuilder.serial_number`), you can use
``int.from_bytes`` to convert the result of ``os.urandom``:
.. code-block:: pycon
>>> serial = int.from_bytes(os.urandom(20), byteorder="big")
.. _`always use your operating system's provided random number generator`: https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/

115
docs/security.rst Normal file
View File

@ -0,0 +1,115 @@
Security
========
We take the security of ``cryptography`` seriously. The following are a set of
policies we have adopted to ensure that security issues are addressed in a
timely fashion.
What is a security issue?
-------------------------
Anytime it's possible to write code using ``cryptography``'s public API which
does not provide the guarantees that a reasonable developer would expect it to
based on our documentation.
That's a bit academic, but basically it means the scope of what we consider a
vulnerability is broad, and we do not require a proof of concept or even a
specific exploit, merely a reasonable threat model under which ``cryptography``
could be attacked.
To give a few examples of things we would consider security issues:
* If a recipe, such as Fernet, made it easy for a user to bypass
confidentiality or integrity with the public API (e.g. if the API let a user
reuse nonces).
* If, under any circumstances, we used a CSPRNG which wasn't fork-safe.
* If ``cryptography`` used an API in an underlying C library and failed to
handle error conditions safely.
Examples of things we wouldn't consider security issues:
* Offering ECB mode for symmetric encryption in the *Hazmat* layer. Though ECB
is critically weak, it is documented as being weak in our documentation.
* Using a variable time comparison somewhere, if it's not possible to
articulate any particular program in which this would result in problematic
information disclosure.
In general, if you're unsure, we request that you to default to treating things
as security issues and handling them sensitively, the worst thing that can
happen is that we'll ask you to file a bug issue.
Reporting a security issue
--------------------------
We ask that you do not report security issues to our normal GitHub issue
tracker.
If you believe you've identified a security issue with ``cryptography``, please
report it to ``alex.gaynor@gmail.com``. Messages may be optionally encrypted
with PGP using key fingerprint
``F7FC 698F AAE2 D2EF BECD E98E D1B3 ADC0 E023 8CA6`` (this public key is
available from most commonly-used key servers).
Once you've submitted an issue via email, you should receive an acknowledgment
within 48 hours, and depending on the action to be taken, you may receive
further follow-up emails.
Supported Versions
------------------
At any given time, we will provide security support for the `master`_ branch
as well as the most recent release.
New releases for OpenSSL updates
--------------------------------
As of version 0.5, ``cryptography`` statically links OpenSSL on Windows, and as
of version 1.0.1 on OS X, to ease installation. Due to this, ``cryptography``
will release a new version whenever OpenSSL has a security or bug fix release to
avoid shipping insecure software.
Like all our other releases, this will be announced on the mailing list and we
strongly recommend that you upgrade as soon as possible.
Disclosure Process
------------------
Our process for taking a security issue from private discussion to public
disclosure involves multiple steps.
Approximately one week before full public disclosure, we will send advance
notification of the issue to a list of people and organizations, primarily
composed of operating-system vendors and other distributors of
``cryptography``. This notification will consist of an email message
containing:
* A full description of the issue and the affected versions of
``cryptography``.
* The steps we will be taking to remedy the issue.
* The patches, if any, that will be applied to ``cryptography``.
* The date on which the ``cryptography`` team will apply these patches, issue
new releases, and publicly disclose the issue.
Simultaneously, the reporter of the issue will receive notification of the date
on which we plan to take the issue public.
On the day of disclosure, we will take the following steps:
* Apply the relevant patches to the ``cryptography`` repository. The commit
messages for these patches will indicate that they are for security issues,
but will not describe the issue in any detail; instead, they will warn of
upcoming disclosure.
* Issue the relevant releases.
* Post a notice to the cryptography mailing list that describes the issue in
detail, point to the new release and crediting the reporter of the issue.
If a reported issue is believed to be particularly time-sensitive due to a
known exploit in the wild, for example the time between advance notification
and public disclosure may be shortened considerably.
The list of people and organizations who receives advanced notification of
security issues is not and will not be made public. This list generally
consists of high profile downstream distributors and is entirely at the
discretion of the ``cryptography`` team.
.. _`master`: https://github.com/pyca/cryptography

View File

@ -0,0 +1,94 @@
affine
Authenticator
backend
Backends
backends
bcrypt
Blowfish
boolean
Botan
Capitan
Changelog
ciphertext
committer
committers
conda
Cryptanalysis
crypto
cryptographic
cryptographically
Debian
decrypt
decrypted
decrypting
DER
deserialize
deserialized
Deserialization
Diffie
Diffie
disambiguating
Django
Docstrings
El
Encodings
endian
fallback
Fernet
fernet
FIPS
Google
hazmat
hostname
indistinguishability
initialisms
interoperable
introspectability
invariants
iOS
iterable
Koblitz
Lange
logins
metadata
Mozilla
multi
namespace
namespaces
macOS
naïve
Nonces
nonces
online
paddings
Parallelization
personalization
pickleable
plaintext
pre
preprocessor
preprocessors
pseudorandom
pyOpenSSL
relicensed
responder
runtime
Schneier
scrypt
serializer
Serializers
SHA
Solaris
syscall
Tanja
testability
tunable
Ubuntu
unencrypted
unpadded
unpadding
verifier
Verifier
Verisign
wildcard
Xcode

15
docs/x509/index.rst Normal file
View File

@ -0,0 +1,15 @@
X.509
=====
X.509 is an ITU-T standard for a `public key infrastructure`_. X.509v3 is
defined in :rfc:`5280` (which obsoletes :rfc:`2459` and :rfc:`3280`). X.509
certificates are commonly used in protocols like `TLS`_.
.. toctree::
:maxdepth: 2
tutorial
reference
.. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure
.. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security

2697
docs/x509/reference.rst Normal file

File diff suppressed because it is too large Load Diff

154
docs/x509/tutorial.rst Normal file
View File

@ -0,0 +1,154 @@
Tutorial
========
X.509 certificates are used to authenticate clients and servers. The most
common use case is for web servers using HTTPS.
Creating a Certificate Signing Request (CSR)
--------------------------------------------
When obtaining a certificate from a certificate authority (CA), the usual
flow is:
1. You generate a private/public key pair.
2. You create a request for a certificate, which is signed by your key (to
prove that you own that key).
3. You give your CSR to a CA (but *not* the private key).
4. The CA validates that you own the resource (e.g. domain) you want a
certificate for.
5. The CA gives you a certificate, signed by them, which identifies your public
key, and the resource you are authenticated for.
6. You configure your server to use that certificate, combined with your
private key, to server traffic.
If you want to obtain a certificate from a typical commercial CA, here's how.
First, you'll need to generate a private key, we'll generate an RSA key (these
are the most common types of keys on the web right now):
.. code-block:: pycon
>>> from cryptography.hazmat.backends import default_backend
>>> from cryptography.hazmat.primitives import serialization
>>> from cryptography.hazmat.primitives.asymmetric import rsa
>>> # Generate our key
>>> key = rsa.generate_private_key(
... public_exponent=65537,
... key_size=2048,
... backend=default_backend()
... )
>>> # Write our key to disk for safe keeping
>>> with open("path/to/store/key.pem", "wb") as f:
... f.write(key.private_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PrivateFormat.TraditionalOpenSSL,
... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
... ))
If you've already generated a key you can load it with
:func:`~cryptography.hazmat.primitives.serialization.load_pem_private_key`.
Next we need to generate a certificate signing request. A typical CSR contains
a few details:
* Information about our public key (including a signature of the entire body).
* Information about who *we* are.
* Information about what domains this certificate is for.
.. code-block:: pycon
>>> from cryptography import x509
>>> from cryptography.x509.oid import NameOID
>>> from cryptography.hazmat.primitives import hashes
>>> # Generate a CSR
>>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
... # Provide various details about who we are.
... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"),
... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
... ])).add_extension(
... x509.SubjectAlternativeName([
... # Describe what sites we want this certificate for.
... x509.DNSName(u"mysite.com"),
... x509.DNSName(u"www.mysite.com"),
... x509.DNSName(u"subdomain.mysite.com"),
... ]),
... critical=False,
... # Sign the CSR with our private key.
... ).sign(key, hashes.SHA256(), default_backend())
>>> # Write our CSR out to disk.
>>> with open("path/to/csr.pem", "wb") as f:
... f.write(csr.public_bytes(serialization.Encoding.PEM))
Now we can give our CSR to a CA, who will give a certificate to us in return.
Creating a self-signed certificate
----------------------------------
While most of the time you want a certificate that has been *signed* by someone
else (i.e. a certificate authority), so that trust is established, sometimes
you want to create a self-signed certificate. Self-signed certificates are not
issued by a certificate authority, but instead they are signed by the private
key corresponding to the public key they embed.
This means that other people don't trust these certificates, but it also means
they can be issued very easily. In general the only use case for a self-signed
certificate is local testing, where you don't need anyone else to trust your
certificate.
Like generating a CSR, we start with creating a new private key:
.. code-block:: pycon
>>> # Generate our key
>>> key = rsa.generate_private_key(
... public_exponent=65537,
... key_size=2048,
... backend=default_backend()
... )
>>> # Write our key to disk for safe keeping
>>> with open("path/to/store/key.pem", "wb") as f:
... f.write(key.private_bytes(
... encoding=serialization.Encoding.PEM,
... format=serialization.PrivateFormat.TraditionalOpenSSL,
... encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
... ))
Then we generate the certificate itself:
.. code-block:: pycon
>>> # Various details about who we are. For a self-signed certificate the
>>> # subject and issuer are always the same.
>>> subject = issuer = x509.Name([
... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"),
... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"),
... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"),
... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"),
... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"),
... ])
>>> cert = x509.CertificateBuilder().subject_name(
... subject
... ).issuer_name(
... issuer
... ).public_key(
... private_key.public_key()
... ).serial_number(
... x509.random_serial_number()
... ).not_valid_before(
... datetime.datetime.utcnow()
... ).not_valid_after(
... # Our certificate will be valid for 10 days
... datetime.datetime.utcnow() + datetime.timedelta(days=10)
... ).add_extension(
... x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
... critical=False,
... # Sign our certificate with our private key
... ).sign(private_key, hashes.SHA256(), default_backend())
>>> # Write our certificate out to disk.
>>> with open("path/to/certificate.pem", "wb") as f:
... f.write(cert.public_bytes(serialization.Encoding.PEM))
And now we have a private key and certificate that can be used for local
testing.

5
setup.cfg Normal file
View File

@ -0,0 +1,5 @@
[egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0

335
setup.py Normal file
View File

@ -0,0 +1,335 @@
#!/usr/bin/env python
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import os
import platform
import subprocess
import sys
from distutils.command.build import build
import pkg_resources
from setuptools import find_packages, setup
from setuptools.command.install import install
from setuptools.command.test import test
base_dir = os.path.dirname(__file__)
src_dir = os.path.join(base_dir, "src")
# When executing the setup.py, we need to be able to import ourselves, this
# means that we need to add the src/ directory to the sys.path.
sys.path.insert(0, src_dir)
about = {}
with open(os.path.join(src_dir, "cryptography", "__about__.py")) as f:
exec(f.read(), about)
VECTORS_DEPENDENCY = "cryptography_vectors=={0}".format(about['__version__'])
requirements = [
"idna>=2.0",
"pyasn1>=0.1.8",
"six>=1.4.1",
"setuptools>=11.3",
]
setup_requirements = []
if sys.version_info < (3, 4):
requirements.append("enum34")
if sys.version_info < (3, 3):
requirements.append("ipaddress")
if platform.python_implementation() == "PyPy":
if sys.pypy_version_info < (2, 6):
raise RuntimeError(
"cryptography 1.0 is not compatible with PyPy < 2.6. Please "
"upgrade PyPy to use this library."
)
else:
requirements.append("cffi>=1.4.1")
setup_requirements.append("cffi>=1.4.1")
test_requirements = [
"pytest>=2.9.0",
"pretend",
"iso8601",
"pyasn1_modules",
"pytz",
]
if sys.version_info[:2] > (2, 6):
test_requirements.append("hypothesis>=1.11.4")
# If there's no vectors locally that probably means we are in a tarball and
# need to go and get the matching vectors package from PyPi
if not os.path.exists(os.path.join(base_dir, "vectors/setup.py")):
test_requirements.append(VECTORS_DEPENDENCY)
def cc_is_available():
return sys.platform == "darwin" and list(map(
int, platform.mac_ver()[0].split("."))) >= [10, 8, 0]
backends = [
"openssl = cryptography.hazmat.backends.openssl:backend"
]
if cc_is_available():
backends.append(
"commoncrypto = cryptography.hazmat.backends.commoncrypto:backend",
)
class PyTest(test):
def finalize_options(self):
test.finalize_options(self)
self.test_args = []
self.test_suite = True
# This means there's a vectors/ folder with the package in here.
# cd into it, install the vectors package and then refresh sys.path
if VECTORS_DEPENDENCY not in test_requirements:
subprocess.check_call(
[sys.executable, "setup.py", "install"], cwd="vectors"
)
pkg_resources.get_distribution("cryptography_vectors").activate()
def run_tests(self):
# Import here because in module scope the eggs are not loaded.
import pytest
test_args = [os.path.join(base_dir, "tests")]
errno = pytest.main(test_args)
sys.exit(errno)
def keywords_with_side_effects(argv):
"""
Get a dictionary with setup keywords that (can) have side effects.
:param argv: A list of strings with command line arguments.
:returns: A dictionary with keyword arguments for the ``setup()`` function.
This setup.py script uses the setuptools 'setup_requires' feature because
this is required by the cffi package to compile extension modules. The
purpose of ``keywords_with_side_effects()`` is to avoid triggering the cffi
build process as a result of setup.py invocations that don't need the cffi
module to be built (setup.py serves the dual purpose of exposing package
metadata).
All of the options listed by ``python setup.py --help`` that print
information should be recognized here. The commands ``clean``,
``egg_info``, ``register``, ``sdist`` and ``upload`` are also recognized.
Any combination of these options and commands is also supported.
This function was originally based on the `setup.py script`_ of SciPy (see
also the discussion in `pip issue #25`_).
.. _pip issue #25: https://github.com/pypa/pip/issues/25
.. _setup.py script: https://github.com/scipy/scipy/blob/master/setup.py
"""
no_setup_requires_arguments = (
'-h', '--help',
'-n', '--dry-run',
'-q', '--quiet',
'-v', '--verbose',
'-V', '--version',
'--author',
'--author-email',
'--classifiers',
'--contact',
'--contact-email',
'--description',
'--egg-base',
'--fullname',
'--help-commands',
'--keywords',
'--licence',
'--license',
'--long-description',
'--maintainer',
'--maintainer-email',
'--name',
'--no-user-cfg',
'--obsoletes',
'--platforms',
'--provides',
'--requires',
'--url',
'clean',
'egg_info',
'register',
'sdist',
'upload',
)
def is_short_option(argument):
"""Check whether a command line argument is a short option."""
return len(argument) >= 2 and argument[0] == '-' and argument[1] != '-'
def expand_short_options(argument):
"""Expand combined short options into canonical short options."""
return ('-' + char for char in argument[1:])
def argument_without_setup_requirements(argv, i):
"""Check whether a command line argument needs setup requirements."""
if argv[i] in no_setup_requires_arguments:
# Simple case: An argument which is either an option or a command
# which doesn't need setup requirements.
return True
elif (is_short_option(argv[i]) and
all(option in no_setup_requires_arguments
for option in expand_short_options(argv[i]))):
# Not so simple case: Combined short options none of which need
# setup requirements.
return True
elif argv[i - 1:i] == ['--egg-base']:
# Tricky case: --egg-info takes an argument which should not make
# us use setup_requires (defeating the purpose of this code).
return True
else:
return False
if all(argument_without_setup_requirements(argv, i)
for i in range(1, len(argv))):
return {
"cmdclass": {
"build": DummyBuild,
"install": DummyInstall,
"test": DummyPyTest,
}
}
else:
cffi_modules = [
"src/_cffi_src/build_openssl.py:ffi",
"src/_cffi_src/build_constant_time.py:ffi",
"src/_cffi_src/build_padding.py:ffi",
]
if cc_is_available():
cffi_modules.append("src/_cffi_src/build_commoncrypto.py:ffi")
return {
"setup_requires": setup_requirements,
"cmdclass": {
"test": PyTest,
},
"cffi_modules": cffi_modules
}
setup_requires_error = ("Requested setup command that needs 'setup_requires' "
"while command line arguments implied a side effect "
"free command or option.")
class DummyBuild(build):
"""
This class makes it very obvious when ``keywords_with_side_effects()`` has
incorrectly interpreted the command line arguments to ``setup.py build`` as
one of the 'side effect free' commands or options.
"""
def run(self):
raise RuntimeError(setup_requires_error)
class DummyInstall(install):
"""
This class makes it very obvious when ``keywords_with_side_effects()`` has
incorrectly interpreted the command line arguments to ``setup.py install``
as one of the 'side effect free' commands or options.
"""
def run(self):
raise RuntimeError(setup_requires_error)
class DummyPyTest(test):
"""
This class makes it very obvious when ``keywords_with_side_effects()`` has
incorrectly interpreted the command line arguments to ``setup.py test`` as
one of the 'side effect free' commands or options.
"""
def run_tests(self):
raise RuntimeError(setup_requires_error)
with open(os.path.join(base_dir, "README.rst")) as f:
long_description = f.read()
setup(
name=about["__title__"],
version=about["__version__"],
description=about["__summary__"],
long_description=long_description,
license=about["__license__"],
url=about["__uri__"],
author=about["__author__"],
author_email=about["__email__"],
classifiers=[
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"License :: OSI Approved :: BSD License",
"Natural Language :: English",
"Operating System :: MacOS :: MacOS X",
"Operating System :: POSIX",
"Operating System :: POSIX :: BSD",
"Operating System :: POSIX :: Linux",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Security :: Cryptography",
],
package_dir={"": "src"},
packages=find_packages(where="src", exclude=["_cffi_src", "_cffi_src.*"]),
include_package_data=True,
install_requires=requirements,
tests_require=test_requirements,
extras_require={
"test": test_requirements,
"docstest": [
"doc8",
"pyenchant",
"readme_renderer >= 16.0",
"sphinx",
"sphinx_rtd_theme",
"sphinxcontrib-spelling",
],
"pep8test": [
"flake8",
"flake8-import-order",
"pep8-naming",
],
},
# for cffi
zip_safe=False,
ext_package="cryptography.hazmat.bindings",
entry_points={
"cryptography.backends": backends,
},
**keywords_with_side_effects(sys.argv)
)

View File

View File

@ -0,0 +1,33 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from _cffi_src.utils import build_ffi_for_binding
ffi = build_ffi_for_binding(
module_name="_commoncrypto",
module_prefix="_cffi_src.commoncrypto.",
modules=[
"cf",
"common_digest",
"common_hmac",
"common_key_derivation",
"common_cryptor",
"common_symmetric_key_wrap",
"seccertificate",
"secimport",
"secitem",
"seckey",
"seckeychain",
"secpolicy",
"sectransform",
"sectrust",
"secure_transport",
],
extra_link_args=[
"-framework", "Security", "-framework", "CoreFoundation"
],
)

View File

@ -0,0 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import os
from _cffi_src.utils import build_ffi, compiler_type, extra_link_args
with open(os.path.join(
os.path.dirname(__file__), "hazmat_src/constant_time.h"
)) as f:
types = f.read()
with open(os.path.join(
os.path.dirname(__file__), "hazmat_src/constant_time.c"
)) as f:
functions = f.read()
ffi = build_ffi(
module_name="_constant_time",
cdef_source=types,
verify_source=functions,
extra_link_args=extra_link_args(compiler_type()),
)

View File

@ -0,0 +1,86 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import os
import sys
from _cffi_src.utils import (
build_ffi_for_binding, compiler_type, extra_link_args
)
def _get_openssl_libraries(platform):
# OpenSSL goes by a different library name on different operating systems.
if platform == "darwin":
return _osx_libraries(
os.environ.get("CRYPTOGRAPHY_OSX_NO_LINK_FLAGS")
)
elif platform == "win32":
if compiler_type() == "msvc":
libs = ["libeay32", "ssleay32"]
else:
libs = ["ssl", "crypto"]
return libs + ["advapi32", "crypt32", "gdi32", "user32", "ws2_32"]
else:
# In some circumstances, the order in which these libs are
# specified on the linker command-line is significant;
# libssl must come before libcrypto
# (http://marc.info/?l=openssl-users&m=135361825921871)
return ["ssl", "crypto"]
def _osx_libraries(build_static):
# For building statically we don't want to pass the -lssl or -lcrypto flags
if build_static == "1":
return []
else:
return ["ssl", "crypto"]
ffi = build_ffi_for_binding(
module_name="_openssl",
module_prefix="_cffi_src.openssl.",
modules=[
# This goes first so we can define some cryptography-wide symbols.
"cryptography",
"aes",
"asn1",
"bignum",
"bio",
"cmac",
"cms",
"conf",
"crypto",
"dh",
"dsa",
"ec",
"ecdh",
"ecdsa",
"engine",
"err",
"evp",
"hmac",
"nid",
"objects",
"ocsp",
"opensslv",
"osrandom_engine",
"pem",
"pkcs12",
"rand",
"rsa",
"ssl",
"x509",
"x509name",
"x509v3",
"x509_vfy",
"pkcs7",
"callbacks",
],
libraries=_get_openssl_libraries(sys.platform),
extra_link_args=extra_link_args(compiler_type()),
)

View File

@ -0,0 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import os
from _cffi_src.utils import build_ffi, compiler_type, extra_link_args
with open(os.path.join(
os.path.dirname(__file__), "hazmat_src/padding.h"
)) as f:
types = f.read()
with open(os.path.join(
os.path.dirname(__file__), "hazmat_src/padding.c"
)) as f:
functions = f.read()
ffi = build_ffi(
module_name="_padding",
cdef_source=types,
verify_source=functions,
extra_link_args=extra_link_args(compiler_type()),
)

View File

@ -0,0 +1,5 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function

View File

@ -0,0 +1,113 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CoreFoundation/CoreFoundation.h>
"""
TYPES = """
typedef bool Boolean;
typedef signed long OSStatus;
typedef unsigned char UInt8;
typedef uint32_t UInt32;
typedef const void * CFAllocatorRef;
const CFAllocatorRef kCFAllocatorDefault;
typedef ... *CFDataRef;
typedef signed long long CFIndex;
typedef ... *CFStringRef;
typedef ... *CFArrayRef;
typedef ... *CFMutableArrayRef;
typedef ... *CFBooleanRef;
typedef ... *CFErrorRef;
typedef ... *CFNumberRef;
typedef ... *CFTypeRef;
typedef ... *CFDictionaryRef;
typedef ... *CFMutableDictionaryRef;
typedef struct {
...;
} CFDictionaryKeyCallBacks;
typedef struct {
...;
} CFDictionaryValueCallBacks;
typedef struct {
...;
} CFRange;
typedef struct {
...;
} CFArrayCallBacks;
typedef UInt32 CFStringEncoding;
enum {
kCFStringEncodingASCII = 0x0600
};
enum {
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
typedef int CFNumberType;
const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
const CFArrayCallBacks kCFTypeArrayCallBacks;
const CFBooleanRef kCFBooleanTrue;
const CFBooleanRef kCFBooleanFalse;
"""
FUNCTIONS = """
CFDataRef CFDataCreate(CFAllocatorRef, const UInt8 *, CFIndex);
CFStringRef CFStringCreateWithCString(CFAllocatorRef, const char *,
CFStringEncoding);
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef, const void **,
const void **, CFIndex,
const CFDictionaryKeyCallBacks *,
const CFDictionaryValueCallBacks *);
CFMutableDictionaryRef CFDictionaryCreateMutable(
CFAllocatorRef,
CFIndex,
const CFDictionaryKeyCallBacks *,
const CFDictionaryValueCallBacks *
);
void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *);
CFIndex CFArrayGetCount(CFArrayRef);
const void *CFArrayGetValueAtIndex(CFArrayRef, CFIndex);
CFIndex CFDataGetLength(CFDataRef);
void CFDataGetBytes(CFDataRef, CFRange, UInt8 *);
CFRange CFRangeMake(CFIndex, CFIndex);
void CFShow(CFTypeRef);
Boolean CFBooleanGetValue(CFBooleanRef);
CFNumberRef CFNumberCreate(CFAllocatorRef, CFNumberType, const void *);
void CFRelease(CFTypeRef);
CFTypeRef CFRetain(CFTypeRef);
CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef, CFIndex,
const CFArrayCallBacks *);
void CFArrayAppendValue(CFMutableArrayRef, const void *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,99 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CommonCrypto/CommonCryptor.h>
"""
TYPES = """
enum {
kCCAlgorithmAES128 = 0,
kCCAlgorithmDES,
kCCAlgorithm3DES,
kCCAlgorithmCAST,
kCCAlgorithmRC4,
kCCAlgorithmRC2,
kCCAlgorithmBlowfish
};
typedef uint32_t CCAlgorithm;
enum {
kCCSuccess = 0,
kCCParamError = -4300,
kCCBufferTooSmall = -4301,
kCCMemoryFailure = -4302,
kCCAlignmentError = -4303,
kCCDecodeError = -4304,
kCCUnimplemented = -4305
};
typedef int32_t CCCryptorStatus;
typedef uint32_t CCOptions;
enum {
kCCEncrypt = 0,
kCCDecrypt,
};
typedef uint32_t CCOperation;
typedef ... *CCCryptorRef;
enum {
kCCModeOptionCTR_LE = 0x0001,
kCCModeOptionCTR_BE = 0x0002
};
typedef uint32_t CCModeOptions;
enum {
kCCModeECB = 1,
kCCModeCBC = 2,
kCCModeCFB = 3,
kCCModeCTR = 4,
kCCModeF8 = 5,
kCCModeLRW = 6,
kCCModeOFB = 7,
kCCModeXTS = 8,
kCCModeRC4 = 9,
kCCModeCFB8 = 10,
kCCModeGCM = 11
};
typedef uint32_t CCMode;
enum {
ccNoPadding = 0,
ccPKCS7Padding = 1,
};
typedef uint32_t CCPadding;
"""
FUNCTIONS = """
CCCryptorStatus CCCryptorCreateWithMode(CCOperation, CCMode, CCAlgorithm,
CCPadding, const void *, const void *,
size_t, const void *, size_t, int,
CCModeOptions, CCCryptorRef *);
CCCryptorStatus CCCryptorCreate(CCOperation, CCAlgorithm, CCOptions,
const void *, size_t, const void *,
CCCryptorRef *);
CCCryptorStatus CCCryptorUpdate(CCCryptorRef, const void *, size_t, void *,
size_t, size_t *);
CCCryptorStatus CCCryptorFinal(CCCryptorRef, void *, size_t, size_t *);
CCCryptorStatus CCCryptorRelease(CCCryptorRef);
CCCryptorStatus CCCryptorGCMAddIV(CCCryptorRef, const void *, size_t);
CCCryptorStatus CCCryptorGCMAddAAD(CCCryptorRef, const void *, size_t);
CCCryptorStatus CCCryptorGCMEncrypt(CCCryptorRef, const void *, size_t,
void *);
CCCryptorStatus CCCryptorGCMDecrypt(CCCryptorRef, const void *, size_t,
void *);
CCCryptorStatus CCCryptorGCMFinal(CCCryptorRef, const void *, size_t *);
CCCryptorStatus CCCryptorGCMReset(CCCryptorRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
/* Not defined in the public header */
enum {
kCCModeGCM = 11
};
"""

View File

@ -0,0 +1,58 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CommonCrypto/CommonDigest.h>
"""
TYPES = """
typedef uint32_t CC_LONG;
typedef uint64_t CC_LONG64;
typedef struct CC_MD5state_st {
...;
} CC_MD5_CTX;
typedef struct CC_SHA1state_st {
...;
} CC_SHA1_CTX;
typedef struct CC_SHA256state_st {
...;
} CC_SHA256_CTX;
typedef struct CC_SHA512state_st {
...;
} CC_SHA512_CTX;
"""
FUNCTIONS = """
int CC_MD5_Init(CC_MD5_CTX *);
int CC_MD5_Update(CC_MD5_CTX *, const void *, CC_LONG);
int CC_MD5_Final(unsigned char *, CC_MD5_CTX *);
int CC_SHA1_Init(CC_SHA1_CTX *);
int CC_SHA1_Update(CC_SHA1_CTX *, const void *, CC_LONG);
int CC_SHA1_Final(unsigned char *, CC_SHA1_CTX *);
int CC_SHA224_Init(CC_SHA256_CTX *);
int CC_SHA224_Update(CC_SHA256_CTX *, const void *, CC_LONG);
int CC_SHA224_Final(unsigned char *, CC_SHA256_CTX *);
int CC_SHA256_Init(CC_SHA256_CTX *);
int CC_SHA256_Update(CC_SHA256_CTX *, const void *, CC_LONG);
int CC_SHA256_Final(unsigned char *, CC_SHA256_CTX *);
int CC_SHA384_Init(CC_SHA512_CTX *);
int CC_SHA384_Update(CC_SHA512_CTX *, const void *, CC_LONG);
int CC_SHA384_Final(unsigned char *, CC_SHA512_CTX *);
int CC_SHA512_Init(CC_SHA512_CTX *);
int CC_SHA512_Update(CC_SHA512_CTX *, const void *, CC_LONG);
int CC_SHA512_Final(unsigned char *, CC_SHA512_CTX *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,37 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CommonCrypto/CommonHMAC.h>
"""
TYPES = """
typedef struct {
...;
} CCHmacContext;
enum {
kCCHmacAlgSHA1,
kCCHmacAlgMD5,
kCCHmacAlgSHA256,
kCCHmacAlgSHA384,
kCCHmacAlgSHA512,
kCCHmacAlgSHA224
};
typedef uint32_t CCHmacAlgorithm;
"""
FUNCTIONS = """
void CCHmacInit(CCHmacContext *, CCHmacAlgorithm, const void *, size_t);
void CCHmacUpdate(CCHmacContext *, const void *, size_t);
void CCHmacFinal(CCHmacContext *, void *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,39 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CommonCrypto/CommonKeyDerivation.h>
"""
TYPES = """
enum {
kCCPBKDF2 = 2,
};
typedef uint32_t CCPBKDFAlgorithm;
enum {
kCCPRFHmacAlgSHA1 = 1,
kCCPRFHmacAlgSHA224 = 2,
kCCPRFHmacAlgSHA256 = 3,
kCCPRFHmacAlgSHA384 = 4,
kCCPRFHmacAlgSHA512 = 5,
};
typedef uint32_t CCPseudoRandomAlgorithm;
typedef unsigned int uint;
"""
FUNCTIONS = """
int CCKeyDerivationPBKDF(CCPBKDFAlgorithm, const char *, size_t,
const uint8_t *, size_t, CCPseudoRandomAlgorithm,
uint, uint8_t *, size_t);
uint CCCalibratePBKDF(CCPBKDFAlgorithm, size_t, size_t,
CCPseudoRandomAlgorithm, size_t, uint32_t);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,35 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <CommonCrypto/CommonSymmetricKeywrap.h>
"""
TYPES = """
enum {
kCCWRAPAES = 1,
};
typedef uint32_t CCWrappingAlgorithm;
"""
FUNCTIONS = """
int CCSymmetricKeyWrap(CCWrappingAlgorithm, const uint8_t *, const size_t,
const uint8_t *, size_t, const uint8_t *, size_t,
uint8_t *, size_t *);
int CCSymmetricKeyUnwrap(CCWrappingAlgorithm algorithm, const uint8_t *,
const size_t, const uint8_t *, size_t,
const uint8_t *, size_t, uint8_t *, size_t *);
size_t CCSymmetricWrappedSize(CCWrappingAlgorithm, size_t);
size_t CCSymmetricUnwrappedSize(CCWrappingAlgorithm, size_t);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,23 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <Security/SecCertificate.h>
"""
TYPES = """
typedef ... *SecCertificateRef;
"""
FUNCTIONS = """
SecCertificateRef SecCertificateCreateWithData(CFAllocatorRef, CFDataRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,86 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <Security/SecImportExport.h>
"""
TYPES = """
typedef ... *SecAccessRef;
CFStringRef kSecImportExportPassphrase;
CFStringRef kSecImportExportKeychain;
CFStringRef kSecImportExportAccess;
typedef uint32_t SecExternalItemType;
enum {
kSecItemTypeUnknown,
kSecItemTypePrivateKey,
kSecItemTypePublicKey,
kSecItemTypeSessionKey,
kSecItemTypeCertificate,
kSecItemTypeAggregate
};
typedef uint32_t SecExternalFormat;
enum {
kSecFormatUnknown = 0,
kSecFormatOpenSSL,
kSecFormatSSH,
kSecFormatBSAFE,
kSecFormatRawKey,
kSecFormatWrappedPKCS8,
kSecFormatWrappedOpenSSL,
kSecFormatWrappedSSH,
kSecFormatWrappedLSH,
kSecFormatX509Cert,
kSecFormatPEMSequence,
kSecFormatPKCS7,
kSecFormatPKCS12,
kSecFormatNetscapeCertSequence,
kSecFormatSSHv2
};
typedef uint32_t SecItemImportExportFlags;
enum {
kSecKeyImportOnlyOne = 0x00000001,
kSecKeySecurePassphrase = 0x00000002,
kSecKeyNoAccessControl = 0x00000004
};
typedef uint32_t SecKeyImportExportFlags;
typedef struct {
/* for import and export */
uint32_t version;
SecKeyImportExportFlags flags;
CFTypeRef passphrase;
CFStringRef alertTitle;
CFStringRef alertPrompt;
/* for import only */
SecAccessRef accessRef;
CFArrayRef keyUsage;
CFArrayRef keyAttributes;
} SecItemImportExportKeyParameters;
"""
FUNCTIONS = """
OSStatus SecItemImport(CFDataRef, CFStringRef, SecExternalFormat *,
SecExternalItemType *, SecItemImportExportFlags,
const SecItemImportExportKeyParameters *,
SecKeychainRef, CFArrayRef *);
OSStatus SecPKCS12Import(CFDataRef, CFDictionaryRef, CFArrayRef *);
OSStatus SecItemExport(CFTypeRef, SecExternalFormat, SecItemImportExportFlags,
const SecItemImportExportKeyParameters *, CFDataRef *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

View File

@ -0,0 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <Security/SecItem.h>
"""
TYPES = """
const CFTypeRef kSecAttrKeyType;
const CFTypeRef kSecAttrKeySizeInBits;
const CFTypeRef kSecAttrIsPermanent;
const CFTypeRef kSecAttrKeyTypeRSA;
const CFTypeRef kSecAttrKeyTypeDSA;
const CFTypeRef kSecUseKeychain;
"""
FUNCTIONS = """
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""

Some files were not shown because too many files have changed in this diff Show More