Index · How it works
8 min readHow it works
The threat model has two halves: an attacker on the wire (intercepting or modifying traffic — a man-in-the-middle on shared Wi-Fi, a malicious proxy, a hostile network) and an attacker with the data (a stolen database dump, a leaked backup, an exfiltrated disk image, an insider). Confidentiality protects against reading the data; integrity protects against tampering with it; authenticity proves who sent it. Good cryptographic design addresses all three, and A02 failures usually come from skipping one or using a primitive that only provides some of them.
Data in transit — TLS, HTTPS, HSTS
Data crossing a network must be encrypted in transit with TLS (the protocol behind HTTPS). Key points:
- Use TLS 1.2 or 1.3; disable everything older. SSL 2.0/3.0 and TLS 1.0/1.1 are broken or deprecated (POODLE, BEAST, etc.). TLS 1.3 is the current best — it removes legacy ciphers, makes forward secrecy mandatory, and is faster (1-RTT handshake, 0-RTT resumption).
- HTTPS everywhere. Encrypt all traffic, not just the login page. Mixed content (HTTPS page loading HTTP assets) undermines the guarantee.
- HSTS (
Strict-Transport-Securityheader) tells the browser to only ever connect over HTTPS for a given duration, defeating SSL-stripping downgrade attacks. AddincludeSubDomainsand, for the strongest form, submit to the HSTS preload list so the first request is HTTPS too. - Certificate validation. Clients must verify the server certificate's chain of trust, hostname, expiry, and revocation. Disabling validation (
verify=False,rejectUnauthorized: false, "trust all certs") to "make it work" silently destroys the security of TLS — any MITM can present a self-signed cert. - Forward secrecy (ephemeral Diffie-Hellman, ECDHE) means a future compromise of the server's private key cannot decrypt past recorded sessions. Prefer cipher suites that provide it.
- Downgrade attacks. An active attacker tries to force the weakest mutually supported protocol/cipher. Defenses: drop weak protocols/ciphers server-side, TLS 1.3's downgrade-protection signaling, and HSTS.
- Certificate pinning (binding a client to a specific cert or public key) defends high-value mobile/native clients against a rogue or compromised CA. It is powerful but operationally risky — a bad rotation can brick the app — so it's reserved for cases where the threat justifies it, not the default for web apps.
Data at rest — disk, database, field-level
Encrypting "at rest" can mean several layers, and they protect against different threats:
- Full-disk / volume encryption (BitLocker, LUKS, cloud EBS encryption) protects against physical theft of the disk. It does not protect a running system or a logical SQL dump — the OS sees plaintext.
- Database / transparent data encryption (TDE) encrypts the data files. Again, a logged-in attacker or SQL injection sees decrypted rows.
- Field-level / application-level encryption encrypts specific sensitive columns (SSNs, card numbers, tokens) inside the application before they hit the database. This survives a DB dump and limits blast radius — it's the strongest but requires real key management.
- Use authenticated encryption. AES-256-GCM (or ChaCha20-Poly1305, or AES-GCM-SIV) provides confidentiality and integrity in one step — tampered ciphertext fails to decrypt. Plain AES-CBC without a separate MAC is malleable and prone to padding-oracle attacks.
Envelope encryption
For data at rest at scale you rarely encrypt everything with one master key. Envelope encryption generates a unique data encryption key (DEK) per object/record, encrypts the data with the DEK, then encrypts (wraps) the DEK with a key encryption key (KEK) held in a KMS/HSM. You store the wrapped DEK next to the ciphertext. This lets you rotate the KEK cheaply (re-wrap DEKs, not re-encrypt terabytes), keep the KEK in hardware, and limit how much data any single key protects.
Hashing vs encryption vs encoding
This distinction is a near-guaranteed interview question, and conflating them is a real source of vulnerabilities:
- Encoding (Base64, URL-encoding, hex) is a reversible transformation with no key, for safe transport/representation of data — not a security control. Anyone can decode Base64. Treating Base64 as "encryption" is a classic failure.
- Encryption is a reversible transformation with a key; without the key you cannot recover the plaintext. Used for confidentiality of data you need to read back later.
- Hashing is a one-way function: you cannot recover the input from the output. Used for integrity checks and for storing values you only ever need to compare (passwords). A good cryptographic hash is collision- and preimage-resistant.
Password hashing vs general hashing
Not all hashing is the same, and this is the second classic interview trap:
- General-purpose hashes (SHA-256, SHA-3, BLAKE2) are built to be fast — ideal for file integrity, HMAC, digital signatures, content addressing.
- Password hashing needs the opposite: slow and memory-hard, so a stolen database can't be brute-forced at billions of guesses per second. Use Argon2id (first choice), scrypt, or bcrypt, with a tunable cost factor.
- Salt: a unique random value per password, stored with the hash, that defeats precomputed rainbow tables and ensures two identical passwords hash differently. Modern password-hashing functions generate and embed the salt for you.
- Pepper: a secret mixed into every hash and kept outside the database (app config/KMS/HSM), so a DB-only leak still leaves hashes protected. It supplements — never replaces — per-password salts. (See the Authentication module for full depth.)
Symmetric vs asymmetric crypto
- Symmetric (one shared secret for encrypt and decrypt): AES, ChaCha20. Fast and used for bulk data. The challenge is distributing the shared key securely.
- Asymmetric / public-key (a public key encrypts/verifies, a private key decrypts/signs): RSA, ECC (ECDSA/EdDSA for signatures, ECDH for key agreement). Solves key distribution and enables digital signatures, but is far slower.
- In practice you combine them. TLS uses asymmetric crypto to authenticate the server and agree on a key, then switches to fast symmetric crypto (AES-GCM) for the actual data — exactly the hybrid pattern of envelope encryption. Rule of thumb: asymmetric to establish trust / exchange keys, symmetric to move data. Prefer ECC over RSA for new systems (smaller keys, equivalent strength: a 256-bit ECC key ≈ a 3072-bit RSA key).
Key management
Key management is where most crypto actually fails — the algorithm is fine, the handling of the key is not.
- Never hardcode keys in source code, config files committed to git, container images, or client-side code. A key in a repo is a leaked key.
- Use a dedicated key store: a cloud KMS (AWS KMS, GCP KMS, Azure Key Vault), an HSM (hardware security module — keys never leave tamper-resistant hardware), or HashiCorp Vault. These give you access control, audit logs, and rotation.
- Rotate keys on a schedule and after any suspected compromise. Envelope encryption makes rotation cheap.
- Separate keys per purpose / environment / tenant. One key for everything means one compromise exposes everything; it also makes rotation impossible without breaking unrelated data.
- Least privilege: services get only the keys they need, decrypt operations are logged, and ideally the app calls the KMS to decrypt rather than ever holding the master key in memory.
Randomness — CSPRNG and IV/nonce uniqueness
Cryptography depends on unpredictable values, and ordinary random functions are predictable.
- Use a CSPRNG (cryptographically secure pseudo-random number generator) for every security value: keys, IVs, nonces, salts, session IDs, password-reset and API tokens, OAuth state. Use
crypto.randomBytes/crypto.getRandomValues(Node/browser),secrets/os.urandom(Python),RandomNumberGenerator/RandomNumberGenerator.GetBytes(.NET),SecureRandom(Java). NeverMath.random(),rand(), or a seededRandom— they're statistically predictable and an attacker can reconstruct the sequence. - IV / nonce uniqueness. An initialization vector or nonce must be unique per encryption under a given key (and for some modes also unpredictable). For AES-GCM, reusing a nonce with the same key is catastrophic — it leaks the authentication key and lets an attacker forge messages. Generate a fresh random nonce per message, or use a guaranteed-unique counter; never a fixed/zero IV.
Common mistakes
A checklist of the failures interviewers love to probe:
- ECB mode — encrypts identical plaintext blocks to identical ciphertext blocks, leaking structure (the infamous "ECB penguin"). Never use ECB; use an authenticated mode like GCM.
- Reused IV/nonce — breaks the security of CTR/GCM/CBC; especially fatal for GCM.
- Hardcoded secrets — keys, passwords, API tokens committed to code or images.
- Rolling your own crypto — custom ciphers, custom protocols, or naive "encryption" like XOR-with-a-string. Use audited libraries (libsodium, the platform crypto provider) and standard protocols.
- Weak / obsolete algorithms — MD5 and SHA-1 (collisions, broken for signatures), DES/3DES (small key/block), RC4 (biased keystream). Replace with SHA-256+/SHA-3, AES, ChaCha20.
- Fast hash for passwords — SHA-256 on a password instead of Argon2id/bcrypt.
- Encryption without integrity — AES-CBC with no MAC, enabling tampering and padding-oracle attacks. Prefer authenticated encryption.
- Disabled certificate validation —
verify=False/"trust all certs", silently allowing MITM. - No transport encryption at all — sensitive data over plain HTTP, internal services talking unencrypted, secrets in URLs/query strings (which land in logs).
- Missing cert pinning where the threat needs it — high-value native/mobile clients that should pin but don't (and, conversely, web apps that try to pin and shouldn't).
Secrets management
Encryption keys are one kind of secret; apps also hold DB passwords, API keys, OAuth client secrets, and signing keys. Manage them the same disciplined way: keep them out of source control (use a secrets manager — Vault, AWS Secrets Manager, sealed/sealed-secrets, or at minimum environment variables injected at runtime), rotate them, scope them per service and environment, audit access, and scan repos and CI for leaked credentials. A leaked secret is functionally identical to a leaked key — it bypasses the cryptography entirely.