iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Common Misuses

Crypto misuse is the gap between "we use AES" and "we use AES correctly". The library is almost never the bug; the usage is. This lesson walks through the misuse patterns that have shipped in production at companies you have heard of.

Eight cryptographic misuse patterns and their fixes

EXAMPLE
# 1) ECB mode reveals patterns in the plaintext (the 'penguin image')
#    BUG: encrypted bitmap shows the outline of the original
#    FIX: never use ECB. Use AES-GCM or ChaCha20-Poly1305 for everything.
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = AESGCM.generate_key(256)
nonce = __import__('secrets').token_bytes(12)         # 12 bytes for GCM
ct = AESGCM(key).encrypt(nonce, b'sensitive', associated_data=b'context-v1')

# 2) Nonce reuse with AES-GCM catastrophically destroys authentication
#    BUG: storing a counter that gets reset on deploy, reusing nonces across processes
#    FIX: 96-bit random nonce per message AND track them on the server,
#         OR derive a unique nonce from a key-id+counter you persist atomically.

# 3) Hashing passwords with SHA-256 (or any general-purpose hash)
#    BUG: GPUs hash billions of SHA-256 candidates per second
#    FIX: argon2id (preferred), or bcrypt with cost >= 12
import argon2
hasher = argon2.PasswordHasher(time_cost=3, memory_cost=64*1024, parallelism=4)
hash = hasher.hash('hunter2')
hasher.verify(hash, 'hunter2')

# 4) Comparing secrets with == (timing leak)
#    BUG: webhook signature compared with == — attacker measures latency to learn bytes
#    FIX: hmac.compare_digest (Python), crypto.timingSafeEqual (Node), subtle (Go)
import hmac
ok = hmac.compare_digest(expected_mac, supplied_mac)

# 5) Skipping certificate validation in TLS calls
#    BUG: verify=False / insecureSkipVerify: true to 'make it work'
#    FIX: ship the right CA bundle; pin if the target is critical (mobile clients).
import requests
requests.get('https://api.example.com', verify=True)   # DEFAULT — keep it

# 6) Encrypting then NOT authenticating
#    BUG: AES-CBC with no HMAC — attacker flips bits to corrupt or oracle-decrypt
#    FIX: always use an AEAD (AES-GCM, ChaCha20-Poly1305). Encrypt-then-MAC ONLY
#         if a constraint forces it and you write the construction carefully.

# 7) JWT 'alg: none' or HS256-vs-RS256 confusion
#    BUG: server accepts whatever 'alg' the token claims; attacker swaps in alg:none
#    FIX: HARDCODE the expected algorithm in the verifier; never trust the header.
import jwt
claims = jwt.decode(token, key=public_key, algorithms=['RS256'], audience='shop-api')

# 8) Reusing the same key for too many things ('one key to rule them all')
#    BUG: same master key encrypts AND signs AND derives session keys
#    FIX: derive purpose-specific keys with HKDF: HKDF(master, info='session-encryption-v1')
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
enc_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None,
                info=b'session-encryption-v1').derive(master)
mac_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None,
                info=b'session-mac-v1').derive(master)

# 9) Rolling your own crypto
#    BUG: 'we wrote our own AES because the library was slow'
#    FIX: do not. Reach for libsodium/Bouncy Castle/BoringSSL/cryptography. Their
#         primitives are constant-time, peer-reviewed, and faster than yours.

Why it matters

A library you trust + an API you do not understand is not safe. The cheapest fix is to pick the highest-level primitive available — AEAD over raw block cipher, password hasher over hash function, HKDF over manual key derivation — because the high-level API hides the misuse-prone knobs.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Common bugs:
// - IV / nonce reuse with the same key.
// - Using a hash for passwords.
// - JWT with alg=none accepted.
// - HKDF info parameter omitted, mixing key purposes.
// - Comparing MACs with ==.
Try it Yourself »

Discussion

Loading…