Examples
Six worked crypto examples covering the cases that come up in real apps: sign + verify a JWT, encrypt-then-MAC a token, hash + verify a password, generate per-request nonces, sign a webhook, and a constant-time compare. Use them as a paste-ready reference.
Six working crypto recipes
EXAMPLE
# Python (cryptography + argon2-cffi + PyJWT)
# pip install cryptography argon2-cffi pyjwt
# ============================================================
# 1) Sign + verify a JWT with RS256
# ============================================================
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import jwt
import time
private = rsa.generate_private_key(public_exponent=65537, key_size=2048)
private_pem = private.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
public_pem = private.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
now = int(time.time())
token = jwt.encode(
{ 'sub': 'u1', 'aud': 'shop-api', 'iat': now, 'exp': now + 3600 },
private_pem, algorithm='RS256',
)
# Always pin the algorithm + audience on verify
claims = jwt.decode(token, public_pem, algorithms=['RS256'], audience='shop-api')
# ============================================================
# 2) Encrypt-then-authenticate via AES-GCM
# ============================================================
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import secrets
key = AESGCM.generate_key(bit_length=256)
nonce = secrets.token_bytes(12)
aad = b'context-v1'
ct = AESGCM(key).encrypt(nonce, b'sensitive payload', aad)
pt = AESGCM(key).decrypt(nonce, ct, aad)
# Wire format: nonce || ct (nonce is NOT a secret; it MUST be unique per key)
# ============================================================
# 3) Hash + verify a password
# ============================================================
import argon2
hasher = argon2.PasswordHasher(time_cost=3, memory_cost=64*1024, parallelism=4)
hash_ = hasher.hash('hunter2')
try:
hasher.verify(hash_, 'hunter2')
print('ok')
except argon2.exceptions.VerifyMismatchError:
print('mismatch')
# Plan a rehash if parameters changed (after a deploy)
if hasher.check_needs_rehash(hash_):
hash_ = hasher.hash('hunter2')
# ============================================================
# 4) Per-request unique nonce / CSRF token
# ============================================================
csrf = secrets.token_urlsafe(32) # URL-safe 32 byte random
# Store on the session; require it back as a header or hidden field.
# ============================================================
# 5) Sign a webhook payload (HMAC-SHA256)
# ============================================================
import hmac
import hashlib
secret = b'shared-with-the-webhook-receiver'
body = b'{"order_id":"o1","status":"paid"}'
sig = hmac.new(secret, body, hashlib.sha256).hexdigest()
# At the receiver
def verify(body, header_sig, secret):
expected = hmac.new(secret, body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header_sig)
# ============================================================
# 6) Constant-time compare (for any user-supplied secret)
# ============================================================
import hmac
ok = hmac.compare_digest(stored_token, incoming_token)
# ============================================================
# Node equivalents (built-in crypto module)
# ============================================================
# JWT: jsonwebtoken or jose package
# AES: crypto.createCipheriv('aes-256-gcm', ...)
# Argon: argon2 package
# HMAC: crypto.createHmac('sha256', key).update(body).digest('hex')
# CT: crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
# ============================================================
# Pitfalls
# ============================================================
# - Reusing a GCM nonce with the SAME key = catastrophic
# - JWT without algorithm pin = 'alg: none' attacks
# - SHA-256 for passwords = GPU-crackable in seconds
# - Comparing secrets with == = timing leak
# - Custom key derivation (concat + SHA) = misuse; use HKDF
Why it matters
For every constant-time-needed compare in your codebase, write a comment with the WHY ("HMAC verify — constant time prevents byte-by-byte timing leak"). It teaches the next person why `==` is wrong here, and it stops a refactor in three months from quietly turning the safe call back into the timing-leaking one.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…