What Is a Hash Function?
A cryptographic hash function takes any input and produces a fixed-length output (the "hash" or "digest"). It has three core properties:
- Deterministic: Same input always produces the same output
- One-way: You cannot reverse a hash to get the input
- Avalanche effect: A tiny input change completely changes the output
SHA-256("hello") → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("Hello") → 185f8db32921bd46d35cc2e13b6a97d7ffc4bce5c5ffbcab3b0b4f7de59e8d7 (completely different!)
The Major Hash Algorithms
MD5 (Message Digest 5)
- Output: 128-bit (32 hex chars)
- Speed: Very fast
- Security: Broken — collision vulnerabilities discovered in 1996, practically broken by 2004
Do not use MD5 for any security purpose. Attackers can craft two different files with the same MD5 hash. Rainbow table databases cover billions of common passwords.
✅ Still OK for: checksums where collision resistance doesn't matter (verifying a download hasn't been corrupted by a network error — not by an attacker), non-security file deduplication.
SHA-1 (Secure Hash Algorithm 1)
- Output: 160-bit (40 hex chars)
- Speed: Fast
- Security: Deprecated — first practical collision demonstrated in 2017 (Google's SHAttered attack)
Most certificate authorities stopped issuing SHA-1 certificates in 2016. Git still uses SHA-1 internally for object IDs (with mitigations) and is migrating to SHA-256.
✅ Still OK for: legacy Git object IDs (not user-facing security), some non-critical checksums.
SHA-256 / SHA-2 Family
- Output: 256-bit (64 hex chars) for SHA-256; also SHA-384, SHA-512
- Speed: Fast (hardware-accelerated on modern CPUs)
- Security: Strong — no known practical attacks
SHA-256 is the current industry standard for:
- Digital signatures (SSL/TLS certificates)
- HMAC message authentication
- Data integrity verification
- Blockchain (Bitcoin uses SHA-256)
- File checksums when security matters
// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('hello').digest('hex');
console.log(hash); // 2cf24dba5fb0a...
SHA-3 / Keccak
- Output: Variable (SHA3-256, SHA3-512, etc.)
- Speed: Slower than SHA-2 in software
- Security: Strong — completely different internal structure from SHA-2
SHA-3 was standardized in 2015 as a backup in case SHA-2 weaknesses were found. Today it's used in Ethereum and some specialized applications. SHA-2 remains more widely used.
Why SHA-256 Is NOT Right for Passwords
This is the most important thing in this article:
SHA-256 is a fast hash. That's its strength for data integrity — and its fatal flaw for passwords.
A modern GPU can compute 10+ billion SHA-256 hashes per second. An attacker who steals your hashed password database can try billions of candidate passwords in minutes.
SHA-256("password123") → ef92b778bafe771207...
// Computable 10 billion times/second on modern GPUs
bcrypt — Designed for Passwords
bcrypt is a password-hashing function designed in 1999 with deliberate slowness built in:
- Work factor (cost): A parameter that controls iterations — doubling cost ≈ doubling compute time
- Built-in salt: Random salt is incorporated into the hash, defeating rainbow tables
- Output includes salt + cost: The hash string is self-contained
const bcrypt = require('bcrypt');
// Hash a password (cost factor 12 = ~250ms)
const hash = await bcrypt.hash('myPassword123', 12);
// → '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/...'
// Verify
const match = await bcrypt.compare('myPassword123', hash);
// → true
At cost factor 12, bcrypt takes ~250ms per hash. An attacker with the same GPU can only try ~4 hashes/second — orders of magnitude slower than SHA-256.
Argon2 — The Modern Champion
Argon2 won the Password Hashing Competition in 2015 and is the current recommendation for new systems:
- Memory-hard: Requires significant RAM, defeating GPU/ASIC attacks
- Three variants: Argon2i (side-channel resistant), Argon2d (GPU resistant), Argon2id (recommended — hybrid)
const argon2 = require('argon2');
const hash = await argon2.hash('myPassword', {
type: argon2.argon2id,
memoryCost: 65536, // 64 MB
timeCost: 3,
parallelism: 4,
});
Decision Guide
| Use Case | Recommended Algorithm |
|---|---|
| Password storage | Argon2id (new) or bcrypt (established) |
| Data integrity / file checksum | SHA-256 |
| HMAC authentication | SHA-256 or SHA-512 |
| TLS/SSL certificates | SHA-256 |
| Digital signatures | SHA-256 |
| Non-security file deduplication | MD5 (fast, acceptable) |
| Anything legacy you're auditing | Upgrade to SHA-256+ |
Salting — Why It Matters
Without a salt, if two users have the same password, they get the same hash. A single precomputed rainbow table cracks all of them at once.
Salt is a random value added to the password before hashing:
hash = SHA256(salt + password)
bcrypt and Argon2 handle salting automatically. If you're using SHA-256 for passwords (don't), you must add your own salt and store it alongside the hash.
Frequently Asked Questions
Q: Is it safe to store SHA-256 hashes of passwords? No. SHA-256 is too fast. Use bcrypt or Argon2id instead.
Q: Can I use MD5 for checking file downloads? For protecting against accidental corruption (not tampering), yes. For security-sensitive verification (e.g., verifying a software download hasn't been replaced by malware), use SHA-256.
Q: What if I need to verify a password that's already stored as MD5? On the next successful login, rehash with bcrypt: verify MD5 first, then re-save the bcrypt hash and delete the MD5.
Q: How often should I update the bcrypt cost factor? Reassess every 2–3 years as hardware gets faster. A hash should take at least 100ms to compute on your production server.
→ Compute SHA-256 and other hashes instantly with the Hash Text Tool.