The modern, audited Python cryptography library (cryptography) providing symmetric/asymmetric encryption, hashing, key derivation, and X.509 handling behind a safe high-level API.
The cryptography package exposes a "recipes" layer (like Fernet) for foolproof symmetric encryption plus a "hazmat" layer for lower-level primitives (AES, RSA, ECDSA, HMAC, PBKDF2). It is the recommended library for any real crypto in Python — replacing home-grown or deprecated PyCrypto code. Security professionals use it to protect tooling data, hash and derive keys, and analyze certificates during assessments.
pip install cryptographyfrom cryptography.fernet import Fernet
key = Fernet.generate_key() # store this securely - losing it loses the data
cipher = Fernet(key)
token = cipher.encrypt(b"lab notes - not real data")
print(token[:24], "...")
print(cipher.decrypt(token))Fernet is the recipes layer: authenticated symmetric encryption with sensible defaults and no options to get wrong. Prefer it over assembling primitives yourself.
| API | Purpose |
|---|---|
fernet.Fernet.generate_key() |
Generate a symmetric key |
Fernet(key).encrypt/decrypt(data) |
Authenticated symmetric encryption |
fernet.MultiFernet([...]) |
Key rotation |
hazmat.primitives.hashes.SHA256() |
Hash algorithm objects |
hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC |
Derive a key from a password |
hazmat.primitives.asymmetric.rsa/ec |
Key generation and signing |
hazmat.primitives.serialization |
Load and write PEM/DER keys |
x509.load_pem_x509_certificate(data) |
Parse a certificate |
cert.subject, cert.issuer, cert.not_valid_after_utc |
Certificate fields |
x509.CertificateBuilder() |
Build a certificate (lab CAs, self-signed) |
Note
Anything under hazmat is "hazardous materials" — the library's own name for its low-level primitives. Reach for it only when the recipes layer genuinely cannot do the job. Note also that some certificate properties gained _utc variants in recent releases; check the version you have installed.
Authenticated symmetric encryption with Fernet (safe default):
from cryptography.fernet import Fernet
key = Fernet.generate_key() # store this securely
f = Fernet(key)
token = f.encrypt(b"loot: internal-admin:S3cret!")
print("ciphertext:", token[:24], b"...")
print("decrypted :", f.decrypt(token).decode())ciphertext: b'gAAAAABl...' b'...'
decrypted : loot: internal-admin:S3cret!
Password-based key derivation with PBKDF2 (never store raw passwords):
import os
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
salt = os.urandom(16)
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=480000)
derived = kdf.derive(b"correct horse battery staple")
print("salt:", salt.hex())
print("key :", derived.hex()[:32], "...")salt: 9f3c1a...e2
key : 4b7d9f0c2a18e5... ...
Parse an X.509 certificate and read its fields (TLS assessment):
from cryptography import x509
from cryptography.hazmat.primitives import hashes
with open("server.crt", "rb") as fh:
cert = x509.load_pem_x509_certificate(fh.read())
print("subject :", cert.subject.rfc4514_string())
print("issuer :", cert.issuer.rfc4514_string())
print("expires :", cert.not_valid_after_utc)
print("sha256 :", cert.fingerprint(hashes.SHA256()).hex()[:32], "...")subject : CN=example.com
issuer : CN=Example CA
expires : 2026-11-01 00:00:00+00:00
sha256 : 3a1f8c9b2e... ...
- Encryption / decryption — protect credentials, loot, and config in your own tooling with Fernet or AES-GCM.
- Password hashing & KDFs — derive keys and store password verifiers with PBKDF2/scrypt instead of raw hashes.
- Integrity & signing — compute HMACs and verify ECDSA/RSA signatures for tamper detection.
- Certificate analysis — parse X.509 certs to check expiry, weak keys, and misissued SANs during TLS reviews.
- Secure random generation — produce cryptographically strong tokens and salts (
os.urandom,secrets).
Important
Do not roll your own crypto or use deprecated ciphers (MD5, DES, ECB). Prefer the high-level Fernet recipe unless you have a specific reason to touch hazmat.
- Building your own construction from
hazmatprimitives whenFernetwould do — this is how nonce reuse and unauthenticated encryption creep in. - Encrypting without authentication. Raw AES-CBC has no integrity protection and is vulnerable to padding-oracle attacks; use Fernet or AES-GCM.
- Reusing a nonce or IV with the same key — catastrophic for GCM and CTR modes.
- Hardcoding keys in source or committing them to a repository.
- Deriving a key from a password without a KDF — use
PBKDF2HMACorscryptwith a random salt and a high iteration count. - Comparing MACs with
==rather than a constant-time comparison. - Confusing encryption with hashing — encryption is reversible by design, hashing is not.
- Installing
cryptoorpycrypto— the maintained package iscryptography;pycryptois unmaintained and has known vulnerabilities.
[!warning] Do not design your own cryptography Use the recipes layer. Novel constructions built from primitives are where real systems break.
- Key management is the hard part. Generating a key is trivial; storing, rotating, and revoking it safely is the actual problem. Use a secrets manager, a KMS, or the OS keyring — never a file beside the ciphertext, and never source control.
- Always use authenticated encryption. Without it, an attacker can modify ciphertext undetected. Fernet and AES-GCM authenticate; CBC alone does not.
- Passwords need a slow KDF, not a hash.
PBKDF2HMACandscryptare here for that; see also [[Hashlib-Module|hashlib]]. - Randomness must be cryptographic. Use the library's generators or [[Secrets-Module|
secrets]], neverrandom. - Keep the library current.
cryptographyships security fixes and bundles OpenSSL; an old version is a real exposure. - Certificate validation is not optional. Parsing a certificate is not the same as verifying its chain, hostname, and validity dates.
- Never use real production keys or data in course exercises.
- Use Fernet or AES-GCM for authenticated encryption; avoid unauthenticated modes.
- Use a unique random salt/nonce per message and never reuse a nonce with the same key.
- Pick a high PBKDF2 iteration count (hundreds of thousands) or prefer
scrypt/argon2for passwords. - Keep keys out of source control — load them from a secrets manager or environment.
- Track library updates; crypto bugs get patched and algorithms get deprecated.
- [[pyOpenSSL]] — OpenSSL-backed TLS and certificate operations
- [[requests]] — consume the TLS endpoints whose certs you analyze here
- [[Readme|Python for Security Professionals]] — course home