Install & Compatibility
Where this runs
tested against v50.0.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.029s · 34.9MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 3.3s · import 0.026s · 35MB
33MB installed
● package 33MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
Fernet
✓ from cryptography.fernet import Fernet
High-level authenticated symmetric encryption; preferred over raw hazmat APIs for most use cases
Cipher, algorithms, modes
✓ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
✗ from cryptography.hazmat.backends import default_backend; Cipher(..., backend=default_backend())
The `backend` parameter was removed in 3.x; passing `default_backend()` to Cipher() raises TypeError on modern versions
AESGCM (AEAD shortcut)
✓ from cryptography.hazmat.primitives.ciphers.aead import AESGCM
Simpler authenticated encryption API; handles IV/tag automatically compared to the Cipher+GCM mode pattern
rsa.generate_private_key
✓ from cryptography.hazmat.primitives.asymmetric import rsa
✗ rsa.generate_private_key(65537, 2048, backend=default_backend())
The `backend` keyword argument was removed; call without it: rsa.generate_private_key(public_exponent=65537, key_size=2048)
padding (asymmetric)
✓ from cryptography.hazmat.primitives.asymmetric import padding
Use padding.OAEP for RSA encryption and padding.PSS for RSA signatures; PKCS1v15 is legacy only
hashes
✓ from cryptography.hazmat.primitives import hashes
Used with asymmetric sign/verify and HMAC; e.g. hashes.SHA256()
serialization
✓ from cryptography.hazmat.primitives import serialization
For loading/serializing PEM/DER keys; use serialization.load_pem_private_key(), not legacy OpenSSL backend helpers
x509
✓ from cryptography import x509
X.509 certificate parsing and building; use x509.load_pem_x509_certificate()
Fernet high-level symmetric encryption (recommended starting point) plus AES-GCM via hazmat for authenticated low-level encryption.
# --- High-level: Fernet (recommended for most use cases) ---
from cryptography.fernet import Fernet
key = Fernet.generate_key() # Must be stored securely; bytes
f = Fernet(key)
token = f.encrypt(b"secret message") # Returns URL-safe base64 token
plaintext = f.decrypt(token) # Raises InvalidToken if tampered
assert plaintext == b"secret message"
# --- Low-level: AES-GCM via hazmat (authenticated encryption) ---
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
aes_key = AESGCM.generate_key(bit_length=256) # 32 random bytes
aesgcm = AESGCM(aes_key)
nonce = os.urandom(12) # 96-bit nonce; NEVER reuse with same key
ciphertext = aesgcm.encrypt(nonce, b"secret data", b"optional AAD")
decrypted = aesgcm.decrypt(nonce, ciphertext, b"optional AAD")
assert decrypted == b"secret data"
# --- RSA key generation & sign/verify ---
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
message = b"message to sign"
signature = private_key.sign(
message,
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
hashes.SHA256()
)
public_key.verify(
signature, message,
padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH),
hashes.SHA256()
) # Raises InvalidSignature if verification fails
print("All operations succeeded")
Debug
Known issues
breakingThe `backend` parameter was removed from all hazmat constructors (Cipher, rsa.generate_private_key, ec.generate_private_key, etc.). Passing `backend=default_backend()` now raises TypeError.fixRemove all `backend=` keyword arguments. Modern API: `rsa.generate_private_key(public_exponent=65537, key_size=2048)` with no backend argument.
affects: <3.x to >=3.x migration
breaking`signer()` and `verifier()` methods on public/private key objects were removed in 44.0.0 after being deprecated since 2.0.fixReplace `key.signer(...)` with `key.sign(...)` and `key.verifier(...)` with `key.verify(...)` directly.
affects: <44.0.0 code running on >=44.0.0
breakingOpenSSL 1.1.x support was removed; OpenSSL 3.0.0 or later is now required when building from source. LibreSSL < 4.1 also dropped.fixUpgrade system OpenSSL to 3.0+, or use pre-built wheels (which bundle a recent OpenSSL statically).
affects: >=47.0.0 (upcoming dev), applies to source builds
breakingLoading keys with unsupported algorithms or explicit curve encodings now raises `UnsupportedAlgorithm` instead of `ValueError`.fixCatch `cryptography.exceptions.UnsupportedAlgorithm` instead of (or in addition to) `ValueError` when loading keys.
affects: >=46.0.0
deprecatedCFB, OFB, and CFB8 modes have been moved to 'Decrepit cryptography' and deprecated in `cryptography.hazmat.primitives.ciphers.modes`. They will be removed in 49.0.0. Camellia cipher is similarly deprecated.fixMigrate to AES-GCM or ChaCha20-Poly1305 (AEAD modes) for new code. Import from `cryptography.hazmat.decrepit` if you must keep using them temporarily.
affects: >=46.0.0, removed in 49.0.0
gotchaECB mode (`modes.ECB`) is available but insecure—it encrypts identical plaintext blocks to identical ciphertext blocks, leaking data patterns. The library does not prevent its use.fixAlways prefer authenticated encryption: use `AESGCM`, `ChaCha20Poly1305`, or `Cipher` with `modes.GCM`. Never use ECB in production.
affects: all
gotchaWhen building from source (not from a wheel), a Rust toolchain (cargo) is required. On Alpine Linux < 3.21 and older Debian/Ubuntu, the default Rust is too old.fixInstall via `pip install cryptography` with an up-to-date pip to receive a pre-built binary wheel. If building from source, install Rust via rustup and ensure version >= 1.83.0.
affects: all source builds
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'cryptography'
The 'cryptography' package is not installed in the Python environment being used, or the Python interpreter cannot find the installed library.
fixEnsure the library is installed for your active Python environment. If using a virtual environment, activate it first. For most users, run: `pip install cryptography` or `python -m pip install cryptography`.
ERROR: Could not build wheels for cryptography which use PEP 517 and cannot be installed directly OR Can not find Rust compiler.
Installation of `cryptography` failed because it needs to be built from source, and the necessary build tools (like a C compiler, OpenSSL development headers, or the Rust compiler) are missing on the system, or `pip` is outdated and cannot find pre-compiled wheels.
fixFirst, upgrade `pip` and `setuptools`: `python -m pip install --upgrade pip setuptools`. If the error persists:
- On Linux, install development headers (e.g., `sudo apt-get install build-essential libssl-dev libffi-dev` on Debian/Ubuntu, or `sudo yum install redhat-rpm-config gcc libffi-devel python3-devel openssl-devel` on RHEL/CentOS).
- On macOS, install Xcode Command Line Tools (`xcode-select --install`) and OpenSSL (e.g., `brew install openssl`).
- On Windows, install Microsoft Visual C++ Build Tools.
- If specifically 'Can not find Rust compiler' appears, install Rust: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh`.
ValueError: Encryption/decryption failed.
This error often occurs with asymmetric encryption (e.g., RSA) when attempting to encrypt data larger than the maximum plaintext size allowed by the key and padding scheme. RSA encryption has strict limits on the size of data it can encrypt directly.
fixFor large data, use hybrid encryption: encrypt the data with a symmetric cipher (e.g., AES/Fernet), and then encrypt only the much smaller symmetric key with RSA.
TypeError: data must be bytes
A cryptographic function that expects a `bytes`-like object (e.g., for plaintext, ciphertext, or keys) received a Python string (`str`) instead.
fixConvert the string data to bytes using the `.encode()` method with an appropriate encoding (e.g., UTF-8). For example, `b'your_string'` or `'your_string'.encode('utf-8')`. Upgrade
Version history
50.0.1latest on PyPI · released Aug 25, 2026
Audit
Dependencies
cffirequiredC FFI bindings layer; pulled in automatically on CPython when installing from source
openssloptionalSystem OpenSSL required only when building from source; pre-built wheels bundle OpenSSL statically
rust / cargooptionalRequired to compile from source (not from wheel); pre-built wheels ship Rust-compiled extensions