New The 2026 Continuous Validation Methodology Paper is now available. Read the paper →

Cryptographic Hashing — Reference.

Practitioner-level hashing reference: when collision resistance matters, when length-extension bites, and what to pick today.

Use-case → choice

  • Password storage. Argon2id (preferred), bcrypt (acceptable), scrypt (acceptable). Never SHA-256/SHA-512 directly, never MD5. OWASP-recommended Argon2id params (2024): t=2, m=19 MiB, p=1 for interactive; t=3, m=64 MiB, p=4 for higher-stakes. Tune until a single hash takes ~100 ms on your hardware.
  • Generic content addressing. SHA-256. Fast enough, ubiquitous library support, no known practical break. BLAKE3 if performance matters more than ecosystem.
  • File-equality / dedup where attacker cannot supply files. BLAKE3 or xxHash. Massive throughput; collision resistance not required.
  • Authenticated message integrity. HMAC-SHA-256 if you must use a hash. Better: AEAD (AES-GCM, ChaCha20-Poly1305) which gives encryption + integrity together. Don't hand-roll MAC by concatenating key and message.
  • Digital signatures. SHA-256 with RSA-PSS or ECDSA P-256 or Ed25519. Avoid SHA-1, MD5 (no longer collision-resistant — chosen-prefix collisions demonstrated).
  • Key derivation from low-entropy input. HKDF (extract + expand) using SHA-256. Not bcrypt/Argon2 (those are for password verification, not key derivation).
  • Commitment schemes / Merkle trees. SHA-256 (Bitcoin) or BLAKE3 / Poseidon (zk-friendly).
  • Random ID generation. Don't hash, just use CSPRNG bytes encoded base32. 16 bytes = 128 bits = safe.

Length-extension attack

  • What it is. Given H(key || message) and length of key, attacker computes H(key || message || padding || extra) without knowing key.
  • Vulnerable. SHA-1, SHA-256, SHA-512 (any Merkle-Damgård construction).
  • Not vulnerable. SHA-3 (Keccak sponge), BLAKE2, BLAKE3, HMAC over any hash.
  • Fix. Use HMAC: HMAC(key, message). Library will do it correctly. Or use AEAD.

Common mistakes

  • MD5 for "non-security" uses. Then someone uses the result for cache key, then for ETag, then for security boundary. Use BLAKE3 or SHA-256 instead — same convenience, no future foot-gun.
  • SHA-256 for password storage. GPU cracking: 10 GH/s. Argon2id: ~10 H/s/GB. 9 orders of magnitude difference.
  • Truncating a hash to "save space". 64-bit truncated SHA-256 has 32-bit collision resistance via birthday bound — practical to attack.
  • Salt reuse / no salt. Reused salt = rainbow-table attack. Per-user random salt always.
  • Comparison via == on hashes used for auth. Timing leak. Use constant-time compare (crypto.timingSafeEqual, hmac.compare_digest).
  • Custom MAC construction. "H(key || msg)" — vulnerable to length extension. "H(msg || key)" — collision on H lets you forge. Just use HMAC.

Migration paths

  • MD5 password hashes →. On next login, rehash with Argon2id and store. Old MD5 hash deletable after grace window where users have logged in.
  • SHA-1 signatures →. Re-sign with SHA-256. Verify both during transition; reject SHA-1 after cut-off.
  • HMAC-SHA-1 (e.g., legacy AWS Sig v2) →. HMAC-SHA-256 (Sig v4).
  • bcrypt approaching cost-factor ceiling →. Argon2id. Wrap during user login.
Rule of thumbFor 99% of use-cases the decision tree is: passwords → Argon2id; integrity with key → HMAC-SHA-256 or AEAD; integrity without key → SHA-256 or BLAKE3; random IDs → CSPRNG, not a hash. Almost everything else is a custom mistake.

From reference to evidence

Run this against your own environment.