Api Stability
API stability
=============
From its first release, `cryptography has had 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.
* Unless otherwise documented, types in cryptography are not intended to
be sub-classed, and we do not guarantee that behavior with respect to
sub-classes will be stable.
* 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 hardencryptography against a possible attack.
Versioning
----------
Version 35.0.0+
~~~~~~~~~~~~~~~
Beginning with release 35.0.0 cryptography uses a Firefox-inspired version
scheme.
Given a version cryptography X.Y.Z,
* X indicates the major version number. This is incremented on any feature
release.
* Y is always 0.
* Z is an integer that is incremented for minor backward-compatible
releases (such as fixing security issues or correcting regressions in a major
release).
This scheme is compatible with SemVer_, though many major releases will
not include any backwards-incompatible changes.
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.0.0 the feature exists.
* In cryptography (X + 1).0.0 using that feature will emit a
CryptographyDeprecationWarning (base class UserWarning).
* In cryptography (X + 2).0.0 using that feature will emit a
CryptographyDeprecationWarning.
* In cryptography (X + 3).0.0 the feature will be removed or changed.
In short, code that runs without warnings will always continue to work for a
period of two major releases.
From time to time, we may decide to deprecate an API that is particularly
widely used. In these cases, we may decide to provide an extended deprecation
period, at our discretion.
Previous Scheme
~~~~~~~~~~~~~~~
Before version 35.0.0 this project uses a custom versioning scheme as described
below.
Given a version cryptography X.Y.Z,
* X.Y is a decimal number that is incremented for
potentially-backwards-incompatible releases.
* This increases like a standard decimal.
In other words, 0.9 is the ninth release, and 1.0 is the tenth (not 0.10).
The dividing decimal point can effectively be ignored.
* Z is an integer that is incremented for backward-compatible releases.
.. _SemVer: https://semver.org/
---
Cobblestone
Cobblestone (streaming symmetric encryption)
=============================================
.. currentmodule:: cryptography.cobblestone
Cobblestone provides authenticated symmetric encryption of large
messages — up to 4 PiB — as a stream, without ever holding the whole
message in memory. It is an implementation of the C2SP
chunked-encryption specification_'s two named instantiations:
Cobblestone-128 (SHA-512 and AES-128-GCM, the recommended choice)
and Cobblestone-256 (SHA-512 and AES-256-GCM, for environments
that mandate 256-bit keys).
.. doctest::
>>> from cryptography.cobblestone import (
... Cobblestone128Decryptor, Cobblestone128Encryptor
... )
>>> key = Cobblestone128Encryptor.generate_key()
>>> encryptor = Cobblestone128Encryptor(
... key, context=b"example-app file encryption"
... )
>>> ciphertext = encryptor.update(b"a secret message")
>>> ciphertext += encryptor.finalize()
>>> decryptor = Cobblestone128Decryptor(
... key, context=b"example-app file encryption"
... )
>>> decryptor.update(ciphertext) + decryptor.finalize()
b'a secret message'
.. class:: Cobblestone128Encryptor(key, context)
.. versionadded:: 50.0.0
Encrypts a single message under key with Cobblestone-128. Eachupdate
instance must be used for exactly one message: call :meth:update_into
(or :meth:) any number of times, then callfinalize
:meth: exactly once. The concatenation of the returned
bytes is the ciphertext.
:param key: A 16-byte key. This must be kept secret, and
must be uniformly random (e.g. the output of
:meth:generate_key — never a password). A single key may bebytes-like
used to encrypt a practically unlimited number of messages.
:type key: :term:Cobblestone128Decryptor
:param context: Application-provided context, bound to the
ciphertext. Decryption fails unless the same value is passed to
:class:. It is not secret, may be
empty, and is not part of the ciphertext, so it must be
available to the decrypting party independently. It can be used
for domain separation, e.g. b"myapp v2 backup encryption".bytes-like
:type context: :term:
:raises ValueError: If key is not 16 bytes.
.. staticmethod:: generate_key()
Generates a fresh 16-byte key.
:return bytes: A new key.
.. method:: update(data)
Encrypts data. Data is internally buffered into 16 KiB
chunks, so between 0 and len(data) + 16 KiB bytes of
ciphertext are returned.
:param data: The data to encrypt.
:type data: :term:bytes-like
:return bytes: The next portion of the ciphertext.
.. method:: update_into(data, buf)
Encrypts data, writing the resulting ciphertext into
buf, and returns the number of bytes written. This avoids
allocating a new buffer for each call.
:param data: The data to encrypt.
:type data: :term:bytes-like
:param buf: A writable buffer to write the ciphertext into. A
buffer of len(data) + len(data) // 1024 + 16456 bytesbytes-like
is always large enough.
:type buf: :term:
:return int: The number of bytes written to buf.
:raises ValueError: If buf is too small.
.. method:: finalize()
Encrypts the final chunk and returns the last portion of the
ciphertext. This must always be called, and the instance cannot
be used afterwards.
:return bytes: The remainder of the ciphertext.
:raises cryptography.exceptions.AlreadyFinalized: If
finalize has already been called.
.. class:: Cobblestone128Decryptor(key, context)
.. versionadded:: 50.0.0
Decrypts a single message encrypted by
:class:Cobblestone128Encryptor with the same key and
context. Call :meth:update (or :meth:update_into) with thefinalize
ciphertext any number of times, then call :meth: exactly
once. The concatenation of the returned bytes is the plaintext.
Any returned plaintext is authenticated, but until
:meth:finalize returns successfully the message could still turn~cryptography.exceptions.InvalidTag
out to be truncated: an application acting on streamed plaintext
before that point must be prepared to discard its work if a later
call raises :class:.
Once any method raises
:class:~cryptography.exceptions.InvalidTag, the instance is~cryptography.exceptions.AlreadyFinalized
permanently unusable and all further calls raise
:class:.
:param key: The 16-byte key the message was encrypted with.
:type key: :term:bytes-likebytes-like
:param context: The context value the message was encrypted with.
:type context: :term:
:raises ValueError: If key is not 16 bytes.
.. method:: update(data)
Processes data, which need not be aligned to any boundary,
and returns the plaintext of all complete chunks that have been
authenticated so far.
:param data: The next portion of the ciphertext.
:type data: :term:bytes-like
:return bytes: The next portion of the plaintext.
:raises cryptography.exceptions.InvalidTag: If the ciphertext
was encrypted with a different key or context, or has been
modified.
.. method:: update_into(data, buf)
Like update, but writes the plaintext into buf and
returns the number of bytes written.
:param data: The next portion of the ciphertext.
:type data: :term:bytes-like
:param buf: A writable buffer to write the plaintext into. A
buffer of len(data) + 16400 bytes is always largebytes-like
enough.
:type buf: :term:
:return int: The number of bytes written to buf.
:raises ValueError: If buf is too small.
:raises cryptography.exceptions.InvalidTag: If the ciphertext
was encrypted with a different key or context, or has been
modified. Note that in this case unauthenticated data may
have been written to buf and must not be used.
.. method:: finalize()
Decrypts and authenticates the final chunk, verifying that the
entire message has been processed, and returns the final
portion of the plaintext. This must always be called: a
successful return is what guarantees the complete message was
authentic and not truncated.
:return bytes: The remainder of the plaintext.
:raises cryptography.exceptions.InvalidTag: If the ciphertext
was truncated or otherwise modified.
:raises cryptography.exceptions.AlreadyFinalized: If
finalize has already been called.
.. class:: Cobblestone256Encryptor(key, context)
.. versionadded:: 50.0.0
Exactly like :class:Cobblestone128Encryptor, but implements
Cobblestone-256: the key is 32 bytes and messages are encrypted
with AES-256-GCM. Use this when a 256-bit key is mandated;
otherwise Cobblestone-128 is recommended.
.. class:: Cobblestone256Decryptor(key, context)
.. versionadded:: 50.0.0
Exactly like :class:Cobblestone128Decryptor, but decryptsCobblestone256Encryptor
messages produced by :class: with a
32-byte key.
.. _C2SP chunked-encryption specification: https://c2sp.org/chunked-encryption
---
Community
Community
=========
You can find cryptography all over the web:
* Mailing list_Source code
* _Issue tracker
* _Documentation
* _
* IRC: #pyca on irc.libera.chat
Wherever we interact, we adhere to the Python Community Code of Conduct_.
.. _Mailing list: https://mail.python.org/mailman/listinfo/cryptography-devSource code
.. _: https://github.com/pyca/cryptographyIssue tracker
.. _: https://github.com/pyca/cryptography/issuesDocumentation
.. _: https://cryptography.io/Python Community Code of Conduct
.. _: https://www.python.org/psf/codeofconduct/
---
Doing A Release
Doing a release
===============
Doing a release of cryptography requires a few steps.
Security Releases
-----------------
In addition to the other steps described below, for a release which fixes a
security vulnerability, you should also include the following steps:
* Request a CVE from MITRE_. Once you have received the CVE, it should bechangelog
included in the :doc:. Ideally you should request the CVE beforechangelog
starting the release process so that the CVE is available at the time of the
release.
* Document the CVE in the git commit that fixes the issue.
* Ensure that the :doc: entry credits whoever reported the issue andoss-security
contains the assigned CVE.
* Publish a GitHub Security Advisory on the repository with all relevant
information.
* The release should be announced on the _ mailing list, in
addition to the regular announcement lists.
Verifying OpenSSL version
-------------------------
The release process creates wheels bundling OpenSSL for Windows, macOS, and
Linux. Check that the Windows, macOS, and Linux builders (the manylinux
containers) have the latest OpenSSL. If anything is out of date follow the
instructions for upgrading OpenSSL.
Upgrading OpenSSL
-----------------
Use the upgrading OpenSSL issue template_.
Bumping the version number
--------------------------
The next step in doing a release is bumping the version number in the
software.
* Run python release.py bump-version {new_version}/changelog
* Set the release date in the :doc:.
* 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 git configured to perform
signed tags. Once this has happened:
* Run python release.py release.
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
------------------
* Send an email to the mailing list_ and python-announce_ announcing themilestone
release.
* Close the _ for the previous release on GitHub.
* For major version releases, send a pull request to pyOpenSSL increasing the
maximum cryptography version pin and perform a pyOpenSSL release.
* Update the version number to the next major (e.g. 0.5.dev1) with
python release.py bump-version {new_version}./changelog
* Add new :doc: 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.
.. _CVE from MITRE: https://cveform.mitre.org/oss-security
.. _: https://www.openwall.com/lists/oss-security/upgrading OpenSSL issue template
.. _: https://github.com/pyca/cryptography/issues/new?template=openssl-release.mdmilestone
.. _: https://github.com/pyca/cryptography/milestonesmailing list
.. _: https://mail.python.org/mailman/listinfo/cryptography-devpython-announce
.. _: https://mail.python.org/mailman3/lists/python-announce-list.python.org/
---
Exceptions
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.
---
Faq
Frequently asked questions
==========================
What issues can you help with in your issue tracker?
----------------------------------------------------
The primary purpose of our issue tracker is to enable us to identify and
resolve bugs and feature requests in cryptography, so any time a user
files a bug, we start by asking: Is this a cryptography bug, or is it a
bug somewhere else?
That said, we do our best to help users to debug issues that are in their code
or environments. Please note, however, that there's a limit to our ability to
assist users in resolving problems that are specific to their environments,
particularly when we have no way to reproduce the issue.
Lastly, we're not able to provide support for general Python or Python
packaging issues.
.. _faq-howto-handle-deprecation-warning:
I cannot suppress the deprecation warning that cryptography emits on import
-------------------------------------------------------------------------------
.. hint::
The deprecation warning emitted on import does not inherit
:py:exc:DeprecationWarning but inherits :py:exc:UserWarning
instead.
If your pytest setup follows the best practices of failing on
emitted warnings (filterwarnings = error), you may ignore it
by adding the following line at the end of the list::
ignore:Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.:UserWarning
Note: Using cryptography.utils.CryptographyDeprecationWarning
is not possible here because specifying it triggersimport cryptography internally that emits the warning before
the ignore rule even kicks in.
Ref: https://github.com/pytest-dev/pytest/issues/7524
The same applies when you use :py:func:~warnings.filterwarnings in-W
your code or invoke CPython with :std:option: command line option.
cryptography failed to install!
-----------------------------------
If you are having issues installing cryptography the first troubleshooting
step is to upgrade pip and then try to install again. For most users this will
take the form of pip install -U pip, but on Windows you should dopython -m pip install -U pip. If you are still seeing errors after upgrading
and trying pip install cryptography again, please see the :doc:/installation
documentation.
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_, which is also
maintained by the PyCA team.
Why use cryptography?
-------------------------
If you've done cryptographic work in Python before you have likely encountered
other libraries in Python such as M2Crypto, PyCrypto, or PyOpenSSL. In
building cryptography we wanted to address a few issues we observed in the
legacy libraries:
* Extremely error prone APIs and insecure defaults.
* Use of poor implementations of algorithms (i.e. ones with known side-channel
attacks).
* Lack of maintenance.
* Lack of high level APIs.
* Lack of PyPy and Python 3 support.
* Absence of algorithms such as
:class:AES-GCM <cryptography.hazmat.primitives.ciphers.aead.AESGCM> and~cryptography.hazmat.primitives.kdf.hkdf.HKDF
:class:.
Why does cryptography require Rust?
---------------------------------------
cryptography uses OpenSSL (see: :doc:/openssl) for its cryptographic operations. OpenSSL ismemory safety
the de facto standard for cryptographic libraries and provides high performance
along with various certifications that may be relevant to developers. However,
it is written in C and lacks _. We want cryptography to be
as secure as possible while retaining the advantages of OpenSSL, so we've
chosen to rewrite non-cryptographic operations (such as ASN.1 parsing) in a
high performance memory safe language: Rust.
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.issue
Please file an _ with instructions on how to reproduce it.
Installing cryptography with OpenSSL older than 3.0.0 fails
------------------------------------------------------------
The OpenSSL project has dropped support for the 0.9.8, 1.0.0, 1.0.1, 1.0.2,
1.1.0, and 1.1.1 release series. Since they are no longer receiving security patches
from upstream, cryptography is also dropping support for them. To fix this
issue you should upgrade to OpenSSL 3.0.0 or later. This may require you to
upgrade to a newer operating system.
Installing cryptography fails with error: Can not find Rust compiler
----------------------------------------------------------------------------
Building cryptography from source requires you have :ref:Rust installed
and available<installation:Rust> on your PATH. You may be able to fix this
by upgrading to a newer version of pip which will install a pre-compiledcryptography wheel. If not, you'll need to install Rust. Follow theinstructions<installation:Rust>
:ref: to ensure you install a recent Rust
version.
Rust is only required during the build phase of cryptography, you do not
need to have Rust installed after you've built cryptography. This is the
same as the C compiler toolchain which is also required to buildcryptography, but not afterwards.
I'm getting errors installing or importing cryptography on AWS Lambda
-------------------------------------------------------------------------
Make sure you're following AWS's documentation either for
building .zip archives for Lambda_ orbuilding container images for Lambda_.
Why are there no wheels for my Python3.x version?
-------------------------------------------------
Our Python3 wheels are abi3 wheels. This means they support multiple
versions of Python. The abi3 wheel can be used with any version of Python
greater than or equal to the version it specifies. Recent versions of pip
will automatically install abi3 wheels.
Why can't I import my PEM file?
-------------------------------
PEM is a format (defined by several RFCs, but originally :rfc:1421) for
encoding keys, certificates, and others cryptographic data into a regular form.
The data is encoded as base64 and wrapped with a header and footer.
If you are having trouble importing PEM files, make sure your file fits
the following rules:
* has a one-line header like this: -----BEGIN [FILE TYPE]-----
(where [FILE TYPE] is CERTIFICATE, PUBLIC KEY, PRIVATE KEY,
etc.)
* has a one-line footer like this: -----END [FILE TYPE]-----
* all lines, except for the final one, must consist of exactly 64
characters.
For example, this is a PEM file for a RSA Public Key: ::
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7CsKFSzq20NLb2VQDXma
9DsDXtKADv0ziI5hT1KG6Bex5seE9pUoEcUxNv4uXo2jzAUgyRweRl/DLU8SoN8+
WWd6YWik4GZvNv7j0z28h9Q5jRySxy4dmElFtIRHGiKhqd1Z06z4AzrmKEzgxkOk
LJjY9cvwD+iXjpK2oJwNNyavvjb5YZq6V60RhpyNtKpMh2+zRLgIk9sROEPQeYfK
22zj2CnGBMg5Gm2uPOsGDltl/I/Fdh1aO3X4i1GXwCuPf1kSAg6lPJD0batftkSG
v0X0heUaV0j1HSNlBWamT4IR9+iJfKJHekOqvHQBcaCu7Ja4kXzx6GZ3M2j/Ja3A
2QIDAQAB
-----END PUBLIC KEY-----
.. _faq-missing-backend:
What happened to the backend argument?
--------------------------------------
cryptography stopped requiring the use of backend arguments in
version 3.1 and deprecated their use in version 36.0. If you are on an older
version that requires these arguments please view the appropriate documentation
version or upgrade to the latest release.
Note that for forward compatibility backend is still silently accepted by
functions that previously required it, but it is ignored and no longer
documented.
Will you upload wheels for my non-x86 non-ARM64 CPU architecture?
-----------------------------------------------------------------
Maybe! But there's some pre-requisites. For us to build wheels and upload them
to PyPI, we consider it necessary to run our tests for that architecture as a
part of our CI (i.e. for every commit). If we don't run the tests, it's hard
to have confidence that everything works -- particularly with cryptography,
which frequently employs per-architecture assembly code.
For us to add something to CI we need a provider which offers builds on that
architecture, which integrate into our workflows, has sufficient capacity, and
performs well enough not to regress the contributor experience. We don't think
this is an insurmountable bar, but it's also not one that can be cleared
lightly.
If you are interested in helping support a new CPU architecture, we encourage
you to reach out, discuss, and contribute that support. We will attempt to be
supportive, but we cannot commit to doing the work ourselves.
.. _NaCl: https://nacl.cr.yp.to/PyNaCl
.. _: https://pynacl.readthedocs.ioissue
.. _: https://github.com/pyca/cryptography/issuesmemory safety
.. _: https://alexgaynor.net/2019/aug/12/introduction-to-memory-unsafety-for-vps-of-engineering/building .zip archives for Lambda
.. _: https://docs.aws.amazon.com/lambda/latest/dg/python-package.htmlbuilding container images for Lambda
.. _: https://docs.aws.amazon.com/lambda/latest/dg/python-image.html
---
Fernet
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 ofMultiFernet
symmetric (also known as "secret key") authenticated cryptography. Fernet also
has support for implementing key rotation via :class:.
.. class:: Fernet(key)
This class provides both encryption and decryption facilities. This class
exhibits :term:thread safety.
.. doctest::
>>> from cryptography.fernet import Fernet
>>> key = Fernet.generate_key()
>>> f = Fernet(key)
>>> token = f.encrypt(b"my deep dark secret")
>>> token
b'...'
>>> f.decrypt(token)
b'my deep dark secret'
:param 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.
:type key: bytes or str
.. 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 to forge arbitrary messages that will be
authenticated and decrypted.
.. method:: encrypt(data)
Encrypts data passed. The result of this encryption is known as a
"Fernet token" and has strong privacy and authenticity guarantees.
: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:: encrypt_at_time(data, current_time)
.. versionadded:: 3.0
Encrypts data passed using explicitly passed current time. See
:meth:encrypt for the documentation of the data parameter, the
return type and the exceptions raised.
The motivation behind this method is for the client code to be able to
test token expiration. Since this method can be used in an insecure
manner one should make sure the correct time (int(time.time()))
is passed as current_time outside testing.
:param int current_time: The current time.
.. note::
Similarly to :meth:encrypt the encrypted message contains the
timestamp in plaintext, in this case the timestamp is the value
of the current_time parameter.
.. method:: decrypt(token, ttl=None)
Decrypts a Fernet token. If successfully decrypted you will receive the
original plaintext as the result, otherwise an exception will be
raised. It is safe to use this data immediately as Fernet verifies
that the data has not been tampered with prior to returning it.
:param bytes or str 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 or str.
.. method:: decrypt_at_time(token, ttl, current_time)
.. versionadded:: 3.0
Decrypts a token using explicitly passed current time. See
:meth:decrypt for the documentation of the token and ttl
parameters (ttl is required here), the return type and the exceptions
raised.
The motivation behind this method is for the client code to be able to
test token expiration. Since this method can be used in an insecure
manner one should make sure the correct time (int(time.time()))
is passed as current_time outside testing.
:param int current_time: The current time.
.. method:: extract_timestamp(token)
.. versionadded:: 2.3
Returns the timestamp for the token. The caller can then decide if
the token is about to expire and, for example, issue a new token.
:param bytes or str token: The Fernet token. This is the result of
calling :meth:encrypt.
:returns int: The Unix timestamp of the token.
:raises cryptography.fernet.InvalidToken: If the token's signature
is invalid this exception
is raised.
:raises TypeError: This exception is raised if token is not
bytes or str.
.. class:: MultiFernet(fernets)
.. versionadded:: 0.7
This class implements key rotation for Fernet. It takes a list ofFernet
:class: instances and implements the same API with the exceptionMultiFernet.rotate
of one additional method: :meth::
.. 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
b'...'
>>> f.decrypt(token)
b'Secret message!'
MultiFernet performs all encryption options using the first key in the
list provided. MultiFernet attempts to decrypt tokens with each key incryptography.fernet.InvalidToken
turn. A :class: 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.
Token rotation as offered by :meth:MultiFernet.rotate is a best practice
and manner of cryptographic hygiene designed to limit damage in the event of
an undetected event and to increase the difficulty of attacks. For example,
if an employee who had access to your company's fernet keys leaves, you'll
want to generate new fernet key, rotate all of the tokens currently deployed
using that new key, and then retire the old fernet key(s) to which the
employee had access.
.. method:: rotate(msg)
.. versionadded:: 2.2
Rotates a token by re-encrypting it under the :class:MultiFernet
instance's primary key. This preserves the timestamp that was originally
saved with the token. If a token has successfully been rotated then the
rotated token will be returned. If rotation fails this will raise an
exception.
.. 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
b'...'
>>> f.decrypt(token)
b'Secret message!'
>>> key3 = Fernet(Fernet.generate_key())
>>> f2 = MultiFernet([key3, key1, key2])
>>> rotated = f2.rotate(token)
>>> f2.decrypt(rotated)
b'Secret message!'
:param bytes or str msg: The token to re-encrypt.
:returns bytes: A secure message that cannot be read or altered without
the key. This is URL-safe base64-encoded. This is referred to as a
"Fernet token".
:raises cryptography.fernet.InvalidToken: If a token is in any
way invalid this exception is raised.
:raises TypeError: This exception is raised if the msg is not
bytes or str.
.. 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. cryptography provides several~cryptography.hazmat.primitives.kdf.argon2.Argon2id
such functions; it is generally recommended to use
:class:.
.. doctest::
>>> import base64
>>> import os
>>> from cryptography.fernet import Fernet
>>> from cryptography.hazmat.primitives import hashes
>>> from cryptography.hazmat.primitives.kdf.argon2 import Argon2id
>>> password = b"password"
>>> salt = os.urandom(16)
>>> kdf = Argon2id(
... salt=salt,
... length=32,
... iterations=1,
... lanes=4,
... memory_cost=221
... )
>>> key = base64.urlsafe_b64encode(kdf.derive(password))
>>> f = Fernet(key)
>>> token = f.encrypt(b"Secret message!")
>>> token
b'...'
>>> f.decrypt(token)
b'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 :class:~cryptography.hazmat.primitives.kdf.argon2.Argon2id parametersIRTF RFC 9106
in the above code example are based on the recommendations of _
for general applications. For memory-constrained applications, the RFC
recommends iterations=3 and memory_cost=216. See that document for
more information.
Implementation
--------------
Fernet is built on top of a number of standard cryptographic primitives.
Specifically it uses:
* :class:~cryptography.hazmat.primitives.ciphers.algorithms.AES in~cryptography.hazmat.primitives.ciphers.modes.CBC
:class: mode with a~cryptography.hazmat.primitives.padding.PKCS7
128-bit key for encryption; using
:class: padding.~cryptography.hazmat.primitives.hmac.HMAC
* :class: using~cryptography.hazmat.primitives.hashes.SHA256
:class: for authentication.
* Initialization vectors are generated using os.urandom().
For complete details consult the specification_.
Limitations
-----------
Fernet is ideal for encrypting data that easily fits in memory. As a design
feature it does not expose unauthenticated bytes. This means that the complete
message contents must be available in memory, making Fernet generally
unsuitable for very large files at this time.
.. _Fernet: https://github.com/fernet/spec/specification
.. _: https://github.com/fernet/spec/blob/master/Spec.mdIRTF RFC 9106
.. _: https://datatracker.ietf.org/doc/html/rfc9106#name-parameter-choice
---
Glossary
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 beprivate key
decrypted using a :term:. Asymmetric cryptography can alsoprivate key
be used to create signatures, which can be generated with a
:term: and verified with a :term:public key.
public key
This is one of two keys involved in :term:public-key cryptography. Itprivate key
can be used to encrypt messages for someone possessing the
corresponding :term: and to verify signatures created withprivate key
the corresponding :term:. This can be distributed
publicly, hence the name.
private key
This is one of two keys involved in :term:public-key cryptography. Itpublic key
can be used to decrypt messages which were encrypted with the
corresponding :term:, as well as to create signatures,public key
which can be verified with the corresponding :term:. 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.
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.
opaque key
An opaque key is a type of key that allows you to perform cryptographic
operations such as encryption, decryption, signing, and verification,
but does not allow access to the key itself. Typically an opaque key is
loaded from a hardware security module_ (HSM).
A-label
The ASCII compatible encoded (ACE) representation of an
internationalized (unicode) domain name. A-labels begin with the
prefix xn--. To create an A-label from a unicode domain string useidna
a library like _.
bits
A bit is binary value -- a value that has only two possible states.
Typically binary values are represented visually as 0 or 1, but
remember that their actual value is not a printable character. A byte
on modern computers is 8 bits and represents 256 possible values. In
cryptographic applications when you see something say it requires a 128
bit key, you can calculate the number of bytes by dividing by 8. 128
divided by 8 is 16, so a 128 bit key is a 16 byte key.
bytes-like
A bytes-like object contains binary data and supports the
buffer protocol_. This includes bytes, bytearray, and
memoryview objects. It is :term:unsafe to pass a mutable object
(e.g., a bytearray or other implementer of the buffer protocol)mutate it concurrently
and to _ with the operation it has been
provided for.
U-label
The presentational unicode form of an internationalized domain
name. U-labels use unicode characters outside the ASCII range and
are encoded as A-labels when stored in certificates.
unsafe
This is a term used to describe an operation where the user must
ensure that the input is correct. Failure to do so can result in
crashes, hangs, and other security issues.
thread safety
All immutable objects in cryptography are safe to use in
multi-threaded environments. This means they can be shared across
threads without requiring additional synchronization. Mutable objects,
such as hash contexts, can also be shared, but concurrent modification
may lead to exceptions or incorrect results. When working with
cryptographic operations in a multi-threaded application, ensure that
any mutable objects are used in a thread-safe manner.
.. _hardware security module: https://en.wikipedia.org/wiki/Hardware_security_moduleidna
.. _: https://pypi.org/project/idna/buffer protocol
.. _: https://docs.python.org/3/c-api/buffer.htmlmutate it concurrently
.. _: https://alexgaynor.net/2022/oct/23/buffers-on-the-edge/
---
Index
Welcome to pyca/cryptography
================================
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 withcryptography'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
b'...'
>>> f.decrypt(token)
b'A really secret message. Not for prying eyes.'
If you are interested in learning more about the field of cryptography, we
recommend Crypto 101, by Laurens Van Houtven_ and The Cryptopals Crypto
Challenges_.
Installation
------------
To install cryptography:
.. tab:: pip
.. code-block:: console
$ pip install cryptography
.. tab:: uv
.. code-block:: console
$ uv add cryptography
See :doc:Installation <installation> for more information.
.. _cryptography-layout:
Layout
------
cryptography is broadly divided into two levels. One with safe
cryptographic recipes that require little to no configuration choices. 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 thecryptography.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.
.. toctree::
:maxdepth: 2
:caption: The recipes layer
fernet
cobblestone
x509/index
.. toctree::
:maxdepth: 2
:caption: The hazardous materials layer
hazmat/primitives/index
exceptions
random-numbers
hazmat/asn1/index
hazmat/decrepit/index
.. toctree::
:maxdepth: 2
:caption: The cryptography open source project
installation
changelog
faq
development/index
openssl
security
limitations
api-stability
doing-a-release
community
glossary
.. toctree::
:maxdepth: 1
statements/index
.. note::
cryptography has not been subjected to an external audit of its code orget in touch </community>
documentation. If you're interested in discussing an audit please
:doc:.
.. _Crypto 101, by Laurens Van Houtven: https://www.crypto101.io/The Cryptopals Crypto Challenges
.. _: https://cryptopals.com/
---
Installation
Installation
============
You can install cryptography:
.. tab:: pip
.. code-block:: console
$ pip install cryptography
.. tab:: uv
.. code-block:: console
$ uv add cryptography
If this does not work please upgrade your pip first, as that is the
single most common cause of installation problems.
Supported platforms
-------------------
Currently we test cryptography on Python 3.9+ and PyPy3.11 on these
operating systems.
* x86-64 CentOS Stream 9, 10
* x86-64 Fedora (latest)
* ARM64 macOS 26 Tahoe
* x86-64 Ubuntu 22.04, 24.04, 26.04, and rolling
* ARM64, ARMv7l, and ppc64le Ubuntu rolling
* x86-64 Debian Bookworm (12.x), Trixie (13.x), and Sid (unstable)
* x86-64 and ARM64 Alpine (latest)
* 64-bit Python on 64-bit Windows Server 2025
We test compiling with clang as well as gcc and use the following
OpenSSL releases in addition to distribution provided releases from the
above supported platforms:
* OpenSSL 3.0-latest
* OpenSSL 3.4-latest
* OpenSSL 3.5-latest
* OpenSSL 3.6-latest
* OpenSSL 4.0-latest
We also test against the latest commit of BoringSSL, the latest aws-lc release,
and versions of LibreSSL that are receiving security support at the time of a
given cryptography release.
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 a binary distribution_.
Be sure to download the proper version for your architecture and Python
(VC2015 is required for 3.9 and above). Wherever you place your copy of OpenSSL
you'll need to set the OPENSSL_DIR environment variable to include the
proper location. For example:
.. code-block:: console
C:\> \path\to\vcvarsall.bat x86_amd64
C:\> set OPENSSL_DIR=C:\OpenSSL-win64
C:\> pip install cryptography
You will also need to have :ref:Rust installed and
available<installation:Rust>.
If you need to rebuild cryptography for any reason be sure to clear thewheel cache
local _.
.. _build-on-linux:
Building cryptography on Linux
------------------------------
.. note::
You should upgrade pip and attempt to install cryptography again
before following the instructions to compile it below. Most Linux
platforms will receive a binary wheel and require no compiler if you have
an updated pip!
cryptography ships manylinux wheels (as of 2.0) so all dependencies
are included. For users on pip 19.3 or above running on a manylinux2014
(or greater) compatible distribution (or pip 21.2.4 for musllinux) all
you should need to do is:
.. code-block:: console
$ pip install cryptography
If you want to compile cryptography yourself you'll need a C compiler, a
Rust compiler, headers for Python (if you're not using pypy), and headers
for the OpenSSL and libffi libraries available on your system.
On all Linux distributions you will need to have :ref:Rust installed and
available<installation:Rust>.
.. tab:: Alpine
.. warning::
The Rust available by default in Alpine < 3.21 is older than the
minimum supported version. See the :ref:Rust installation instructions
<installation:Rust> for information about installing a newer Rust.
.. code-block:: console
$ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo pkgconfig
If you get an error with openssl-dev you may have to use libressl-dev.
.. tab:: Debian/Ubuntu
.. warning::
The Rust available in Debian versions prior to Trixie are older than the
minimum supported version. See the :ref:Rust installation instructions
<installation:Rust> for information about installing a newer Rust.
.. code-block:: console
$ sudo apt-get install build-essential libssl-dev libffi-dev \
python3-dev cargo pkg-config
.. tab:: Fedora/RHEL/CentOS
.. warning::
For RHEL and CentOS you must be on version 9.6 or newer for the command
below to install a sufficiently new Rust. If your Rust is less than
1.83.0 please see the :ref:Rust installation instructions
<installation:Rust> for information about installing a newer Rust.
.. code-block:: console
$ sudo dnf install redhat-rpm-config gcc libffi-devel python3-devel \
openssl-devel cargo pkg-config
Building
~~~~~~~~
You should now be able to build and install cryptography. To avoid getting
the pre-built wheel on manylinux compatible distributions you'll need to
use --no-binary.
.. code-block:: console
$ pip install cryptography --no-binary 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,-Bsymbolic-functions -fPIC shared
Static Wheels
~~~~~~~~~~~~~
Cryptography ships statically-linked wheels for macOS, Windows, and Linux (viamanylinux and musllinux). This allows compatible environments to use
the most recent OpenSSL, regardless of what is shipped by default on those
platforms.
If you are using a platform not covered by our wheels, 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.virtualenv
Please also make sure you have _ installed: this should be
available from your system package manager.
Then, paste the following into a shell script. You'll need to populate theOPENSSL_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 3.0.9, use OPENSSL_VERSION="3.0.9".
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 -LO https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
tar xzvf openssl-${OPENSSL_VERSION}.tar.gz
cd openssl-${OPENSSL_VERSION}
./config no-shared no-ssl2 no-ssl3 -fPIC --prefix=${CWD}/openssl
make && make install
cd ..
OPENSSL_DIR="${CWD}/openssl" pip wheel --no-cache-dir --no-binary cryptography cryptography
Building cryptography on macOS
------------------------------
.. note::
If installation gives a fatal error: 'openssl/aes.h' file not foundFAQ </faq>
see the :doc: for information about how to fix this issue.
The wheel package on macOS 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 macOS version,
cryptography requires the presence of a C compiler, development headers, and
the proper libraries. On macOS much of this is provided by Apple's Xcode
development tools. To install the Xcode command line tools (on macOS 10.10+)
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 will also need to have :ref:Rust installed and
available<installation:Rust>, which can be obtained from Homebrew_,MacPorts_, or directly from the Rust website.
Finally you need OpenSSL, which you can obtain from Homebrew_ or MacPorts_.
Cryptography does not support the OpenSSL/LibreSSL libraries Apple ships
in its base operating system.
To build cryptography and dynamically link it:
Homebrew_
.. code-block:: console
$ brew install openssl@3 rust
$ pip install --no-binary cryptography cryptography
MacPorts_:
.. code-block:: console
$ sudo port install openssl rust
$ env OPENSSL_DIR="-L/opt/local" pip install --no-binary cryptography cryptography
You can also build cryptography statically:
Homebrew_
.. code-block:: console
$ brew install openssl@3 rust
$ env OPENSSL_STATIC=1 pip install --no-binary cryptography cryptography
MacPorts_:
.. code-block:: console
$ sudo port install openssl rust
$ env OPENSSL_STATIC=1 OPENSSL_DIR="/opt/local" pip install --no-binary cryptography cryptography
If you need to rebuild cryptography for any reason be sure to clear thewheel cache
local _.
Building with BoringSSL, LibreSSL, or AWS-LC
--------------------------------------------
To build against BoringSSL, LibreSSL, or AWS-LC instead of OpenSSL, you can set theOPENSSL_DIR environment variable to point to your BoringSSL, LibreSSL, or AWS-LC
installation directory.
Rust
----
.. note::
If you are using Linux, then you should upgrade pip (in
a virtual environment!) and attempt to install cryptography again before
trying to install the Rust toolchain. On most Linux distributions, the latest
version of pip will be able to install a binary wheel, so you won't need
a Rust toolchain.
Building cryptography requires having a working Rust toolchain. The current
minimum supported Rust version is 1.83.0. This is newer than the Rust some
package managers ship, so users may need to install with the
instructions below.
Instructions for installing Rust can be found on the Rust Project's website_.
We recommend installing Rust with rustup (as documented by the Rust
Project) in order to ensure you have a recent version.
Rust is only required when building cryptography, meaning that you may
install it for the duration of your pip install command and then remove it
from a system. A Rust toolchain is not required to use cryptography. In
deployments such as docker, you may use a multi-stage Dockerfile where
you install Rust during the build phase but do not install it in the runtime
image. This is the same as the C compiler toolchain which is also required to
build cryptography, but not afterwards.
.. _Homebrew: https://brew.shMacPorts
.. _: https://www.macports.orga binary distribution
.. _: https://wiki.openssl.org/index.php/Binarieswheel cache
.. _virtualenv: https://virtualenv.pypa.io/en/latest/
.. _openssl.org: https://www.openssl.org/source/
.. _: https://pip.pypa.io/en/stable/cli/pip_install/#cachingthe Rust Project's website
.. _: https://www.rust-lang.org/tools/install
---
Limitations
Known security limitations
==========================
Secure memory wiping
--------------------
Memory wiping_ is used to protect secret data or key material from attackers
with access to deallocated memory. This is a defense-in-depth measure against
vulnerabilities that leak application memory.
Many cryptography APIs which accept bytes also accept types which
implement the buffer interface. Thus, users wishing to do so can passmemoryview or another mutable type to cryptography APIs, and overwrite
the contents once the data is no longer needed.
However, cryptography does not clear memory by default, as there is no way
to clear immutable structures such as bytes. As a result, cryptography,CERT secure coding guidelines
like almost all software in Python is potentially vulnerable to this attack. The_ 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.
RSA PKCS1 v1.5 constant time decryption
---------------------------------------
RSA decryption has several different modes, one of which is PKCS1 v1.5. When
used in online contexts, a secure protocol implementation requires that
peers not be able to tell whether RSA PKCS1 v1.5 decryption failed or
succeeded, even by timing variability.
cryptography does not provide an API that makes this possible, due to the
fact that RSA decryption raises an exception on failure, which takes a
different amount of time than returning a value in the success case.
In OpenSSL 3.2.0 and newer, this is automatically mitigated by OpenSSL (by
returning a random value and never raising an exception). If you are using
cryptography with an older version of OpenSSL, such attacks are still possible.
Regardless of OpenSSL version, we recommend not implementing or using online
protocols that use RSA PKCS1 v1.5 decryption, as such protocols generally have
poor security properties due to their lack of forward security.
.. _Memory wiping: https://devblogs.microsoft.com/oldnewthing/?p=4223CERT secure coding guidelines
.. _: https://wiki.sei.cmu.edu/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources
---
Openssl
Use of OpenSSL
==============
cryptography depends on the OpenSSL_ C library for all cryptographic
operation. OpenSSL is the de facto standard for cryptographic libraries and
provides high performance along with various certifications that may be
relevant to developers.
A list of supported versions can be found in our :doc:/installation
documentation.
In general the backend should be considered an internal implementation detail
of the project, but there are some public methods available for debugging
purposes.
.. data:: cryptography.hazmat.backends.openssl.backend
.. method:: openssl_version_text()
:return text: The friendly string name of the loaded OpenSSL library.
This is not necessarily the same version as it was compiled against.
.. method:: openssl_version_number()
.. versionadded:: 1.8
:return int: The integer version of the loaded OpenSSL library. This is
defined in opensslv.h as OPENSSL_VERSION_NUMBER and is
typically shown in hexadecimal (e.g. 0x1010003f). This is
not necessarily the same version as it was compiled against.
.. _legacy-provider:
Legacy provider in OpenSSL 3.x
------------------------------
.. versionadded:: 39.0.0
Users can set CRYPTOGRAPHY_OPENSSL_NO_LEGACY environment variable to
disable the legacy provider in OpenSSL 3.x. This will disable legacy
cryptographic algorithms, including Blowfish, CAST5, SEED,ARC4, and RC2 (which is used by some encrypted serialization formats).
Additionally, the CRYPTOGRAPHY_BUILD_OPENSSL_NO_LEGACY environment variable
can be set during the build process to prevent the library from ever attempting
to load the legacy provider.
If loading the legacy provider is not disabled and the legacy provider fails to
load, a warning is emitted.
.. _OpenSSL: https://www.openssl.org/
---
Random Numbers
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 notrandom
want to use the standard :mod: 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)
If you need your random number as an big integer, you can useint.from_bytes to convert the result of os.urandom:
.. code-block:: pycon
>>> serial = int.from_bytes(os.urandom(16), byteorder="big")
In addition, the Python standard library_ includes the secrets module,
which can be used for generating cryptographically secure random numbers, with
specific helpers for text-based formats.
.. _always use your operating system's provided random number generator: https://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/Python standard library
.. _: https://docs.python.org/3/library/secrets.html
---
Security
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.
Known vulnerabilities
---------------------
A list of all known vulnerabilities in cryptography can be found onosv.dev_, as well as other ecosystem vulnerability databases. They canpip-audit
automatically be scanned for using tools such as _ or osv-scan_.
Infrastructure
--------------
In addition to cryptography's code, we're also concerned with the security
of the infrastructure we run (primarily cryptography.io). If you discover
a security vulnerability in our infrastructure, we ask you to report it using
the same procedure.
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.
* An uncaught PanicException from pyo3. In general, these
represent bugs that should be filed as regular issues, but they are not
security vulnerabilities because they do not cause memory unsafety or
undefined behavior -- the process remains in a well-defined state.
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 public 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,security advisory page
please report it via our _.
Once you've submitted an issue, you should receive an acknowledgment within 48
hours, and depending on the action to be taken, you may receive further
follow-up.
Supported Versions
------------------
At any given time, we will provide security support for the main_ branch
as well as the most recent release.
New releases for OpenSSL updates
--------------------------------
As of versions 0.5, 1.0.1, and 2.0.0, cryptography statically links OpenSSL
in binary distributions for Windows, macOS, and Linux respectively, 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
------------------
When we become aware of a security bug in cryptography, we will endeavor to
fix it and issue a release as quickly as possible. We will generally issue a new
release for any security issue.
The steps for issuing a security release are described in our
:doc:/doing-a-release documentation.
.. _osv.dev: https://osv.dev/list?ecosystem=PyPI&q=cryptographypip-audit
.. _: https://pypi.org/project/pip-audit/osv-scan
.. _: https://google.github.io/osv-scanner/security advisory page
.. _: https://github.com/pyca/cryptography/security/advisories/newmain`: https://github.com/pyca/cryptography
.. _
---