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:
commit
443c9c11a1
|
@ -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>
|
|
@ -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/
|
|
@ -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/
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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 *
|
|
@ -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
|
|
@ -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
|
|
@ -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,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.
|
|
@ -0,0 +1 @@
|
|||
.. include:: ../CHANGELOG.rst
|
|
@ -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/
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
|
@ -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>`
|
|
@ -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')
|
|
@ -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.")
|
||||
}
|
|
@ -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>`
|
|
@ -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")
|
|
@ -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.")
|
||||
}
|
|
@ -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
|
|
@ -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")
|
|
@ -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)
|
|
@ -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
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
)
|
|
@ -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
|
|
@ -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
|
||||
)
|
|
@ -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)
|
|
@ -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
|
|
@ -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")
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,238 @@
|
|||
.. hazmat::
|
||||
|
||||
Diffie-Hellman key exchange
|
||||
===========================
|
||||
|
||||
.. currentmodule:: cryptography.hazmat.primitives.asymmetric.dh
|
||||
|
||||
|
||||
`Diffie-Hellman key exchange`_ (D–H) is a method that allows two parties
|
||||
to jointly agree on a shared secret using an insecure channel.
|
||||
|
||||
|
||||
Exchange Algorithm
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For most applications the ``shared_key`` should be passed to a key
|
||||
derivation function.
|
||||
|
||||
.. 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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.
|
|
@ -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())
|
||||
... )
|
|
@ -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/
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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
|
|
@ -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:
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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/
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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/
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
|
@ -0,0 +1,5 @@
|
|||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
|
@ -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)
|
||||
)
|
|
@ -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"
|
||||
],
|
||||
)
|
|
@ -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()),
|
||||
)
|
|
@ -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()),
|
||||
)
|
|
@ -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()),
|
||||
)
|
|
@ -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
|
|
@ -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 = """
|
||||
"""
|
|
@ -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
|
||||
};
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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 = """
|
||||
"""
|
|
@ -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
Loading…
Reference in New Issue