MD5 vs SHA1 vs SHA256: Which Hash Should You Use?
Hash functions are everywhere in software — file checksums, JWT signatures, API authentication, password storage. But picking the wrong one can be a serious security mistake.
Quick tool: Hash Generator Online — generate MD5, SHA1, SHA256, SHA512 in your browser (free, private).
TL;DR — The Decision Table
| Use case | Algorithm | Notes |
|---|---|---|
| Password storage | bcrypt / Argon2 | Never use MD5/SHA |
| Digital signatures | SHA-256 | NIST approved |
| File integrity | SHA-256 or MD5 | MD5 ok for non-security uses |
| JWT (HS256) | SHA-256 | Standard choice |
| Git commits | SHA-1 (→ SHA-256) | Being migrated |
| TLS certificates | SHA-256 | SHA-1 certs rejected |
| HMAC | SHA-256 or SHA-512 | Both secure |
Understanding Hash Functions
A cryptographic hash function takes arbitrary input and produces a fixed-length output:
import hashlib
text = "Hello, World!"
md5 = hashlib.md5(text.encode()).hexdigest() # 32 hex chars
sha1 = hashlib.sha1(text.encode()).hexdigest() # 40 hex chars
sha256 = hashlib.sha256(text.encode()).hexdigest() # 64 hex chars
sha512 = hashlib.sha512(text.encode()).hexdigest() # 128 hex chars
print(sha256)
# 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
Key properties:
- Deterministic: same input always → same output
- One-way: you can't reverse a hash to get the input
- Avalanche effect: changing one bit completely changes the output
- Collision resistant: it should be infeasible to find two inputs with the same hash
MD5 — Fast but Broken
Status: Cryptographically broken. Use only for non-security checksums.
MD5 produces a 128-bit (32 hex char) hash. It was widely used through the 1990s but has been thoroughly broken:
- 2004: Collision attacks demonstrated
- 2008: Rogue CA certificates created using MD5 collisions
- 2012: Flame malware forged Windows Update signatures using MD5
// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('md5').update('Hello').digest('hex');
// 8b1a9953c4611296a827abf8c47804d7
Safe uses for MD5:
- Non-security file deduplication
- Caching keys (where collisions don't matter)
- Legacy system compatibility
Unsafe uses:
- Password hashing (use bcrypt/Argon2)
- Digital signatures
- SSL/TLS certificates
- Any security-critical context
SHA-1 — Deprecated, Being Phased Out
Status: Deprecated. Practical collision attacks demonstrated.
SHA-1 produces a 160-bit (40 hex char) hash. The "SHAttered" attack in 2017 demonstrated the first real-world SHA-1 collision:
# Two different PDFs with the same SHA-1 hash
sha1sum shattered-1.pdf shattered-2.pdf
# 38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-1.pdf
# 38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-2.pdf
Git still uses SHA-1 for commit IDs (though SHA-256 migration is underway). Browsers reject TLS certificates signed with SHA-1.
SHA-256 — The Current Standard
Status: Secure. Recommended for new applications.
Part of the SHA-2 family, SHA-256 produces a 256-bit (64 hex char) hash. Used in:
- Bitcoin blockchain
- TLS 1.3
- JWT (HS256, RS256, ES256)
- Code signing certificates
- Password managers
// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('Hello').digest('hex');
// 185f8db32921bd46d35cc3c66b9a7b8f3a2bc37f9f0e87c
// Browser (Web Crypto API)
async function sha256(text) {
const data = new TextEncoder().encode(text);
const buf = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(buf))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
sha256('Hello').then(console.log);
import hashlib
hash = hashlib.sha256(b'Hello').hexdigest()
print(hash)
HMAC — For Authentication
HMAC (Hash-based Message Authentication Code) uses a secret key with a hash function to authenticate messages:
import hmac, hashlib
secret = b'my-secret-key'
message = b'user_id=123&amount=50'
sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(sig) # Use this to verify the message wasn't tampered with
Used in:
- JWT signatures (HS256 = HMAC-SHA256)
- Webhook payload verification (GitHub, Stripe)
- API request signing (AWS Signature V4)
The Password Hashing Trap
This is the most common mistake:
# WRONG — never do this
import hashlib
password_hash = hashlib.sha256(password.encode()).hexdigest()
# RIGHT — use bcrypt
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
Why SHA-256 fails for passwords:
- Too fast — attackers can try billions per second
- No salt by default — rainbow tables work
- Deterministic — same password = same hash, leaks duplicates
bcrypt, scrypt, and Argon2 are designed to be:
- Slow (configurable cost)
- Salted automatically
- Memory-intensive (Argon2/scrypt)
Quick Reference: Hashing in Popular Languages
JavaScript (Node.js):
const { createHash, createHmac } = require('crypto');
createHash('sha256').update('text').digest('hex');
createHmac('sha256', 'key').update('text').digest('hex');
Python:
import hashlib, hmac
hashlib.sha256(b'text').hexdigest()
hmac.new(b'key', b'text', hashlib.sha256).hexdigest()
Go:
import "crypto/sha256"
h := sha256.Sum256([]byte("text"))
fmt.Printf("%x\n", h)
Shell:
echo -n "text" | sha256sum
echo -n "text" | md5sum
Online Hash Generator
Need to quickly hash a string or verify a checksum? Use the DevKits Hash Generator:
- MD5, SHA-1, SHA-256, SHA-384, SHA-512
- HMAC support with custom secret key
- File hashing (drag & drop)
- 100% browser-based — nothing sent to a server
- Free, no signup
Or use the API for programmatic access:
curl -X POST https://api.aiforeverthing.com/api/hash/generate \
-H "Content-Type: application/json" \
-d '{"text": "hello world", "algorithm": "sha256"}'
Summary
- MD5: Fast, broken, use only for non-security checksums
- SHA-1: Deprecated, avoid for new code
- SHA-256: Current standard, use for everything new
- SHA-512: Max security, often faster on 64-bit
- bcrypt/Argon2: For passwords — always, no exceptions
- HMAC-SHA256: For message authentication and JWT
Top comments (0)