Cryptography - work with encryption

онлайн тренажер по питону
Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Cryptography in Python: A Complete Guide to Secure Encryption and Cryptography

In today’s digital world, cryptographic security has become an essential part of any serious project. Whether it’s protecting user data, securely transmitting information between services, or storing confidential documents — all of this requires the use of robust cryptographic methods.

The Cryptography library for Python is a powerful and versatile tool that combines ease of use with professional‑grade security. It provides both high‑level solutions for everyday tasks and low‑level access to cryptographic primitives for specialized cases.

What Is the Cryptography Library

Cryptography is a modern cryptographic library for Python that offers recipes and primitives for Python developers. It was created by the PyCA (Python Cryptographic Authority) team and quickly became the de‑facto standard for cryptographic operations in the Python ecosystem.

Key principles of the library:

  • Security by default
  • Ease of use
  • Performance thanks to C bindings
  • Standards compliance
  • Active community support

Installation and Setup

Install the library via the pip package manager:

pip install cryptography

Additional features may require extra dependencies:

# SSH support
pip install cryptography[ssh]

# Full installation with all extras
pip install cryptography[all]

Cryptography Library Architecture

Two‑Level Architecture

The library follows a two‑level architecture:

High‑Level Recipes

  • Ready‑made solutions for typical tasks
  • Secure defaults
  • Minimal code for maximum result
  • Examples: Fernet, X.509 certificate builder

Low‑Level Primitives

  • Full control over cryptographic operations
  • Flexibility in parameter configuration
  • Access to specialized algorithms
  • Examples: AES in various modes, elliptic curves

Architecture Benefits

  • Security: high‑level API prevents common mistakes
  • Flexibility: low‑level access for special cases
  • Performance: uses OpenSSL and custom C bindings
  • Compatibility: supports standard formats and protocols

Symmetric Encryption with Fernet

What Is Fernet

Fernet is a high‑level symmetric encryption algorithm that provides:

  • AES‑128 encryption in CBC mode
  • HMAC‑SHA256 for authenticity
  • Timestamps for TTL control
  • Base64URL‑encoded output

Core Fernet Operations

Key generation:

from cryptography.fernet import Fernet

# Generate a new key
key = Fernet.generate_key()
print(f"Key: {key}")

Saving the key to a file:

# Securely save the key
with open("secret.key", "wb") as key_file:
    key_file.write(key)

# Load the key from a file
with open("secret.key", "rb") as key_file:
    loaded_key = key_file.read()

Encrypting data:

# Create a Fernet cipher object
cipher_suite = Fernet(key)

# Encrypt a string
message = "This is confidential information"
encrypted_message = cipher_suite.encrypt(message.encode())

print(f"Encrypted message: {encrypted_message}")

Decrypting data:

# Decrypt
decrypted_message = cipher_suite.decrypt(encrypted_message)
print(f"Decrypted message: {decrypted_message.decode()}")

Working with TTL (Time To Live)

import time

# Encrypt with a timestamp
encrypted_with_time = cipher_suite.encrypt(b"Temporary message")

# Decrypt with a 30‑second TTL check
try:
    decrypted = cipher_suite.decrypt(encrypted_with_time, ttl=30)
    print("Message is still valid")
except:
    print("Message has expired")

Asymmetric Encryption

RSA Encryption

RSA remains one of the most popular asymmetric encryption algorithms.

Key‑pair generation:

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

# Generate a private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)

# Derive the public key
public_key = private_key.public_key()

Key serialization:

# Serialize private key
private_pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.NoEncryption()
)

# Serialize public key
public_pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
)

Encryption and decryption:

from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

# Encrypt
message = b"Secret message"
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Decrypt
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

Elliptic Curve Cryptography (ECC)

ECC offers comparable security to RSA with smaller key sizes.

from cryptography.hazmat.primitives.asymmetric import ec

# Generate a key on the SECP256R1 curve
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()

# Sign
signature = private_key.sign(
    b"Message to sign",
    ec.ECDSA(hashes.SHA256())
)

# Verify
try:
    public_key.verify(signature, b"Message to sign", ec.ECDSA(hashes.SHA256()))
    print("Signature is valid")
except:
    print("Signature is invalid")

Hashing and MAC

Simple Hashing

from cryptography.hazmat.primitives import hashes

# Create a hash object
digest = hashes.Hash(hashes.SHA256())

# Add data
digest.update(b"First part of data")
digest.update(b"Second part of data")

# Finalize
hash_value = digest.finalize()
print(f"SHA‑256 hash: {hash_value.hex()}")

HMAC (Hash‑Based Message Authentication Code)

from cryptography.hazmat.primitives import hmac

# Create HMAC
secret_key = b"secret_key"
h = hmac.HMAC(secret_key, hashes.SHA256())
h.update(b"Message for authentication")

# Get MAC
mac = h.finalize()
print(f"HMAC: {mac.hex()}")

# Verify MAC
h2 = hmac.HMAC(secret_key, hashes.SHA256())
h2.update(b"Message for authentication")
h2.verify(mac)  # No exception means MAC is correct

Digital Signatures

RSA Signatures

# Create a signature
signature = private_key.sign(
    b"Document to sign",
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Verify the signature
try:
    public_key.verify(
        signature,
        b"Document to sign",
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("Signature is valid")
except:
    print("Signature is invalid")

Ed25519 Signatures

Ed25519 is a modern digital signature algorithm that offers high performance.

from cryptography.hazmat.primitives.asymmetric import ed25519

# Generate a key
private_key = ed25519.Ed25519PrivateKey.generate()
public_key = private_key.public_key()

# Sign
signature = private_key.sign(b"Message")

# Verify
try:
    public_key.verify(signature, b"Message")
    print("Ed25519 signature is valid")
except:
    print("Ed25519 signature is invalid")

Key Derivation Functions (KDF)

PBKDF2

PBKDF2 converts passwords into cryptographic keys.

from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import os

# Generate a salt
salt = os.urandom(16)

# Configure KDF
kdf = PBKDF2HMAC(
    algorithm=hashes.SHA256(),
    length=32,
    salt=salt,
    iterations=100_000,
)

# Derive a key from a password
password = b"my_super_password"
key = kdf.derive(password)

# Verify password
kdf2 = PBKDF2HMAC(
    algorithm=hashes.SHA256(),
    length=32,
    salt=salt,
    iterations=100_000,
)

try:
    kdf2.verify(password, key)
    print("Password is correct")
except:
    print("Password is incorrect")

Scrypt

Scrypt provides resistance against attacks using specialized hardware.

from cryptography.hazmat.primitives.kdf.scrypt import Scrypt

salt = os.urandom(16)
kdf = Scrypt(
    algorithm=hashes.SHA256(),
    length=32,
    salt=salt,
    n=2**14,
    r=8,
    p=1,
)

key = kdf.derive(b"password")

Low‑Level Symmetric Encryption

AES in Various Modes

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
import os

# AES in CBC mode
key = os.urandom(32)  # 256‑bit key
iv = os.urandom(16)   # 128‑bit IV

cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
encryptor = cipher.encryptor()
decryptor = cipher.decryptor()

# Apply PKCS7 padding
padder = padding.PKCS7(128).padder()
padded_data = padder.update(b"Long message to encrypt")
padded_data += padder.finalize()

# Encrypt
ciphertext = encryptor.update(padded_data) + encryptor.finalize()

# Decrypt
plaintext_padded = decryptor.update(ciphertext) + decryptor.finalize()

# Remove padding
unpadder = padding.PKCS7(128).unpadder()
plaintext = unpadder.update(plaintext_padded) + unpadder.finalize()

ChaCha20

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms

key = os.urandom(32)
nonce = os.urandom(16)

cipher = Cipher(algorithms.ChaCha20(key, nonce), mode=None)
encryptor = cipher.encryptor()

ciphertext = encryptor.update(b"Message for ChaCha20") + encryptor.finalize()

Working with X.509 Certificates

Creating a Self‑Signed Certificate

from cryptography import x509
from cryptography.x509.oid import NameOID
import datetime

# Build certificate subject/issuer
subject = issuer = x509.Name([
    x509.NameAttribute(NameOID.COUNTRY_NAME, u"RU"),
    x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Moscow"),
    x509.NameAttribute(NameOID.LOCALITY_NAME, u"Moscow"),
    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(
    public_key
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.datetime.utcnow()
).not_valid_after(
    datetime.datetime.utcnow() + datetime.timedelta(days=365)
).sign(private_key, hashes.SHA256())

# Save certificate
with open("certificate.pem", "wb") as f:
    f.write(cert.public_bytes(serialization.Encoding.PEM))

Comprehensive Method and Function Reference for Cryptography

High‑Level Recipes

Module/Class Method/Function Description
Fernet generate_key() Generate a symmetric key for Fernet
  encrypt(data) Encrypt data with authenticity protection
  decrypt(token, ttl=None) Decrypt with optional TTL verification
MultiFernet encrypt(data) Encrypt with key rotation
  decrypt(token, ttl=None) Decrypt supporting multiple keys
  rotate(data) Re‑encrypt data with a new key

Asymmetric Cryptography

Module Function/Method Description
rsa generate_private_key(public_exponent, key_size) Generate an RSA key pair
  encrypt(message, padding) RSA encryption
  decrypt(ciphertext, padding) RSA decryption
  sign(message, padding, algorithm) RSA signing
  verify(signature, message, padding, algorithm) RSA signature verification
ec generate_private_key(curve) Generate an elliptic‑curve key
  sign(data, signature_algorithm) ECSDA signing
  verify(signature, data, signature_algorithm) ECSDA verification
ed25519 Ed25519PrivateKey.generate() Generate an Ed25519 key
  sign(data) Ed25519 signing
  verify(signature, data) Ed25519 verification
x25519 X25519PrivateKey.generate() Generate a key for key exchange
  exchange(peer_public_key) Perform key exchange

Hashing and MAC

Module Function/Method Description
hashes Hash(algorithm) Create a hash object
  update(data) Add data to the hash
  finalize() Obtain the final hash
hmac HMAC(key, algorithm) Create an HMAC object
  update(data) Add data to the HMAC
  finalize() Obtain the MAC
  verify(signature) Verify the MAC

Key Derivation Functions

Class Method Description
PBKDF2HMAC derive(key_material) Derive a key from a password
  verify(key_material, expected_key) Validate that a password matches a derived key
Scrypt derive(key_material) Scrypt key derivation
  verify(key_material, expected_key) Validate a Scrypt‑derived key
HKDF derive(key_material) HKDF key expansion
  expand(key_material, length, info) HKDF expansion with additional context

Symmetric Ciphers

Class Parameters Description
AES key (128/192/256 bits) AES algorithm
ChaCha20 key (256 bits), nonce (128 bits) ChaCha20 stream cipher
TripleDES key (192 bits) Legacy 3DES

Cipher Modes

Mode Parameters Description
CBC initialization_vector Cipher Block Chaining
GCM initialization_vector, tag Galois/Counter Mode with authentication
CTR nonce Counter mode
ECB - Electronic Codebook (not recommended)
OFB initialization_vector Output Feedback
CFB initialization_vector Cipher Feedback

Serialization

Module Function Description
serialization load_pem_private_key(data, password) Load a private key from PEM
  load_pem_public_key(data) Load a public key from PEM
  load_der_private_key(data, password) Load a private key from DER
  load_der_public_key(data) Load a public key from DER

X.509 Certificates

Class Method Description
CertificateBuilder subject_name(name) Set certificate subject
  issuer_name(name) Set certificate issuer
  public_key(key) Set the public key
  serial_number(number) Set the serial number
  not_valid_before(time) Set the start of the validity period
  not_valid_after(time) Set the end of the validity period
  sign(private_key, algorithm) Sign the certificate

Practical Usage Examples

Creating a Secure Password Vault

import json
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import os

class PasswordManager:
    def __init__(self, master_password: str):
        self.salt = os.urandom(16)
        self.key = self._derive_key(master_password, self.salt)
        self.cipher = Fernet(self.key)
        self.passwords = {}
    
    def _derive_key(self, password: str, salt: bytes) -> bytes:
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            iterations=100_000,
        )
        key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
        return key
    
    def add_password(self, service: str, password: str):
        encrypted_password = self.cipher.encrypt(password.encode())
        self.passwords[service] = base64.urlsafe_b64encode(encrypted_password).decode()
    
    def get_password(self, service: str) -> str:
        if service not in self.passwords:
            raise ValueError("Service not found")
        
        encrypted_password = base64.urlsafe_b64decode(self.passwords[service])
        decrypted_password = self.cipher.decrypt(encrypted_password)
        return decrypted_password.decode()

# Usage
pm = PasswordManager("my_master_password")
pm.add_password("gmail", "super_secret_password")
print(pm.get_password("gmail"))

Secure File Transfer

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.fernet import Fernet

def secure_file_transfer():
    # Recipient generates a key pair
    recipient_private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
    )
    recipient_public_key = recipient_private_key.public_key()
    
    # Sender
    # 1. Generate a symmetric key for the file
    file_key = Fernet.generate_key()
    file_cipher = Fernet(file_key)
    
    # 2. Encrypt the file
    file_content = b"Contents of a confidential file"
    encrypted_file = file_cipher.encrypt(file_content)
    
    # 3. Encrypt the file key with the recipient's public key
    encrypted_key = recipient_public_key.encrypt(
        file_key,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    
    # Recipient
    # 1. Decrypt the file key
    decrypted_file_key = recipient_private_key.decrypt(
        encrypted_key,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None
        )
    )
    
    # 2. Decrypt the file
    file_cipher_recipient = Fernet(decrypted_file_key)
    decrypted_file = file_cipher_recipient.decrypt(encrypted_file)
    
    print(f"Original file: {file_content}")
    print(f"Decrypted file: {decrypted_file}")

secure_file_transfer()

Security and Best Practices

Fundamental Security Principles

  1. Never use hard‑coded keys — always generate random keys
  2. Use a salt when hashing passwords — prevents rainbow‑table attacks
  3. Validate data authenticity — use HMAC or authenticated encryption
  4. Limit token lifetimes — use TTL with Fernet
  5. Never log secret material — keys and passwords must not appear in logs

Common Mistakes

Using eval() on decrypted data

# WRONG!
decrypted_data = cipher.decrypt(token)
result = eval(decrypted_data)  # Dangerous!

# CORRECT!
import json
decrypted_data = cipher.decrypt(token)
result = json.loads(decrypted_data)  # Safe

Storing keys alongside data

# WRONG!
key = Fernet.generate_key()
encrypted_data = cipher.encrypt(data)
# Storing key and data together

# CORRECT!
# Keys should be stored separately from data
# Use environment variables, Key Management Services, etc.

Performance Recommendations

  1. Reuse Cipher objects — cipher creation is expensive
  2. Use streaming encryption for large payloads
  3. Consider ChaCha20 for mobile devices

Comparison with Other Libraries

Library API Level Symmetric Encryption Asymmetric Encryption Active Development Recommendation
cryptography High + Low ✅ Full support ✅ RSA, ECC, Ed25519 ✅ Active Recommended
pycryptodome Mid‑level ✅ Good support ✅ RSA, ECC ✅ Active Alternative
pycrypto Low ⚠️ Basic only ⚠️ RSA only ❌ Unmaintained Not recommended
hashlib High ❌ Hashing only ❌ None ✅ Standard Use for hashing only
ssl High ⚠️ TLS‑oriented ⚠️ Limited ✅ Standard For TLS/SSL

Real‑World Use Cases

Web Application Security

Session storage:

from cryptography.fernet import Fernet
import json
import datetime

class SessionManager:
    def __init__(self, secret_key):
        self.cipher = Fernet(secret_key)
    
    def create_session(self, user_id, expires_in_hours=24):
        session_data = {
            'user_id': user_id,
            'created_at': datetime.datetime.utcnow().isoformat(),
            'expires_at': (datetime.datetime.utcnow() + 
                         datetime.timedelta(hours=expires_in_hours)).isoformat()
        }
        
        token = self.cipher.encrypt(json.dumps(session_data).encode())
        return token
    
    def validate_session(self, token):
        try:
            decrypted_data = self.cipher.decrypt(token)
            session_data = json.loads(decrypted_data.decode())
            
            expires_at = datetime.datetime.fromisoformat(session_data['expires_at'])
            if datetime.datetime.utcnow() > expires_at:
                return None
                
            return session_data
        except:
            return None

Microservice Architecture

JWT‑like tokens with extra security:

import json
import base64
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

class SecureTokenService:
    def __init__(self):
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
        )
        self.public_key = self.private_key.public_key()
    
    def create_token(self, payload):
        # Header
        header = {"alg": "RS256", "typ": "JWT"}
        
        # Encode header and payload
        encoded_header = base64.urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip('=')
        encoded_payload = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip('=')
        
        # Sign
        message = f"{encoded_header}.{encoded_payload}".encode()
        signature = self.private_key.sign(
            message,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        
        encoded_signature = base64.urlsafe_b64encode(signature).decode().rstrip('=')
        
        return f"{encoded_header}.{encoded_payload}.{encoded_signature}"
    
    def verify_token(self, token):
        try:
            parts = token.split('.')
            if len(parts) != 3:
                return None
            
            header, payload, signature = parts
            
            # Recreate signature bytes
            signature_bytes = base64.urlsafe_b64decode(signature + '==')
            message = f"{header}.{payload}".encode()
            
            # Verify signature
            self.public_key.verify(
                signature_bytes,
                message,
                padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=padding.PSS.MAX_LENGTH
                ),
                hashes.SHA256()
            )
            
            # Decode payload
            payload_data = json.loads(base64.urlsafe_b64decode(payload + '==').decode())
            return payload_data
            
        except Exception:
            return None

Frequently Asked Questions

What RSA key size should I use?

At least 2048 bits is recommended for RSA keys. For high‑security environments consider 4096 bits, keeping performance impact in mind.

When should I use Fernet versus low‑level primitives?

Fernet is ideal for most use cases thanks to built‑in authentication and simplicity. Low‑level primitives are needed for custom protocols or when compatibility with existing systems is required.

How should I store cryptographic keys?

  • In production, use a Key Management Service (AWS KMS, Azure Key Vault, etc.)
  • During development — environment variables
  • Never hard‑code keys or commit them to version control

What if a key is compromised?

  1. Immediately revoke the compromised key
  2. Generate a new key pair
  3. Re‑encrypt all data with the new key
  4. Notify users to update any dependent credentials

How can I ensure compatibility across different library versions?

Use stable serialization formats (PEM, DER) and avoid experimental features in production.

Performance and Optimization

Operation Benchmarks

Operation Time (ms/op) Recommendation
Fernet encrypt (1 KB) ~0.1 Optimal for most tasks
RSA encrypt (2048‑bit) ~1.5 Use for small payloads
AES‑GCM (1 KB) ~0.05 Faster than Fernet, but requires more code
Ed25519 sign ~0.3 Faster than RSA signatures
PBKDF2 (100k iterations) ~50 Good balance of security and speed

Optimizing for Large Data Volumes

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os

def encrypt_large_file(input_file, output_file, key):
    """Stream‑encrypt a large file"""
    iv = os.urandom(16)
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
    encryptor = cipher.encryptor()
    
    with open(input_file, 'rb') as infile, open(output_file, 'wb') as outfile:
        # Write IV at the beginning
        outfile.write(iv)
        
        # Process in 64 KB chunks
        while True:
            chunk = infile.read(64 * 1024)
            if not chunk:
                break
            
            # Apply padding only to the final chunk
            if len(chunk) < 64 * 1024:  # Last block
                from cryptography.hazmat.primitives import padding
                padder = padding.PKCS7(128).padder()
                chunk = padder.update(chunk) + padder.finalize()
            
            encrypted_chunk = encryptor.update(chunk)
            outfile.write(encrypted_chunk)
        
        # Finalize
        final_chunk = encryptor.finalize()
        if final_chunk:
            outfile.write(final_chunk)

Integration with Popular Frameworks

Django

from cryptography.fernet import Fernet
from django.conf import settings

class EncryptedModelField:
    def __init__(self):
        self.cipher = Fernet(settings.ENCRYPTION_KEY.encode())
    
    def encrypt_field(self, value):
        if value:
            return self.cipher.encrypt(str(value).encode()).decode()
        return value
    
    def decrypt_field(self, value):
        if value:
            return self.cipher.decrypt(value.encode()).decode()
        return value

FastAPI

from fastapi import HTTPException, Depends
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

async def verify_signature(request_data: dict, signature: str):
    """Middleware to verify API request signatures"""
    try:
        public_key = get_api_public_key()  # Retrieve key from config
        message = json.dumps(request_data, sort_keys=True).encode()
        signature_bytes = base64.b64decode(signature)
        
        public_key.verify(
            signature_bytes,
            message,
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        return True
    except Exception:
        raise HTTPException(status_code=401, detail="Invalid signature")

Conclusion

The Cryptography library is a powerful and reliable tool for solving cryptographic challenges in Python. It successfully blends the simplicity of a high‑level API with the flexibility of low‑level primitives, making it suitable for rapid prototyping as well as production‑grade solutions.

Key advantages of the library:

  • Security by default: modern algorithms and protection against common mistakes
  • Performance: optimized C bindings for critical operations
  • Standardization: support for industry‑standard formats and protocols
  • Active development: regular updates and security patches

Cryptography is used in major projects ranging from banking systems and government services to startups and scientific research. Its reliability is proven by time and the trust of the developer community.

When choosing a cryptographic library for a Python project, Cryptography should be the first and primary option. It provides all the tools needed to build secure systems, and its documentation and community support help resolve any issues that arise.

News