A self-contained, defensive reference for the difference between secure and looks secure. Cryptography is the rare area where intuition is actively dangerous — the right answer is almost always “use a vetted primitive correctly,” and the interesting knowledge is which primitive, why, and how systems get it subtly wrong (nonce reuse, padding oracles, downgrade attacks). This chapter is that knowledge, framed for building and defending real systems.
How to use this: Part 1 is the reference card. Part 2 maps the territory. Part 3 is the full depth with pros/cons per primitive. Part 4 is exhaustive interview prep with counter-question ladders. Everything here is for building secure systems and defending them.
Key takeaways
- Never invent your own crypto — use vetted primitives and standard constructions (AEAD, TLS 1.3, HKDF, Argon2); security rests on the key, not secret design.
- Match the primitive to the goal: encryption is not integrity, a MAC is not a signature, and a fast hash is not password storage.
- Most real breaks are misuse of good primitives — nonce reuse, padding oracles, downgrade attacks, and JWT alg:none.
- Use ephemeral key exchange for forward secrecy, CSPRNGs for all keys and nonces, and a KMS or HSM for key management.
PART 1 — CHEATSHEET (Reference Card)
Every concept in this document, condensed.
The one idea
Never invent your own crypto. Use standard, vetted primitives, compose them with vetted constructions (AEAD, TLS, HKDF), and assume the algorithms are public (Kerckhoffs’s principle) — security must rest on the key, not the secrecy of the design. Most real breaks are misuse of good primitives, not broken math.
Security goals
- Confidentiality — only authorized parties read it (encryption).
- Integrity — tampering is detectable (MACs, signatures, hashes).
- Authenticity — you know who you’re talking to (signatures, MACs, certificates).
- Non-repudiation — sender can’t deny it (digital signatures).
- (CIA triad = Confidentiality, Integrity, Availability.)
Primitive selection (which tool for which job)
| Goal | Use | Not |
|---|---|---|
| Encrypt + authenticate data | AEAD (AES-GCM, ChaCha20-Poly1305) | ECB; encryption without a MAC |
| Integrity/authenticity (shared key) | HMAC | plain hash; “encryption = integrity” |
| Verify identity / non-repudiation | Digital signature (Ed25519, ECDSA, RSA-PSS) | MAC (no non-repudiation) |
| Derive keys from a shared secret | HKDF | raw hash; reusing the secret directly |
| Hash a password | Argon2 / scrypt / bcrypt (slow, salted) | SHA-256 (too fast) |
| Key agreement over insecure channel | ECDH (X25519) / DH | sending a key in plaintext |
| Random tokens/keys/IVs | CSPRNG (/dev/urandom, libsodium) |
rand(), timestamps |
Symmetric vs asymmetric
| Symmetric (AES, ChaCha20) | Asymmetric (RSA, ECC) | |
|---|---|---|
| Keys | One shared secret | Public/private pair |
| Speed | Fast (bulk data) | Slow (small data/setup) |
| Use | Bulk encryption, MACs | Key exchange, signatures, identity |
| Problem solved | Confidentiality at speed | Key distribution, authentication |
Key sizes / facts (rules of thumb)
- AES-128 (fine) / AES-256; block size 128 bits. Never reuse a (key, nonce) pair in GCM/CTR.
- RSA ≥ 2048 (3072 for long-term); ECC-256 (P-256/Curve25519) ≈ RSA-3072 strength at far less cost.
- SHA-256 / SHA-3 for hashing; avoid MD5/SHA-1 (collisions).
- Hash properties: preimage, second-preimage, collision resistance.
Quick decision rules
- Encrypt anything → AEAD, fresh nonce per message, manage keys properly.
- Store passwords → Argon2id (or bcrypt/scrypt) with per-user salt; never reversible encryption.
- Authenticate a token you issued → HMAC (or signature if third parties verify).
- Two parties need a shared key → ECDH + derive with HKDF; want forward secrecy → ephemeral keys.
- Set up a secure channel → TLS 1.3 (don’t build your own).
Top gotchas (litmus tests)
- Don’t roll your own crypto — and don’t roll your own protocol either.
- Nonce/IV reuse is catastrophic — in GCM it breaks confidentiality and forgeable integrity; in CTR it XORs plaintexts.
- ECB leaks structure (identical blocks → identical ciphertext — the “ECB penguin”).
- Encryption ≠ integrity — unauthenticated ciphertext is malleable; use AEAD (encrypt-then-MAC).
- Hash ≠ password storage — fast hashes are brute-forced; use slow, salted KDFs (Argon2/bcrypt/scrypt).
- Compare secrets in constant time —
==leaks via timing (timing side channel). - Padding oracles (and error-message oracles) break CBC — another reason for AEAD.
- Downgrade attacks force weak ciphers — disable legacy; TLS 1.3 removed the weak options.
- No forward secrecy = one stolen long-term key decrypts all past traffic — use ephemeral (EC)DH.
- JWT pitfalls:
alg:none, algorithm confusion (HS256 vs RS256), no expiry, secrets in the token — validate strictly.
PART 2 — OUTLINE (full map)
- Security goals and Kerckhoffs’s principle
- Symmetric encryption: AES, modes, and AEAD
- Hash functions and MACs
- Key derivation and password hashing
- Asymmetric cryptography: RSA, Diffie–Hellman, ECC
- Digital signatures
- Key exchange and forward secrecy
- The TLS 1.3 handshake
- PKI, certificates, and certificate transparency
- Authentication systems: passwords, OAuth2/OIDC, JWT, MFA
- Zero-knowledge proofs
- Merkle trees
- Threat modeling (STRIDE)
- Classic protocol failures
- Randomness, secrets management, defense in depth
- Decision guide
- Make it stick — the teaching tutorial (primitive-to-goal map, mnemonics, flashcards)
PART 3 — DEEP DIVE
1. Security goals and Kerckhoffs’s principle
Before choosing primitives, name the goal: confidentiality (secrecy), integrity (no undetected tampering), authenticity (identity), non-repudiation (provable origin), plus availability. Different primitives serve different goals — encryption gives confidentiality but not integrity; a MAC gives integrity/authenticity but not confidentiality. Kerckhoffs’s principle: a system must be secure even if everything about it except the key is public — so security rests on key secrecy, not algorithm obscurity (“no security through obscurity”). This is why we use public, peer-reviewed algorithms; a secret algorithm is a red flag.
2. Symmetric encryption: AES, modes, and AEAD
Symmetric encryption uses one shared key for both encrypt and decrypt; it’s fast and used for bulk data. AES is the standard block cipher (128-bit blocks; 128/192/256-bit keys). A block cipher needs a mode to encrypt more than one block:
- ECB (Electronic Codebook): encrypt each block independently — broken: identical plaintext blocks produce identical ciphertext, leaking structure (the infamous “ECB penguin”). Never use.
- CBC, CTR: chain or counter-based modes that hide structure — but provide no integrity alone, and CBC is vulnerable to padding-oracle attacks if decryption errors leak.
- AEAD (Authenticated Encryption with Associated Data) — the modern default: encrypts and authenticates in one construction, and can authenticate (but not encrypt) associated data (headers). AES-GCM and ChaCha20-Poly1305 are the standard AEADs (Rogaway formalized AEAD, 2002). They give confidentiality + integrity together, eliminating whole bug classes.
The cardinal rule — never reuse a (key, nonce/IV) pair. In GCM, nonce reuse is catastrophic: it leaks the authentication key, enabling forgeries, and reveals plaintext relationships. Use a counter or a CSPRNG nonce and track it carefully (or use misuse-resistant AEAD like AES-GCM-SIV where nonce reuse is less fatal).
Pros (AEAD): one primitive for confidentiality + integrity; hard to misuse compared to manual encrypt-then-MAC. Cons: nonce management is critical; key management remains the hard problem.
3. Hash functions and MACs
A cryptographic hash (SHA-256, SHA-3) maps arbitrary input to a fixed-size digest with three properties: preimage resistance (can’t find input from hash), second-preimage resistance (can’t find a different input with the same hash), and collision resistance (can’t find any two inputs that collide). MD5 and SHA-1 are broken for collision resistance — don’t use them where collisions matter.
A MAC (Message Authentication Code) provides integrity + authenticity using a shared secret key — only someone with the key can produce/verify it. HMAC is the standard construction (HMAC-SHA256), designed to be secure even given weaknesses in the underlying hash and immune to length-extension attacks (which naive hash(secret||message) suffers). Verify MACs in constant time to avoid timing leaks.
MAC vs signature: a MAC uses a shared key (both parties can produce it → no non-repudiation); a signature uses a private key (only the holder can produce it → non-repudiation + third-party verifiability).
Pros: cheap, strong integrity/authenticity. Cons: a plain hash is not a MAC (no key) and not password storage (too fast); MAC gives no non-repudiation.
4. Key derivation and password hashing
Two related but distinct jobs:
- Key Derivation Function (KDF) — HKDF (Krawczyk, 2010; RFC 5869): turn a shared secret (e.g. from ECDH, which isn’t uniformly random) into one or more strong, uniformly-distributed keys, with a salt and context info (“extract-then-expand”). Use it whenever you derive symmetric keys from a key-exchange output.
- Password hashing — a deliberately slow, salted function: Argon2 (memory-hard, current recommendation), scrypt, bcrypt. The point is to make brute-force/guessing expensive. Never store passwords with a fast hash (SHA-256) — GPUs try billions/sec. Always use a per-user salt (defeats rainbow tables) and tune the work/memory factor. (PBKDF2 is acceptable but not memory-hard, so weaker against GPU/ASIC attacks.)
Pros: HKDF gives clean key separation; slow KDFs make stolen password databases far harder to crack. Cons: password hashing cost must be tuned (too slow = DoS surface, too fast = crackable); salts must be unique.
5. Asymmetric cryptography: RSA, Diffie–Hellman, ECC
Public-key crypto (Diffie & Hellman, “New Directions in Cryptography”, 1976) solves what symmetric can’t: key distribution and authentication without a pre-shared secret. Each party has a public key (shareable) and a private key (secret).
- Diffie–Hellman (DH): two parties derive a shared secret over a public channel without ever transmitting it (based on the discrete-log problem). The basis of key exchange.
- RSA (Rivest, Shamir, Adleman, 1978): based on the hardness of factoring; supports both encryption and signatures. Needs large keys (≥2048 bits). Use modern padding (OAEP for encryption, PSS for signatures) — textbook RSA is insecure.
- Elliptic Curve Cryptography (ECC): same problems (key exchange via ECDH, signatures via ECDSA/Ed25519) at much smaller keys — a 256-bit curve (P-256, Curve25519) ≈ 3072-bit RSA strength, so it’s faster and cheaper. The modern default.
Pros: solves key distribution + identity; signatures give non-repudiation. Cons: slow vs symmetric (so used only for setup/small data, then switch to symmetric); large keys (RSA); implementation pitfalls (bad padding, weak curves, nonce reuse in ECDSA leaks the private key).
6. Digital signatures
A digital signature binds a message to a private key: the holder signs with their private key; anyone verifies with the public key. It provides integrity + authenticity + non-repudiation (only the private-key holder could have produced it, and they can’t deny it). Schemes: Ed25519 (fast, safe defaults — the modern recommendation), ECDSA (careful: a repeated/predictable nonce leaks the private key — a famous real-world break), RSA-PSS. Signatures underpin certificates, software signing, and authentication. (Contrast with a MAC, which authenticates but, using a shared key, gives no non-repudiation.)
7. Key exchange and forward secrecy
To set up a secure channel, parties run a key exchange (typically ECDH) to agree on a shared secret, then derive symmetric keys (HKDF) for fast bulk AEAD encryption — combining asymmetric (for setup) and symmetric (for speed). Forward secrecy (perfect forward secrecy, PFS): use ephemeral keys (a fresh DH key pair per session, ECDHE) so that even if a long-term private key is later compromised, past session keys (and thus past recorded traffic) remain secret — the ephemeral keys were discarded. Without PFS, stealing one long-term key retroactively decrypts all captured sessions. TLS 1.3 mandates forward secrecy.
Pros: PFS dramatically limits the damage of key compromise. Cons: ephemeral key generation per session has cost (minor with ECC).
8. The TLS 1.3 handshake
TLS provides a secure channel (confidentiality, integrity, server—and optionally client—authentication). TLS 1.3 (Rescorla, RFC 8446, 2018) is a major cleanup:
- 1-RTT handshake (down from 2 in TLS 1.2), with 0-RTT resumption (faster, but 0-RTT data is replayable → idempotent requests only).
- Forward secrecy mandatory (ephemeral ECDHE only).
- Removed legacy/weak options (RSA key transport, CBC modes, weak ciphers) — shrinking the attack surface and resisting downgrade attacks.
- Flow (simplified): client sends supported groups + a key share; server picks parameters, sends its key share + certificate + a signature proving it holds the private key; both derive keys via ECDHE + HKDF; the certificate (PKI) authenticates the server. Don’t implement TLS yourself — use a vetted library.
Pros: fast, forward-secret, fewer footguns. Cons: still depends on PKI trust (a compromised/mis-issued CA cert breaks authentication) and correct certificate validation by clients.
9. PKI, certificates, and certificate transparency
How do you trust a public key belongs to “example.com”? Public Key Infrastructure (PKI): a Certificate Authority (CA) signs a certificate binding a public key to an identity; clients trust a set of root CAs, and trust chains down (root → intermediate → leaf). The weaknesses: a compromised or mis-issuing CA can forge certificates for any site (the trust is only as strong as the weakest trusted CA), and revocation is hard (CRLs are bulky; OCSP has privacy/availability issues; OCSP stapling helps). Certificate Transparency (CT): public, append-only, cryptographically-verifiable logs (Merkle-tree-based) of all issued certificates, so mis-issuance is detectable by domain owners and browsers — a detective control layered on PKI’s preventive one.
Pros: scalable trust without pre-sharing every key; CT adds accountability. Cons: CA compromise is systemic; revocation is unreliable; certificate validation bugs in clients are common.
10. Authentication systems: passwords, OAuth2/OIDC, JWT, MFA
- Passwords: store with a slow salted KDF (Argon2/bcrypt/scrypt), never plaintext or reversible encryption; rate-limit and monitor for credential stuffing; support MFA.
- MFA (multi-factor): something you know + have + are. TOTP, push, and especially phishing-resistant WebAuthn/FIDO2 (public-key based, bound to the origin — resists phishing because the credential won’t sign for a look-alike domain).
- OAuth 2.0: an authorization framework — a user grants a third-party app limited access (scopes) to their resources without sharing the password, via tokens (use the Authorization Code flow with PKCE). It’s delegation, not authentication.
- OpenID Connect (OIDC): an authentication layer on top of OAuth 2.0 — issues an ID token (a JWT) proving who the user is. (Common interview trap: OAuth = authorization, OIDC = authentication.)
- JWT (JSON Web Token): a signed (and/or encrypted) token carrying claims. Pitfalls to know cold:
alg:none(reject it), algorithm confusion (an attacker swaps RS256→HS256 so the public key is used as an HMAC secret — pin the algorithm), missing/long expiry, no revocation (stateless tokens can’t be easily revoked — keep them short-lived + use refresh tokens), and putting secrets in the payload (it’s only base64, not encrypted, unless you use JWE). Always validate signature, algorithm, issuer, audience, and expiry.
Pros: standardized delegation/identity; stateless tokens scale. Cons: JWTs are easy to misuse; statelessness fights revocation; OAuth/OIDC flows are subtle and frequently misimplemented.
11. Zero-knowledge proofs
A zero-knowledge proof (Goldwasser, Micali, Rackoff, 1985) lets a prover convince a verifier that a statement is true without revealing anything beyond its truth — satisfying completeness (true statements verify), soundness (false ones don’t, except negligibly), and zero-knowledge (the verifier learns nothing else). Classic intuition: proving you know a password without sending it. Modern practical forms (zk-SNARKs/zk-STARKs) produce succinct proofs and power privacy-preserving authentication and blockchain scaling (prove a computation was done correctly without revealing inputs).
Pros: prove knowledge/correctness without disclosure — powerful for privacy. Cons: complex, computationally heavy (proving cost), and easy to get subtly wrong; specialized.
12. Merkle trees
A Merkle tree (Merkle, 1987) is a tree of hashes: leaves hash data blocks, each internal node hashes its children, and the root hash commits to the entire dataset. Its power: you can prove a single block is included with a Merkle proof — just the sibling hashes along the path to the root (O(log n)), without revealing or transferring the whole dataset. Uses: Git commits, blockchain blocks, Certificate Transparency logs, anti-entropy/replica reconciliation (compare roots, descend only into differing subtrees), and content-addressed storage. Any change to any block changes the root — tamper-evident by construction.
Pros: efficient integrity verification and inclusion proofs; cheap diffing of large datasets. Cons: proofs need a trusted root; not confidential (it’s about integrity, not secrecy).
13. Threat modeling (STRIDE)
Security is a process, not a primitive. Threat modeling systematically asks “what can go wrong?” STRIDE is a checklist of threat categories: Spoofing (authenticity), Tampering (integrity), Repudiation (non-repudiation), Information disclosure (confidentiality), Denial of service (availability), Elevation of privilege (authorization). For each component/data-flow, enumerate STRIDE threats and decide on mitigations. It maps cleanly onto the security goals and forces you to reason about the attacker, not just the happy path.
14. Classic protocol failures
Knowing how good crypto gets misused is the senior differentiator:
- Padding oracle (CBC): decryption error messages/timing reveal whether padding was valid, letting an attacker decrypt without the key — defeated by AEAD (no separate padding check) and constant-time handling.
- Timing / side-channel attacks: secret-dependent timing, cache access, or power leaks the key; use constant-time comparisons and libraries.
- Nonce/IV reuse: breaks GCM/CTR confidentiality and integrity (see §2).
- Downgrade attacks: an attacker forces negotiation of a weak cipher/version (e.g. POODLE, FREAK) — disable legacy; TLS 1.3 removed weak options and signs the handshake transcript.
- Replay attacks: capturing and re-sending a valid message — defeated by nonces, timestamps, sequence numbers (and why TLS 1.3 0-RTT is restricted to idempotent ops).
- MAC-then-encrypt vs encrypt-then-MAC: encrypt-then-MAC (what AEAD does) is the safe order; MAC-then-encrypt enabled several real attacks.
15. Randomness, secrets management, defense in depth
- Cryptographically secure randomness (CSPRNG): keys, nonces, salts, and tokens must come from a CSPRNG (
/dev/urandom,getrandom(),crypto.randomBytes, libsodium) — neverrand(), PID, or timestamps (predictable randomness has broken real systems, e.g. weak SSH/TLS keys from low entropy). - Secrets management: keep keys out of code/config/logs; use a secrets manager / KMS / HSM, rotate keys, scope them least-privilege, and prefer envelope encryption (a KMS-held master key wraps data keys).
- Defense in depth & least privilege: don’t rely on one control; layer them (network, app, data, monitoring) so one failure isn’t fatal, and grant the minimum access needed. Assume breach and limit blast radius.
Pros: these practices catch the failures crypto math can’t; least privilege + rotation bound damage. Cons: operational overhead; key management is genuinely the hardest part of applied crypto.
16. Decision guide
What do you need?
├─ Encrypt data ───────────────► AEAD (AES-GCM / ChaCha20-Poly1305), fresh nonce, KMS-managed keys
├─ Integrity (shared key) ─────► HMAC-SHA256 (constant-time verify)
├─ Identity / non-repudiation ─► SIGNATURE (Ed25519 / RSA-PSS)
├─ Store passwords ────────────► Argon2id (or bcrypt/scrypt) + per-user salt
├─ Derive keys from a secret ──► HKDF (extract-then-expand)
├─ Agree a key over the wire ──► ECDH (X25519); ephemeral → FORWARD SECRECY
├─ Secure channel ─────────────► TLS 1.3 (use a library; never DIY)
├─ Delegated access ───────────► OAuth 2.0 (Auth Code + PKCE); prove identity → OIDC (ID token)
├─ Random key/nonce/salt ──────► CSPRNG (never rand())
└─ Prove inclusion / tamper-evidence ► MERKLE TREE
Always: threat-model with STRIDE; least privilege + defense in depth; keys in a KMS/HSM, rotated.
Reach-for / avoid:
- AEAD — for: all encryption. Avoid: ECB ever; encryption without authentication.
- Argon2/bcrypt — for: passwords. Avoid: SHA-256 for passwords (too fast).
- Signatures — for: third-party verification / non-repudiation. Avoid: MAC when non-repudiation is needed.
- Ephemeral ECDH — for: forward secrecy. Avoid: static-key exchange for long-lived confidentiality.
- Rolling your own — never. Use vetted libraries (libsodium, your platform’s crypto) and standard protocols.
PART 4 — INTERVIEW ARSENAL
How to wield this. Senior signals: (1) you match the primitive to the goal (encryption ≠ integrity; MAC ≠ signature; hash ≠ password storage); (2) you cite misuse failures (nonce reuse, padding oracle, downgrade, JWT
alg:none) not just algorithm names; (3) you default to standard constructions (AEAD, TLS 1.3, HKDF, Argon2) and threat-model rather than improvise. All defensive. Each question has a model answer and counter-ladder.
A. Fundamentals
Q1. Encryption vs hashing vs MAC vs signature — match each to a goal. Answer: Encryption → confidentiality (reversible with a key). Hash → integrity/fingerprint (one-way, no key). MAC → integrity + authenticity with a shared key (no non-repudiation). Signature → integrity + authenticity + non-repudiation with a private key (third-party verifiable). Choosing the wrong one (e.g. encrypting for integrity, or hashing a password expecting safety) is the classic mistake. Counter-ladder:
- “Does encryption give integrity?” → No — unauthenticated ciphertext is malleable; use AEAD (encrypt-then-MAC).
- “MAC vs signature for an API token you issue and verify yourself?” → HMAC (shared secret, faster) suffices; use a signature only if third parties must verify.
Q2. Why must you never roll your own crypto, given Kerckhoffs’s principle? Answer: Security must rest on the key, not secret design (Kerckhoffs) — so the algorithm will be public and must withstand expert scrutiny. Homegrown crypto/protocols almost always have subtle flaws (padding, timing, nonce handling) that vetted, peer-reviewed primitives and libraries have already fixed. Use AES-GCM/ChaCha20-Poly1305, TLS 1.3, libsodium — and standard protocols, not just primitives. Counter-ladder:
- “Isn’t a secret algorithm more secure?” → No — security through obscurity fails; it breaks the moment the design leaks and gets no public review.
- “Where do most real breaks come from?” → Misuse of good primitives (nonce reuse, bad padding, weak randomness), not broken math.
B. Symmetric & integrity
Q3. What’s AEAD and why is ECB / unauthenticated encryption dangerous? Answer: AEAD (AES-GCM, ChaCha20-Poly1305) encrypts and authenticates together, optionally authenticating associated data — giving confidentiality + integrity in one safe construction. ECB encrypts blocks independently, so identical plaintext blocks leak as identical ciphertext (structure visible — the “ECB penguin”). Unauthenticated encryption (CBC/CTR alone) is malleable and enables padding-oracle attacks. Always AEAD. Counter-ladder:
- “What happens if you reuse a nonce in GCM?” → Catastrophic: leaks the auth key (forgeries) and reveals plaintext relationships; never reuse (key, nonce).
- “How do you manage nonces safely?” → Counter or CSPRNG with tracking; or misuse-resistant AES-GCM-SIV.
Q4. How should passwords be stored, and why not SHA-256? Answer: With a slow, memory-hard, salted KDF — Argon2id (or bcrypt/scrypt) — and a unique per-user salt. SHA-256 is far too fast: GPUs try billions/sec, so a stolen hash database is quickly cracked. Slowness + memory-hardness make each guess expensive; the salt defeats rainbow tables. Counter-ladder:
- “Why a salt if the hash is slow?” → Salt makes each hash unique, defeating precomputed rainbow tables and parallel cracking of identical passwords.
- “PBKDF2 ok?” → Acceptable but not memory-hard → weaker against GPU/ASIC than Argon2/scrypt.
- “Pepper?” → An app-wide secret (in a KMS, not the DB) added to defense-in-depth; complements, not replaces, salts.
C. Asymmetric & channels
Q5. Walk through how TLS sets up a secure channel and what forward secrecy buys. Answer: Asymmetric for setup, symmetric for speed: parties run ephemeral ECDH to agree a shared secret, the server proves identity with a certificate + signature (PKI), both derive symmetric keys via HKDF, then bulk data uses AEAD. Forward secrecy (ephemeral keys per session) means a future compromise of the long-term key can’t decrypt past recorded sessions — the session keys were ephemeral and discarded. TLS 1.3 mandates it and does it in 1-RTT. Counter-ladder:
- “Why not just use RSA to encrypt everything?” → Slow; and RSA key transport (no PFS) lets one stolen key decrypt all past traffic — TLS 1.3 removed it.
- “0-RTT risk?” → 0-RTT data is replayable → only for idempotent requests.
- “What breaks TLS’s trust?” → A compromised/mis-issuing CA, or a client that doesn’t validate the certificate chain.
Q6. RSA vs ECC — which and why? Answer: ECC for new systems: a 256-bit curve (e.g. Curve25519) gives ~3072-bit RSA strength at far lower CPU/key size — faster handshakes, smaller certs. RSA is still widely deployed and fine at ≥2048 bits with proper padding (OAEP/PSS), but it’s heavier. Prefer Ed25519 for signatures, X25519 for key exchange. Counter-ladder:
- “ECDSA footgun?” → A reused/predictable per-signature nonce leaks the private key (a real, famous break); Ed25519 derives the nonce deterministically to avoid it.
- “Textbook RSA — why insecure?” → Deterministic, malleable; needs OAEP (encryption) / PSS (signatures) padding.
D. Auth & protocol failures
Q7. OAuth vs OIDC, and the top JWT pitfalls. Answer: OAuth 2.0 is authorization (delegated access via scoped tokens, no password sharing — use Auth Code + PKCE); OIDC adds authentication on top (an ID token proving who the user is). JWT pitfalls: reject alg:none; prevent algorithm confusion (RS256↔HS256 — pin the expected algorithm); enforce expiry (and short lifetimes since stateless tokens are hard to revoke, with refresh tokens for renewal); don’t store secrets in the payload (base64, not encrypted); always validate signature, alg, issuer (iss), audience (aud), expiry (exp). Counter-ladder:
- “How do you revoke a stateless JWT?” → You largely can’t — keep them short-lived + maintain a revocation/denylist or use opaque reference tokens for sensitive actions.
- “Why is OAuth not authentication?” → An access token says “this app may act on these scopes,” not “this is user X” — that’s what OIDC’s ID token is for.
Q8. Name three ways good crypto gets defeated in practice and the defenses. Answer: (1) Nonce/IV reuse → catastrophic in GCM/CTR; manage nonces, use SIV. (2) Padding oracle in CBC → error/timing leaks decrypt data; use AEAD + constant-time handling. (3) Downgrade attack → forced weak cipher (POODLE/FREAK); disable legacy, use TLS 1.3 (signs the transcript). Bonus: timing side channels → constant-time comparisons; weak randomness → CSPRNG only. Counter-ladder:
- “Why compare MACs/tokens in constant time?” → Early-exit
==leaks how many bytes matched via timing → byte-by-byte forgery. - “How does TLS 1.3 resist downgrade?” → It removed weak options and authenticates the handshake transcript so tampering with negotiation is detected.
E. Worked drill — driving a design end-to-end
Watch every choice be a standard primitive matched to a goal, with the misuse failure pre-empted. Defensive throughout.
Prompt: “Design secure authentication and session handling for a web + mobile app: users log in with passwords, stay logged in across devices, some actions are sensitive, and you must protect against database theft and token abuse.”
1 — Threat-model first (STRIDE). “Spoofing (stolen creds/tokens), Tampering (forged tokens), Info disclosure (DB theft → password/PII leak), Elevation (privilege via token confusion), DoS (login flooding). That checklist drives the controls below.”
2 — Password storage (assume DB theft). “Store passwords with Argon2id + a unique per-user salt, tuned work/memory factors, plus an app-side pepper held in a KMS (not the DB) — so even with a full DB dump, offline cracking is expensive and the pepper is missing. Never reversible encryption. Rate-limit logins and monitor for credential stuffing; offer MFA (prefer WebAuthn/FIDO2 — phishing-resistant).”
3 — Transport. “Everything over TLS 1.3 (forward secrecy, no weak ciphers), HSTS to prevent downgrade to HTTP. Never build the channel myself.”
4 — Sessions across devices. “Issue a short-lived access token + a long-lived refresh token. For the access token I’ll use an HMAC-signed JWT (I’m the only verifier, so symmetric HMAC is fine and fast) with strict validation of alg (pinned), iss, aud, exp and rejection of alg:none. Short lifetime (minutes) bounds the damage of theft since stateless JWTs are hard to revoke. The refresh token is an opaque, random (CSPRNG) reference stored server-side (hashed) so it can be revoked per-device — that’s how ‘log out everywhere’ works and how I cut off a stolen device.”
5 — Sensitive actions. “For high-value operations (change password, payment), require step-up auth / MFA re-challenge and check the action against the server-side session, not just the JWT claims — defense in depth so a leaked access token alone can’t perform them. Use anti-CSRF protection for cookie-based sessions, and bind tokens to the client where possible.”
6 — Token abuse defenses. “Refresh-token rotation with reuse detection: each refresh issues a new refresh token and invalidates the old; if an old one is replayed, treat it as theft and revoke the whole chain. Constant-time comparison for any token/secret check. Tokens carry no secrets in the payload (it’s only base64).”
7 — Keys & secrets. “Signing keys and the pepper live in a KMS/HSM, least-privilege, rotated; nothing sensitive in code, config, or logs. CSPRNG for all tokens, salts, nonces.”
8 — Tradeoffs stated. “I used standard primitives matched to goals — Argon2id (not a fast hash) for storage, HMAC-JWT for cheap self-verification, opaque revocable refresh tokens to solve JWT’s revocation weakness, TLS 1.3 for the channel, FIDO2 for phishing resistance — and pre-empted the known misuse failures (alg:none, algorithm confusion, nonce reuse, timing leaks, downgrade). The cost: server-side refresh-token state (giving up pure statelessness) bought revocation and ‘logout everywhere’ — a worthwhile trade. I rolled nothing myself; I composed vetted building blocks and threat-modeled the flows.”
Template: STRIDE threat-model → password storage assuming breach → TLS 1.3 channel → short access token + revocable opaque refresh → step-up for sensitive actions → rotation/constant-time defenses → KMS-managed rotated keys → state the tradeoff.
F. Consolidated gotchas & traps (rapid fire)
- Never roll your own crypto or protocol.
- AEAD always; never ECB; never reuse a (key, nonce).
- Encryption ≠ integrity (use AEAD / encrypt-then-MAC).
- Hash ≠ password storage (use Argon2/bcrypt/scrypt + salt).
- MAC ≠ signature (no non-repudiation).
- Constant-time comparisons for secrets.
- Forward secrecy via ephemeral ECDH.
- JWT: reject
alg:none, pin algorithm, enforce exp/iss/aud, no secrets in payload. - OAuth = authorization, OIDC = authentication.
- CSPRNG only; secrets in a KMS/HSM, rotated; threat-model with STRIDE.
G. Pros/cons master tables
Primitives
| Primitive | Pros | Cons / misuse |
|---|---|---|
| AEAD (GCM/ChaCha20-Poly1305) | Confidentiality + integrity together | Nonce reuse catastrophic |
| HMAC | Fast, strong integrity (shared key) | No non-repudiation; not password storage |
| Signature (Ed25519/RSA-PSS) | Non-repudiation, third-party verify | Slower; ECDSA nonce reuse leaks key |
| Argon2/bcrypt/scrypt | Slow+salted → resists cracking | Must tune cost (DoS vs strength) |
| HKDF | Clean key separation from a secret | Misused if you skip it and reuse raw secrets |
| ECDH (ephemeral) | Key agreement + forward secrecy | Key validation pitfalls |
| TLS 1.3 | Fast, forward-secret, fewer footguns | Depends on PKI/CA trust + client validation |
Auth mechanisms
| Mechanism | Pros | Cons |
|---|---|---|
| Password + Argon2 + MFA | Familiar; MFA adds strong factor | Phishing (unless FIDO2); user friction |
| OAuth2 + PKCE | Delegated access, no password sharing | Subtle flows; often misimplemented |
| OIDC | Standard authentication/ID token | Complexity on top of OAuth |
| JWT (access) | Stateless, scalable | Hard to revoke; many footguns |
| Opaque refresh token | Revocable, server-controlled | Requires server-side state |
Go deeper (primary sources)
- Diffie & Hellman, “New Directions in Cryptography” (1976).
- Rivest, Shamir, Adleman, “A Method for Obtaining Digital Signatures and Public-Key Cryptosystems” (1978) — RSA.
- Rogaway, “Authenticated-Encryption with Associated-Data” (2002).
- Krawczyk, “Cryptographic Extraction and Key Derivation: The HKDF Scheme” (2010); HKDF — RFC 5869.
- Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.3” (RFC 8446, 2018).
- Goldwasser, Micali, Rackoff, “The Knowledge Complexity of Interactive Proof Systems” (1985) — zero-knowledge.
- Merkle, “A Digital Signature Based on a Conventional Encryption Function” (1987) — Merkle trees.
- Bellare & Rogaway, “Random Oracles are Practical: A Paradigm for Designing Efficient Protocols” (1993).
- Katz & Lindell, Introduction to Modern Cryptography; Boneh & Shoup, A Graduate Course in Applied Cryptography.
- Anderson, Security Engineering.
PART 5 — MAKE IT STICK (Teaching Tutorial)
The references are the map; this is the driving lesson. Crypto sticks when you stop seeing a pile of algorithms and start seeing one question: which goal, which primitive? Plus the handful of misuse failures that cause real breaches. All defensive.
17.1 The one idea: match the primitive to the GOAL
GOAL → PRIMITIVE NOT
confidentiality + integrity → AEAD (AES-GCM) ECB; encryption-without-MAC
integrity (shared key) → HMAC a plain hash
identity / non-repudiation → SIGNATURE (Ed25519) a MAC (no non-repudiation)
derive keys from a secret → HKDF reuse the raw secret
store a PASSWORD → Argon2/bcrypt/scrypt + salt SHA-256 (too fast!)
agree a key over the wire → ECDH (X25519) send a key in plaintext
random key/nonce/salt → CSPRNG rand()/timestamp
That table is 80% of applied crypto. Don’t memorize algorithms — memorize goal → primitive. And rule zero: never roll your own crypto (Kerckhoffs: the algorithm is public; only the key is secret).
17.2 The four cousins people confuse (one line each)
ENCRYPTION → confidentiality (reversible WITH a key)
HASH → one-way fingerprint (integrity; NO key)
MAC → integrity + authenticity (SHARED key; NO non-repudiation)
SIGNATURE → integrity + authenticity + NON-REPUDIATION (PRIVATE key; anyone verifies)
Encryption ≠ integrity — unauthenticated ciphertext is malleable, which is exactly why we use AEAD (encrypt and authenticate together).
17.3 Why passwords aren’t hashed with SHA-256 (the picture)
SHA-256: a GPU tries ~BILLIONS/sec → a stolen hash DB cracks fast.
Argon2/bcrypt/scrypt: DELIBERATELY slow + memory-hard → ~thousands/sec → infeasible.
+ per-user SALT → identical passwords get different hashes → kills rainbow tables.
Password storage wants the opposite of a fast hash. Slow + salted (+ optionally a KMS-held pepper).
17.4 The misuse failures that actually break systems
NONCE REUSE (AES-GCM) → leaks the auth key → forgeries. Never reuse (key,nonce).
PADDING ORACLE (CBC) → error/timing leaks decrypt data. → use AEAD.
DOWNGRADE attack → forced weak cipher. → disable legacy; TLS 1.3 removed them.
TIMING side channel → secret-dependent compare leaks. → constant-time compare.
JWT: alg:none / RS256↔HS256 confusion / no expiry / secrets in payload → validate strictly.
Real breaches are almost never “the math broke” — they’re misuse of good primitives. Knowing these five is the senior signal.
17.5 Forward secrecy in one picture
No forward secrecy: one long-term key decrypts ALL past recorded traffic if stolen later.
Forward secrecy: EPHEMERAL key per session, then discarded →
stealing the long-term key later reveals NOTHING about past sessions.
(TLS 1.3 mandates ephemeral ECDH.)
17.6 Analogies that stick
- AEAD = a tamper-evident sealed envelope — hides the letter and shows if anyone opened it. (Plain encryption hides but doesn’t reveal tampering.)
- MAC vs signature = a shared secret handshake vs a notarized signature — the handshake proves “one of us,” the notary proves “specifically you” (and you can’t deny it).
- Forward secrecy = using a new burner phone each call — stealing today’s phone tells you nothing about yesterday’s calls.
- Salt = adding a random word to everyone’s password before hashing so two identical passwords don’t look alike.
17.7 Misconceptions → corrections
| You might think… | Actually… |
|---|---|
| “A secret algorithm is more secure.” | Kerckhoffs: security rests on the key; use public, vetted algorithms. |
| “Encryption gives integrity.” | No — use AEAD (encrypt-then-authenticate). |
| “Hash the password (SHA-256).” | Too fast; use Argon2/bcrypt/scrypt + salt. |
| “A MAC gives non-repudiation.” | No — shared key; use a signature. |
| “OAuth authenticates the user.” | OAuth = authorization; OIDC = authentication. |
| “JWTs are easy and safe.” | alg:none, algorithm confusion, no expiry, secrets-in-payload — validate strictly. |
17.8 Explain it back (Feynman)
- Give the goal→primitive for: encrypt data, store a password, prove identity. [17.1]
- Encryption vs hash vs MAC vs signature — one line each. [17.2]
- Why not SHA-256 for passwords? [17.3]
- Name three misuse failures and their fixes. [17.4]
- What does forward secrecy protect, and how? [17.5]
17.9 Flashcards (cover the right column)
| Prompt | Answer |
|---|---|
| Rule zero | Never roll your own crypto |
| Encrypt data | AEAD (AES-GCM / ChaCha20-Poly1305) |
| Integrity (shared key) | HMAC |
| Identity / non-repudiation | Signature (Ed25519) |
| Store password | Argon2/bcrypt/scrypt + salt |
| Encryption gives integrity? | No → use AEAD |
| Nonce reuse (GCM) | Catastrophic — never reuse (key,nonce) |
| Forward secrecy | Ephemeral keys → past traffic stays safe |
| OAuth vs OIDC | Authorization vs authentication |
| JWT traps | alg:none, RS256↔HS256, no exp, secrets in payload |
17.10 The 60-second recall
“Never roll your own crypto — security rests on the key, not the algorithm. The whole field is matching a goal to a vetted primitive: confidentiality plus integrity is AEAD (never ECB, never encryption without authentication); integrity with a shared key is HMAC; identity and non-repudiation is a signature; deriving keys is HKDF; storing a password is a slow, salted Argon2/bcrypt/scrypt, never a fast hash; agreeing a key is ECDH; and all randomness comes from a CSPRNG. Encryption is not integrity, a MAC is not a signature, and a hash is not password storage. Real breaks are misuse — nonce reuse, padding oracles, downgrade attacks, timing leaks, and JWT pitfalls like alg:none — so use AEAD, constant-time comparisons, TLS 1.3, and strict token validation. Use ephemeral key exchange for forward secrecy, and remember OAuth is authorization while OIDC is authentication.”
Frequently asked questions
Why should you never roll your own crypto?
By Kerckhoffs’s principle, a system must be secure even if everything except the key is public, so your algorithm will be scrutinized. Homegrown crypto and protocols almost always have subtle flaws in padding, timing, or nonce handling that vetted, peer-reviewed primitives and libraries have already fixed. Use AES-GCM, ChaCha20-Poly1305, TLS 1.3, and libsodium.
What’s the difference between encryption, hashing, MAC, and signatures?
Encryption provides confidentiality (reversible with a key). A hash provides a one-way fingerprint for integrity. A MAC provides integrity and authenticity with a shared key but no non-repudiation. A digital signature provides integrity, authenticity, and non-repudiation with a private key that third parties can verify.
How should passwords be stored?
With a deliberately slow, memory-hard, salted key-derivation function such as Argon2id, bcrypt, or scrypt, using a unique per-user salt. Never store passwords with a fast hash like SHA-256, because GPUs can try billions of guesses per second, and never use reversible encryption.
What is forward secrecy?
Forward secrecy uses ephemeral key-exchange keys per session, so that even if a long-term private key is later compromised, past recorded sessions remain secret — the ephemeral keys were discarded. TLS 1.3 mandates forward secrecy using ephemeral elliptic-curve Diffie-Hellman.
What’s the difference between OAuth and OIDC?
OAuth 2.0 is an authorization framework: a user grants a third-party app scoped access to their resources via tokens, without sharing a password. OpenID Connect (OIDC) adds an authentication layer on top, issuing an ID token that proves who the user is. In short, OAuth is authorization and OIDC is authentication.
