Filter concepts by levelShowing all levels.

System Design · Encryption

Encryption

Two protections for two windows in data's life, why a password hash has no key at all, and who gets to hold the keys that remain

  • TLS + at restin motion and at standstill — both required
  • Hash, don't encryptpasswords must never be recoverable
  • KMS/HSMraw key material never touches app code
  • Separation of dutiesdecrypt access and audit control, different roles

1.Encryption in transit (TLS) vs encryption at rest

Encryption in transit (TLS) protects data while it moves across a network; encryption at rest protects data while it sits on a disk, in a backup, or in a database file. You need both — TLS does nothing once a request lands and the data is written to storage.

Key features

  • TLS protects data between two endpoints (client-to-server, service-to-service) — it does not protect the data once it is written to disk at either end
  • Encryption at rest protects stored data — database files, backups, snapshots, log files — from anyone who gets the raw storage medium without going through the application
  • A stolen laptop, an exposed S3 bucket, or a leaked database backup all bypass TLS entirely — TLS was never in the request path for those
  • TLS 1.3 (RFC 8446) is the current baseline; TLS 1.0 and 1.1 are deprecated and should be rejected by any service that still accepts them
  • At-rest encryption is usually transparent to the application (disk- or database-level, e.g. AES-256) — the app reads and writes plaintext and the storage layer handles the encrypt/decrypt step

What each protection actually covers

What each protection actually covers
ProtectionCoversDoes not cover
TLS (in transit)Data on the network between client and server, or between two servicesData already written to disk, a backup file, or a database snapshot
Encryption at restData on disk, in backups, in snapshots, in log filesData currently being read or written by an authorized, already-connected process
Two protections, two different attack scenarios

TLS in transit

  • Stops an attacker sniffing traffic on the network path
  • Active only while a request is moving between endpoints
  • Useless against a stolen disk or leaked backup file

Encryption at rest

  • Stops an attacker who obtains the raw storage medium
  • Active only while data is sitting still, not moving
  • Useless against traffic sniffed off an unencrypted connection
  • TLS in transit
    • Stops an attacker sniffing traffic on the network path
    • Active only while a request is moving between endpoints
    • Useless against a stolen disk or leaked backup file
  • Encryption at rest
    • Stops an attacker who obtains the raw storage medium
    • Active only while data is sitting still, not moving
    • Useless against traffic sniffed off an unencrypted connection

Command

text
// In transit: negotiated per connection
client --TLS 1.3 handshake--> server
       <---- encrypted channel ---->

// At rest: applied to the storage layer, not the request
disk / database volume: AES-256 encryption
backup snapshot: AES-256 encryption
(application reads/writes plaintext; storage layer
 handles encrypt/decrypt transparently)

TLS protects data in motion; encryption at rest protects data at standstill. A system needs both, because a stolen disk or leaked backup never touches the network path TLS covers.

2.Password hashing: why it is not encryption

A password hash is one-way — there is no key that turns it back into the original password, even for the system that created it. Encryption is two-way by design — whoever holds the key can reverse it. Passwords must be hashed, never encrypted, because nothing should ever be able to recover the original.

Key features

  • A cryptographic hash is one-way: there is no key, secret, or process that reverses it back to the input — this is the property that makes it correct for passwords
  • Encryption is two-way by design: it exists so an authorized holder of the key CAN recover the original — the opposite property from what a password needs
  • Purpose-built password hashes (bcrypt, scrypt, Argon2) are deliberately slow and memory-hard, which makes brute-forcing every possible password prohibitively expensive
  • General-purpose hashes (MD5, SHA-256) are built for speed — billions of hashes per second on commodity GPUs — which makes them fast for an attacker to brute-force, not just for you to verify
  • A per-password random salt (built into bcrypt/scrypt/Argon2 by default) stops an attacker from using one precomputed rainbow table against every stored hash at once

Password hashing algorithms and what to set

Password hashing algorithms and what to set
AlgorithmTunable cost factorNotes
bcryptwork factor (rounds), commonly 10-12Widest support; capped at 72-byte input, pre-hash longer inputs if needed
scryptCPU/memory cost + block sizeMemory-hard — also expensive to brute-force on custom ASIC/GPU hardware
Argon2idmemory, iterations, parallelismWinner of the 2015 Password Hashing Competition; OWASP's current default recommendation
Hashing (one-way) vs encryption (two-way) for password storage

Hashing — correct for passwords

  • No key exists that reverses a hash back to the password
  • Verification re-hashes the login attempt and compares
  • A stolen hash still requires brute force to recover anything

Encryption — wrong for passwords

  • A key can decrypt ciphertext back to the exact original
  • Verification would mean decrypting and comparing plaintext
  • A stolen key (or the system itself) recovers every password instantly
  • Hashing — correct for passwords
    • No key exists that reverses a hash back to the password
    • Verification re-hashes the login attempt and compares
    • A stolen hash still requires brute force to recover anything
  • Encryption — wrong for passwords
    • A key can decrypt ciphertext back to the exact original
    • Verification would mean decrypting and comparing plaintext
    • A stolen key (or the system itself) recovers every password instantly

Command

python
import bcrypt

# hash once, at signup -- salt is generated
# and stored inside the returned hash itself
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
# store `hashed` (bytes) in the database

# verify at login -- never decrypt, always re-hash and compare
bcrypt.checkpw(login_attempt.encode(), hashed)  # -> True / False

Hashing is one-way and correct for passwords; encryption is two-way and wrong for passwords, no matter how strong the cipher. Use a slow, purpose-built hash (bcrypt, scrypt, Argon2) — a fast general-purpose hash like SHA-256 makes brute force cheap.

3.Encryption keys: KMS/HSM, rotation and separation of duties

A Key Management Service (KMS) stores and controls access to encryption keys so application code never touches raw key material. Keys get rotated on a schedule to limit how much damage a leaked key can do, and separation of duties means no single person can both decrypt data and hide that they did it.

Key features

  • A KMS (e.g. AWS KMS, Google Cloud KMS) manages keys as a service — applications call an API to encrypt/decrypt or to get a data key, and never see or store the underlying key material directly
  • An HSM (Hardware Security Module) is dedicated tamper-resistant hardware that generates and stores keys such that they cannot be exported in plaintext, even by administrators — used directly, or as the backing layer under a KMS
  • Envelope encryption is the common pattern: a KMS-held master key encrypts a per-object "data key," and the data key (not the master key) encrypts the actual data — this avoids sending bulk data through the KMS itself
  • Key rotation replaces a key on a schedule (e.g. annually, or immediately after suspected compromise) so a leaked or aging key has a bounded window of usefulness to an attacker
  • Separation of duties means the person or role that can decrypt data is not the same person or role that controls audit logging of decrypt events — one compromised or malicious actor should not be able to both act and erase the record of acting

KMS vs HSM — where each one fits

KMS vs HSM — where each one fits
ConceptWhat it isWhen you reach for it
KMSManaged service API for creating, rotating, and using encryption keysDefault choice for application-level encryption — S3/database encryption keys, envelope encryption, secrets
HSMDedicated tamper-resistant hardware holding key materialRegulatory requirements (e.g. PCI-DSS, FIPS 140-2) or the highest-sensitivity keys, often as the layer backing a KMS
Key rotationScheduled or event-triggered key replacementEvery long-lived key — limits the blast radius of a leak that has not yet been discovered
Separation of dutiesNo single role can both decrypt and control the audit trail of decryptionAny system where insider risk or a single compromised credential must not go undetected
Key rotation without breaking already-encrypted data
decrypts

Key v1

marked rotated, kept for decrypt

Data encrypted under v1

still decryptable via v1

  • Key v1 — marked rotated, kept for decrypt
    • leads to Data encrypted under v1 (decrypts)
  • Key v2 — used for all new encryption
    • leads to New data (encrypts)
  • Data encrypted under v1 — still decryptable via v1
  • New data — encrypted under v2

Command

text
// Envelope encryption with a KMS
1. app calls KMS.GenerateDataKey(masterKeyId)
   -> KMS returns { plaintextKey, encryptedKey }
2. app encrypts the actual data with plaintextKey
   (locally, never sends bulk data to the KMS)
3. app discards plaintextKey from memory,
   stores encryptedKey alongside the data
4. to decrypt later: app calls
   KMS.Decrypt(encryptedKey) -> plaintextKey
   (only succeeds if the caller's IAM role
   is authorized to use masterKeyId)

A KMS/HSM keeps raw key material out of application code and enforces who can use a key, not just who can see it. Rotate keys on a schedule to bound a leak's usefulness, and keep decrypt access separate from audit-log control so no single role can act and erase the evidence.

Remember

  • TLS protects data in motion; encryption at rest protects data at standstill — a system needs both, and neither implies the other.
  • Hashing is one-way and correct for passwords; encryption is two-way and wrong for passwords, no matter how strong the cipher.
  • A fast general-purpose hash (MD5/SHA-256) makes brute force cheap — use a slow, purpose-built one (bcrypt, scrypt, Argon2) instead.
  • A KMS/HSM keeps raw key material out of app code; rotate keys on a schedule; keep decrypt access and audit-log control on separate roles.

Pro tip

  • Envelope encryption (a KMS-held master key encrypts a per-object data key) avoids sending bulk data through the KMS itself.
  • Rotate keys on a schedule even with no known compromise — it bounds how useful a leaked-but-undiscovered key can be to an attacker.

Next up

  • Multi-tenancy

Sources

  • OWASP Password Storage Cheat Sheet — cheatsheetseries.owasp.org
  • Checked 2026-08-25

Spotted a mistake on this page? Tell us.