Hash Functions Explained: MD5, SHA-256, bcrypt & More
What Is a Hash Function?
A hash function takes an input of any size -- a password, a file, or an entire database -- and produces a fixed-size output called a hash, digest, or checksum. The same input always produces the same output, but even a tiny change in the input produces a completely different hash. This deterministic, one-way transformation is the foundation of password storage, data integrity verification, digital signatures, and dozens of other security mechanisms.
Unlike encryption, hashing is irreversible by design. You cannot take a hash and recover the original input. This is exactly what makes hashing perfect for passwords: even if a database is breached, the attacker gets hashes, not plaintext passwords.
Input: "hello"
MD5: 5d41402abc4b2a76b9719d911017c592
SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Input: "hello!" (one character added)
MD5: 9b71d224bd62f3785d96d46ad3ea3d73
SHA-256: ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b
// Completely different outputs -- this is the "avalanche effect"To generate hashes instantly, try our Hash Generator tool. It computes MD5, SHA-1, SHA-256, SHA-384, and SHA-512 hashes entirely in your browser -- your data is never sent to any server.
Properties of Cryptographic Hash Functions
A cryptographic hash function must satisfy five properties to be considered secure. Understanding these properties helps you choose the right algorithm for your use case.
| Property | Meaning | Why It Matters |
|---|---|---|
| Deterministic | Same input always gives same output | Password verification, checksums |
| Pre-image resistance | Cannot reverse a hash to find the input | Protects stored passwords |
| Second pre-image resistance | Cannot find a different input with the same hash | Prevents file substitution attacks |
| Collision resistance | Cannot find any two inputs with the same hash | Digital signatures, certificates |
| Avalanche effect | Tiny input change produces drastically different output | Prevents pattern analysis |
Hash Algorithm Comparison
| Algorithm | Output Size | Security Status | Best For |
|---|---|---|---|
| MD5 | 128 bits (32 hex) | Broken | Non-security checksums only |
| SHA-1 | 160 bits (40 hex) | Deprecated | Legacy compatibility only |
| SHA-256 | 256 bits (64 hex) | Secure | Data integrity, signatures, HMAC |
| SHA-384 | 384 bits (96 hex) | Secure | Higher security requirements |
| SHA-512 | 512 bits (128 hex) | Secure | Maximum security, faster on 64-bit CPUs |
| SHA-3 | Variable | Secure | Future-proofing, different design from SHA-2 |
| bcrypt | 184 bits | Secure | Password hashing |
| scrypt | Variable | Secure | Password hashing (memory-hard) |
| Argon2id | Variable | Best | Password hashing (recommended) |
Generate hashes with any of the SHA-family algorithms using our Hash Generator. For password-specific hashing, use bcrypt or Argon2id -- never a general-purpose hash like SHA-256.
MD5: Fast but Broken
MD5 was designed by Ronald Rivest in 1991 and produces a 128-bit (32-character hex) hash. It was widely used for password storage and file verification until collision attacks were demonstrated in 2004. By 2008, researchers created a rogue SSL certificate using an MD5 collision, proving the practical danger. Today, MD5 collisions can be generated in seconds on a standard laptop.
// JavaScript (Node.js) - MD5 for non-security checksum
const crypto = require('crypto');
const hash = crypto.createHash('md5').update('hello world').digest('hex');
// '5eb63bbbe01eeed093cb22bb8f5acdc3'
// Python
import hashlib
hashlib.md5(b'hello world').hexdigest()
# '5eb63bbbe01eeed093cb22bb8f5acdc3'
// Command line
echo -n "hello world" | md5sum
# 5eb63bbbe01eeed093cb22bb8f5acdc3 -Use MD5 only for: non-security checksums (verifying a downloaded file matches the source), cache key generation, deduplication. Never use MD5 for: password hashing, digital signatures, certificate verification, or any security-critical application.
SHA-256: The Current Standard
SHA-256 is part of the SHA-2 family designed by the NSA and published by NIST in 2001. It produces a 256-bit (64-character hex) hash and remains unbroken as of 2026. SHA-256 is used in Bitcoin mining, TLS certificates, code signing, Git (since 2023), and most modern integrity verification systems.
// JavaScript (Node.js)
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('hello world').digest('hex');
// 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
// JavaScript (browser - Web Crypto API)
async function sha256(message) {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
await sha256('hello world');
// Python
import hashlib
hashlib.sha256(b'hello world').hexdigest()
// Go
import (
"crypto/sha256"
"fmt"
)
hash := sha256.Sum256([]byte("hello world"))
fmt.Sprintf("%x", hash)
// Command line
echo -n "hello world" | sha256sumSHA-256 is the best general-purpose hash for data integrity, digital signatures, and HMAC authentication. It is fast, widely supported, and has no known vulnerabilities. However, its speed makes it unsuitable for password hashing -- an attacker with a GPU can compute billions of SHA-256 hashes per second, making brute-force attacks practical.
Password Hashing: bcrypt, scrypt, and Argon2
Passwords require special hash functions that are intentionally slow to compute. General-purpose hashes like SHA-256 are designed to be fast, which is exactly what you do not want for passwords. An attacker who can compute 10 billion SHA-256 hashes per second can brute-force an 8-character password in hours. Password hashing functions solve this by being deliberately expensive in terms of CPU time and memory.
bcrypt
bcrypt was designed in 1999 and remains one of the most widely used password hashing functions. It includes a built-in salt (random data added to the password before hashing) and a configurable work factor that controls computation time. Each increment of the work factor doubles the time required.
// Node.js with bcrypt
const bcrypt = require('bcrypt');
// Hash a password (work factor 12 = ~250ms)
const saltRounds = 12;
const hash = await bcrypt.hash('myPassword123', saltRounds);
// '$2b$12$LJ3m4ys3dRYoXMxKBqE5T.6qZB0DKFK2vZ7lXQ4KeqUCY.ZR7pGS'
// Verify a password
const isMatch = await bcrypt.compare('myPassword123', hash);
// true
// Python
import bcrypt
hashed = bcrypt.hashpw(b'myPassword123', bcrypt.gensalt(rounds=12))
bcrypt.checkpw(b'myPassword123', hashed) # TrueArgon2id (Recommended)
Argon2 won the Password Hashing Competition (PHC) in 2015. The Argon2id variant combines resistance to GPU attacks (memory-hard like scrypt) with resistance to side-channel attacks (like Argon2i). OWASP recommends Argon2id as the primary choice for password hashing in 2026.
// Node.js with argon2
const argon2 = require('argon2');
// Hash with Argon2id (recommended settings)
const hash = await argon2.hash('myPassword123', {
type: argon2.argon2id,
memoryCost: 65536, // 64 MB memory
timeCost: 3, // 3 iterations
parallelism: 4, // 4 threads
});
// Verify
const isValid = await argon2.verify(hash, 'myPassword123');
// Python
from argon2 import PasswordHasher
ph = PasswordHasher()
hash = ph.hash("myPassword123")
ph.verify(hash, "myPassword123") # True| Feature | bcrypt | scrypt | Argon2id |
|---|---|---|---|
| Year | 1999 | 2009 | 2015 |
| Built-in salt | Yes | Yes | Yes |
| Memory-hard | No | Yes | Yes |
| GPU resistant | Moderate | High | High |
| Max input length | 72 bytes | Unlimited | Unlimited |
| OWASP recommended | Fallback | Acceptable | Primary |
HMACs: Hash-Based Message Authentication
An HMAC (Hash-based Message Authentication Code) combines a hash function with a secret key to verify both the integrity and authenticity of a message. While a plain hash proves that data has not been modified, an HMAC proves that it has not been modified and that it was created by someone who knows the secret key.
// JavaScript (Node.js) - HMAC-SHA256
const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'my-secret-key')
.update('message to authenticate')
.digest('hex');
// 'a1b2c3d4...'
// Python
import hmac
import hashlib
signature = hmac.new(
b'my-secret-key',
b'message to authenticate',
hashlib.sha256
).hexdigest()
// Common HMAC use cases:
// 1. API webhook signature verification (Stripe, GitHub)
// 2. JWT signature (HS256 = HMAC-SHA256)
// 3. Session cookie signing
// 4. API request authenticationHMACs are used extensively in JWT tokens (the HS256 algorithm is HMAC-SHA256), webhook signature verification, and API authentication. You can decode and inspect JWT tokens with our JWT Decoder to see the HMAC signature in action.
Checksums for File Integrity
One of the most practical uses of hash functions is verifying file integrity. When downloading software, the publisher provides a hash (usually SHA-256) of the file. After downloading, you compute the hash of the downloaded file and compare it to the published value. If they match, the file is authentic and complete.
# Verify a downloaded file (Linux/macOS)
sha256sum downloaded-file.tar.gz
# Compare with published hash
# Generate checksums for distribution
sha256sum myapp-v1.0.tar.gz > SHA256SUMS
sha256sum myapp-v1.0.zip >> SHA256SUMS
# Verify multiple files at once
sha256sum -c SHA256SUMS
# Windows (PowerShell)
Get-FileHash downloaded-file.zip -Algorithm SHA256
# Python - hash a large file in chunks
import hashlib
def file_hash(filepath, algorithm='sha256'):
h = hashlib.new(algorithm)
with open(filepath, 'rb') as f:
while chunk := f.read(8192):
h.update(chunk)
return h.hexdigest()For quick hash generation without the command line, use our Hash Generator tool. It computes MD5, SHA-1, SHA-256, SHA-384, and SHA-512 in your browser. For verifying data transmitted via APIs, combine hashing with proper API response handling.
Hash Functions in Practice: When to Use What
| Use Case | Recommended | Never Use |
|---|---|---|
| Password storage | Argon2id, bcrypt | MD5, SHA-* |
| File integrity / checksum | SHA-256 | MD5 (for security) |
| Digital signatures | SHA-256, SHA-384 | MD5, SHA-1 |
| HMAC / API auth | HMAC-SHA256 | HMAC-MD5 |
| JWT signing | RS256, ES256, HS256 | None (algorithm) |
| Cache keys / dedup | MD5, SHA-256 | N/A (not security) |
| Content addressing (Git) | SHA-256 (new), SHA-1 (legacy) | MD5 |
Common Security Mistakes with Hashing
- Using SHA-256 for passwords -- SHA-256 is too fast. GPUs can compute billions of hashes per second. Use bcrypt or Argon2id, which are intentionally slow.
- Not using a salt -- Without a unique salt per password, identical passwords produce identical hashes, enabling rainbow table attacks. bcrypt and Argon2 include salting automatically.
- Storing passwords with MD5 -- MD5 is broken and fast. A database of MD5-hashed passwords can be cracked almost instantly using precomputed lookup tables.
- Rolling your own hash scheme -- Constructions like
sha256(salt + sha256(password))do not improve security and may introduce vulnerabilities. Use established password hashing libraries. - Comparing hashes with == instead of constant-time comparison -- String comparison with
==is vulnerable to timing attacks. Usecrypto.timingSafeEqual()in Node.js orhmac.compare_digest()in Python. - Not upgrading hash algorithms -- If your database still uses MD5 or SHA-1 for passwords, implement a migration strategy: re-hash passwords with bcrypt/Argon2 at login time.
Hashing vs Encryption: Know the Difference
| Feature | Hashing | Encryption |
|---|---|---|
| Direction | One-way (irreversible) | Two-way (reversible with key) |
| Output size | Fixed (e.g., 256 bits) | Same as input (plus overhead) |
| Key required | No (except HMAC) | Yes |
| Purpose | Verify integrity, store passwords | Protect data confidentiality |
| Examples | SHA-256, bcrypt | AES-256, RSA, ChaCha20 |
Use hashing when you need to verify data without storing the original (passwords, checksums). Use encryption when you need to store data securely and retrieve it later (database fields, file storage, network communication). For encoding (not security), see our guides on Base64 encoding and URL encoding.
Frequently Asked Questions
Is MD5 still safe to use?
MD5 is cryptographically broken and should never be used for security purposes like password hashing, digital signatures, or certificate verification. Collision attacks against MD5 are practical and can be performed in seconds on modern hardware. However, MD5 is still acceptable for non-security checksums like verifying file download integrity (where an attacker cannot modify the source) or generating cache keys.
What is the best hash function for passwords in 2026?
Argon2id is the recommended password hashing function as of 2026. It won the Password Hashing Competition in 2015 and is recommended by OWASP. Argon2id combines resistance to both GPU attacks (memory-hard) and side-channel attacks. If Argon2id is not available in your framework, use bcrypt with a work factor of 12 or higher. Never use SHA-256 or MD5 for passwords -- they are too fast and lack built-in salting.
What is the difference between hashing and encryption?
Hashing is a one-way function that produces a fixed-size digest from any input. You cannot reverse a hash to get the original data. Encryption is a two-way function that transforms data using a key, and the original data can be recovered with the decryption key. Use hashing for passwords, data integrity, and digital signatures. Use encryption for data that must be retrieved in its original form.
Generate Hashes Instantly
Compute MD5, SHA-1, SHA-256, SHA-384, and SHA-512 hashes for any text or file. Our free Hash Generator runs entirely in your browser -- your data never leaves your machine.
Open Hash GeneratorRelated Articles
JWT Tokens Explained
Deep dive into JWT structure, HMAC signatures, and security.
Base64 Encoding Explained
When and why to use Base64 encoding in your projects.
URL Encoding Guide
Percent-encoding, reserved characters, and common pitfalls.
JWT vs Session Cookies
Compare authentication methods for APIs and web apps.