# Hash Algorithms Comparison
A cryptographic hash turns arbitrary input into a fixed-size fingerprint. Not all hash functions are interchangeable — some are broken for security use but still fine for checksums, and "fast" is a security weakness for password hashing specifically. This sheet compares the common algorithms and says where each one actually belongs.
| Algorithm | Output size | Hex length | Relative speed | Status |
|---|---|---|---|---|
| MD5 | 128 bits | 32 chars | Very fast | **Broken** — collisions practical since 2004 |
| SHA-1 | 160 bits | 40 chars | Fast | **Broken** — collisions demonstrated (SHAttered, 2017) |
| SHA-256 | 256 bits | 64 chars | Moderate | Secure, industry standard |
| SHA-512 | 512 bits | 128 chars | Moderate (faster than SHA-256 on 64-bit CPUs) | Secure |
| SHA-3-256 | 256 bits | 64 chars | Slower than SHA-2 in software | Secure, different internal design (Keccak) than SHA-2 |
| BLAKE2b | Up to 512 bits (configurable) | up to 128 chars | Faster than SHA-2, faster than MD5 in many cases | Secure |
| BLAKE3 | 256 bits default (extendable) | 64 chars | Faster than BLAKE2, parallelizable | Secure |
| Use case | Right tool | Wrong tool |
|---|---|---|
| File integrity checksum | SHA-256, BLAKE3 | MD5 (fine only for accidental-corruption checks, not tamper detection) |
| Git object IDs | SHA-1 (the default everywhere, including GitHub/GitLab) | SHA-256 repos are still an opt-in experimental git feature, not hosted in production by major forges |
| Password storage | **bcrypt, scrypt, or Argon2** — never a raw hash | SHA-256, MD5, SHA-512 alone |
| Message authentication | HMAC-SHA256 | A plain hash with no key |
| Digital signatures / TLS certs | SHA-256 or stronger | MD5, SHA-1 (both rejected by modern CAs and browsers) |
| Deduplication / content-addressing | SHA-256, BLAKE3 | MD5 (collision risk means two different files could map to the same key) |
const crypto = require('crypto');
crypto.createHash('sha256').update('hello world').digest('hex');
// "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
crypto.createHmac('sha256', 'secret-key').update(payload).digest('hex');
Plain sha256(secret + payload) is not a substitute for HMAC — naive concatenation is vulnerable to length-extension attacks on some hash constructions; HMAC's nested construction is specifically designed to avoid that.
crypto.timingSafeEqual(Buffer.from(hashA), Buffer.from(hashB));
A plain === string comparison on secrets/HMACs can leak timing information about how many leading bytes matched — timingSafeEqual compares in constant time.
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12); // cost factor 12
await bcrypt.compare(password, hash);
Password hashing needs to be deliberately slow and salted per-record — the opposite of what SHA-256/MD5 are optimized for.
HS256) or an RSA/EC signature — inspect which algorithm a token actually uses.