Chapter 1 · Practice 3 of 4
Know when to hash, encrypt, MAC or sign
Why it matters
Many bugs come from using the right algorithm for the wrong job, such as hashing a webhook body when you needed to prove who sent it. Pick by the property you need:
| You need | Use | Key | Example |
|---|---|---|---|
| A fingerprint anyone can recompute | hash (SHA-256, SHA-3, BLAKE2) | none | file checksums, content addressing |
| Secrecy and tamper detection | AEAD encryption (AES-GCM, ChaCha20-Poly1305) | shared secret key | encrypting a field or a file |
| Proof a message came from someone holding a shared key | MAC (HMAC-SHA256) | shared secret key | webhook signatures, signed cookies |
| Proof anyone can check, without sharing a secret | digital signature (Ed25519, ECDSA, ML-DSA) | private key signs, public key verifies | release artifacts, JWTs verified by many services |
| Storing a password you only need to verify | password hash (Argon2id) | none, plus a salt | user passwords |
A few rules fall out of the table:
- A plain hash does not authenticate. Anyone can change the message and recompute it.
- Encryption without authentication (AES-CBC or AES-CTR alone) lets attackers flip bits in the plaintext. Use an AEAD.
- A MAC needs both sides to share the key, so any party that verifies can also forge. When many services verify, use signatures.
- Passwords are not encrypted. OWASP's storage cheat sheet says passwords should not use reversible encryption. Sefism's Authentication Best Practices guide covers Argon2id parameters, so this guide does not repeat them.
Avoid
- A bare SHA-256 of the body as a webhook "signature"
- Encrypting passwords so they can be decrypted later
- AES-CBC or AES-CTR without a MAC