What a hash is
A hash is a one-way function: any input, any size, produces a fixed-length "digest." The same input always produces the same digest. Any change — even one byte — produces a completely different one.
"hello" → SHA-256 → 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
"Hello" → SHA-256 → 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
SHA-1, SHA-256 and SHA-512 use the browser's built-in window.crypto.subtle. MD5 uses a client-side JS implementation. Nothing you type is uploaded.
When to use which
| Algorithm | Output size | Use when… | Do not use for… |
|---|---|---|---|
| MD5 | 128 bits | File checksums, cache keys, deduplication, non-security fingerprints. | Signing, password storage, tamper detection. |
| SHA-1 | 160 bits | Legacy verification only (Git commit IDs, old certs). | Anything new. Broken since 2017. |
| SHA-256 | 256 bits | The default in 2025. Signatures, integrity, blockchain, tokens. | Password storage (use bcrypt/argon2). |
| SHA-512 | 512 bits | Long messages where extra headroom matters. Same class as SHA-256, longer output. | Password storage. |
Never use raw hashes for passwords
Hashes are fast — that is the problem. A modern GPU tries billions of SHA-256 attempts per second. Use a password-hashing algorithm designed to be slow:
- bcrypt — the safe default.
- argon2id — the modern winner of the Password Hashing Competition.
- scrypt — memory-hard, still solid.
All three include salt, cost factors, and side-channel resistance. Raw SHA-256 does not.
What a good use of SHA-256 looks like
async function fingerprint(fileBuffer) {
const buf = await crypto.subtle.digest('SHA-256', fileBuffer)
return [...new Uint8Array(buf)].map(b => b.toString(16).padStart(2, '0')).join('')
}
Use it for: file integrity, cache invalidation, ETags, content-addressable storage, HMAC (with a key), signature verification.
Common mistakes
- Truncating a hash. Never keep only the first 8 chars — collision probability skyrockets.
- Hashing passwords with SHA. Always bcrypt / argon2 / scrypt.
- Comparing hashes with
==. Usecrypto.timingSafeEqualserver-side to avoid timing attacks. - Assuming MD5 is safe. It is broken for collision resistance — never sign anything with it.
- Confusing hashing with encryption. Hashes are one-way. If you need to get the original back, you need encryption.
FAQ
Is MD5 completely broken? For security, yes. For checksums, cache keys and fingerprints, MD5 is still fine — that is why it is still widely deployed.
What is a rainbow table? A precomputed lookup of common inputs → hashes. Salting your input (prepending random bytes) defeats them.
Are all three SHA family algorithms equally safe? SHA-1 is broken. SHA-256 and SHA-512 are both secure — pick 256 unless you have a specific reason.