What Is a Hash Function?
A cryptographic hash function takes an input of any length and produces a fixed-length output (the hash or digest). Three properties define a good hash function:
- **Deterministic** — the same input always produces the same output
- **One-way** — you cannot reverse the hash to recover the input
- **Collision-resistant** — it should be computationally infeasible to find two different inputs that produce the same hash
Different algorithms offer different trade-offs between speed, collision resistance, and resistance to brute-force attacks.
MD5 (128-bit output)
MD5 was designed in 1991 and was the standard hashing algorithm for most of the 1990s and 2000s. It produces a 128-bit (32 hex character) hash. The problem: collision attacks against MD5 were demonstrated in 2004, and practical attacks followed. You can generate an MD5 collision on modern hardware in under a second.
**Still acceptable:** Checksums for file integrity where security doesn't matter — verifying a downloaded file matches its advertised hash when the threat model isn't adversarial substitution. Fast, widely supported.
**Never use for:** Passwords, signatures, certificates, or anything where an attacker might try to forge a hash.
MD5("hello") = 5d41402abc4b2a76b9719d911017c592
SHA-256 (256-bit output)
SHA-256 is part of the SHA-2 family designed by the NSA and published in 2001. It produces a 256-bit (64 hex character) output. No practical collision attacks exist. SHA-256 is the current standard for digital signatures, TLS certificates, code signing, and integrity checking.
**Use for:** File integrity verification, HMAC authentication, digital signatures, blockchain (Bitcoin uses SHA-256), API request signing, anything that needs a secure checksum.
**Not for:** Password storage — SHA-256 is designed to be fast, and fast means a GPU can compute billions of hashes per second, making brute-force attacks against password hashes feasible.
SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
HMAC-SHA256
HMAC (Hash-based Message Authentication Code) uses a secret key combined with SHA-256 to produce a hash. Unlike a plain SHA-256 hash, an HMAC can't be forged without knowing the key. This is what JWTs use for the signature portion — the header and payload are HMAC-signed with a server secret, so the client can't tamper with the token.
Bcrypt (output includes salt and cost factor)
Bcrypt was designed in 1999 specifically for password hashing. Its defining feature is a configurable work factor (also called cost or rounds). Doubling the work factor doubles the computation time. This means you can tune bcrypt to be slower as hardware gets faster, keeping brute-force attacks impractical.
Bcrypt output looks like: $2b$12$... — the $12$ is the work factor (12 rounds = 2^12 iterations). A modern server takes ~100-300ms to verify a bcrypt hash at factor 12, which is acceptable for login but makes brute-force impractical.
**Use for:** Storing user passwords in a database. Always and only.
**Not for:** File integrity, signatures, or anything that needs to be fast.
Argon2 (winner of the Password Hashing Competition)
Argon2 won the 2015 Password Hashing Competition and is the current recommended algorithm for password storage. It has three variants: Argon2i (side-channel resistant), Argon2d (fastest), and Argon2id (recommended for passwords). Unlike bcrypt, Argon2 is configurable for memory usage as well as time, making GPU and ASIC attacks significantly harder.
If you're starting a new project, use Argon2id over bcrypt.
Quick Reference
| Algorithm | Output size | Speed | Use for |
|---|---|---|---|
| MD5 | 128-bit | Very fast | Legacy checksums only |
| SHA-256 | 256-bit | Fast | Signatures, HMAC, file integrity |
| HMAC-SHA256 | 256-bit | Fast | API authentication, JWTs |
| Bcrypt | 60 chars | Slow (tunable) | Password storage |
| Argon2id | Variable | Slow + memory-hard | Password storage (preferred) |
One Rule to Remember
Fast = good for most purposes. Fast = dangerous for passwords. The entire goal of bcrypt and Argon2 is to be slow — that's the feature, not a bug. Never store passwords with MD5, SHA-1, or SHA-256 alone.