Hashes vs Encryption vs Password Hashing: What Developers Need to Know
You need to verify a downloaded file hasn't been corrupted, store user passwords securely, or encrypt sensitive data. Choosing the wrong algorithm—using MD5 for passwords or SHA256 for encryption—creates serious security vulnerabilities. This guide explains what hashing, encryption, and password hashing actually do and when to use each.
The Three Categories: What They Actually Do
1. Cryptographic Hashing (MD5, SHA-1, SHA-256, SHA-512)
Purpose: Generate a fixed-size fingerprint of data.
- One-way: Cannot reverse the hash to get original data
- Deterministic: Same input always produces same output
- Fast: Designed for speed
- Collision-resistant: Hard to find two inputs with same hash (in theory)
Common uses: File integrity checks, checksums, digital signatures, data deduplication
2. Encryption (AES, RSA, ChaCha20)
Purpose: Transform data so only authorized parties can read it.
- Two-way: Can encrypt and decrypt with key(s)
- Confidentiality: Protects data in transit or at rest
- Key-dependent: Security depends on key secrecy
- Symmetric or asymmetric: One key (AES) or key pair (RSA)
Common uses: HTTPS, database encryption, file encryption, secure messaging
3. Password Hashing (bcrypt, scrypt, Argon2, PBKDF2)
Purpose: Store passwords securely to resist brute-force attacks.
- One-way: Cannot reverse to get password
- Slow by design: Makes brute-forcing expensive
- Salted: Random salt prevents rainbow table attacks
- Adaptive: Can increase cost factor over time
Common uses: User password storage, API key derivation
When to Use Cryptographic Hashing
File Integrity Verification
Verify downloaded files haven't been corrupted or tampered with. The Hash/Checksum Generator can compute MD5, SHA-1, SHA-256, and SHA-512 hashes for text input.
# Download file and its published SHA-256 hash
curl -O https://example.com/software.tar.gz
curl -O https://example.com/software.tar.gz.sha256
# Compute hash locally
sha256sum software.tar.gz
# Output: a3b5c7d9e1f2... software.tar.gz
# Compare with published hash
cat software.tar.gz.sha256
# Output: a3b5c7d9e1f2...
# If hashes match, file is authentic and uncorruptedWhich algorithm to use:
- MD5: Fast but cryptographically broken. Use only for non-security purposes (checksums, deduplication)
- SHA-1: Deprecated due to collision attacks. Avoid for security-critical applications
- SHA-256: Standard choice for most applications. Good balance of speed and security
- SHA-512: Stronger variant. Use when extra security margin is needed
Git Commit IDs
Git uses SHA-1 hashes to identify commits, trees, and blobs. Each commit hash is deterministic based on content, parent commits, author, and timestamp:
git log --oneline
a3b5c7d Fix authentication bug
e1f2g3h Add user profile endpoint
i4j5k6l Update dependenciesGit is transitioning to SHA-256 due to SHA-1 collision vulnerabilities, but SHA-1 remains widely used.
Data Deduplication
Identify duplicate files by comparing hashes:
import hashlib
def hash_file(filepath):
sha256 = hashlib.sha256()
with open(filepath, 'rb') as f:
for chunk in iter(lambda: f.read(8192), b''):
sha256.update(chunk)
return sha256.hexdigest()
# Find duplicates
seen_hashes = {}
for file in files:
file_hash = hash_file(file)
if file_hash in seen_hashes:
print(f"Duplicate: {file} == {seen_hashes[file_hash]}")
else:
seen_hashes[file_hash] = fileETag Headers in HTTP
Web servers use hashes for cache validation:
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "a3b5c7d9e1f2"
Last-Modified: Mon, 19 Jan 2026 10:00:00 GMT
# Client includes ETag in subsequent request
GET /index.html HTTP/1.1
If-None-Match: "a3b5c7d9e1f2"
# Server responds with 304 Not Modified if content unchangedWhen to Use Encryption
HTTPS/TLS Communication
Web browsers use encryption to protect data in transit. HTTPS combines asymmetric encryption (RSA/ECDSA for key exchange) with symmetric encryption (AES for bulk data):
# Browser connects to server
Client: [ClientHello] - Supported cipher suites
Server: [ServerHello] - Selected cipher (e.g., TLS_AES_256_GCM_SHA384)
Server: [Certificate] - Server's public key
Client: [ClientKeyExchange] - Encrypted session key
Both: [ChangeCipherSpec] - Switch to encrypted communication
# All subsequent data encrypted with AES-256Database Encryption at Rest
Protect sensitive data stored in databases:
# Encrypt sensitive fields before storage
from cryptography.fernet import Fernet
key = Fernet.generate_key() # Store securely (not in code!)
cipher = Fernet(key)
# Encrypt
plaintext = b"user@example.com"
ciphertext = cipher.encrypt(plaintext)
# Store: gAAAAABh3b5c... in database
# Decrypt when needed
retrieved = cipher.decrypt(ciphertext)
# Output: b"user@example.com"Key management is critical: Losing the encryption key means permanent data loss. Store keys in secure key management systems (AWS KMS, HashiCorp Vault, etc.).
File Encryption
Encrypt files before storing in cloud or on disk:
# Using GPG to encrypt a file
gpg --symmetric --cipher-algo AES256 document.pdf
# Creates: document.pdf.gpg
# Decrypt
gpg --decrypt document.pdf.gpg > document.pdfWhen to Use Password Hashing
User Password Storage
Never store plaintext passwords or use fast hashes like SHA-256. Use password hashing algorithms designed to resist brute-force attacks:
# WRONG: Fast hash (vulnerable to brute-force)
import hashlib
password = "user_password"
hash = hashlib.sha256(password.encode()).hexdigest()
# An attacker can test billions of passwords per second
# CORRECT: bcrypt (slow by design)
import bcrypt
password = "user_password"
salt = bcrypt.gensalt(rounds=12) # Cost factor
hashed = bcrypt.hashpw(password.encode(), salt)
# Output: $2b$12$abcdef... (includes salt and cost)
# Verify password
if bcrypt.checkpw(user_input.encode(), hashed):
print("Password correct")
else:
print("Password incorrect")Why bcrypt/scrypt/Argon2?
- Intentionally slow: Takes ~100ms to compute, limiting attacker to thousands (not billions) of attempts per second
- Automatic salting: Each password gets unique random salt to prevent rainbow table attacks
- Adaptive cost: Increase rounds/cost as hardware improves
API Key Derivation
Generate API keys from master secrets:
from hashlib import pbkdf2_hmac
master_secret = b"master_key_here"
salt = b"api_key_salt_v1"
iterations = 100000
api_key = pbkdf2_hmac('sha256', master_secret, salt, iterations)
print(api_key.hex())
# Output: a3b5c7d9e1f2...Common Mistakes to Avoid
1. Using MD5 or SHA-256 for Passwords
# BAD: Fast hash can be brute-forced
password_hash = hashlib.md5("password123".encode()).hexdigest()
# Attacker can test 1 billion MD5 hashes per second on GPU
# "password123" would be cracked instantlyFix: Use bcrypt, scrypt, or Argon2 with appropriate cost factors.
2. Using Encryption When Hashing is Needed
# BAD: File integrity check using encryption
encrypted_content = aes_encrypt(file_content, key)
# Problem: Anyone with key can forge "valid" content
# GOOD: File integrity check using hash
file_hash = hashlib.sha256(file_content).hexdigest()
# No key needed; hash proves content hasn't changed3. Not Using Salt for Passwords
# BAD: Same password = same hash
user1_hash = bcrypt.hashpw("password123".encode(), bcrypt.gensalt())
user2_hash = bcrypt.hashpw("password123".encode(), bcrypt.gensalt())
# Different hashes due to different salts (GOOD)
# If you manually control salt:
# BAD: Reusing same salt for all passwords
salt = bcrypt.gensalt() # Generated once
user1_hash = bcrypt.hashpw("password123".encode(), salt)
user2_hash = bcrypt.hashpw("password123".encode(), salt)
# Same hash! Attacker can crack one password and find all users with same passwordFix: Let bcrypt/scrypt generate unique salt per password (automatic with proper usage).
4. Low Cost Factor for Password Hashing
# BAD: Too few rounds (fast = insecure)
salt = bcrypt.gensalt(rounds=4) # Way too low!
# Computation time: ~1ms per hash
# GOOD: Appropriate cost factor
salt = bcrypt.gensalt(rounds=12) # Standard for 2026
# Computation time: ~100-200ms per hash
# Increase to 13-14 as hardware improves5. Hardcoding Encryption Keys
# BAD: Key in source code
encryption_key = "a3b5c7d9e1f2..." # Anyone with code access can decrypt
# GOOD: Load from secure storage
import os
encryption_key = os.environ['ENCRYPTION_KEY'] # From secrets managerDecision Tree: Which Should I Use?
Need to...
├─ Verify file hasn't changed?
│ └─ Use: SHA-256 hash (cryptographic hashing)
│ Tool: Hash/Checksum Generator
│
├─ Store user passwords?
│ └─ Use: bcrypt/Argon2 (password hashing)
│ NEVER use: MD5, SHA-256, or any fast hash
│
├─ Hide data so only authorized users can read it?
│ └─ Use: AES-256 encryption
│ Need to decrypt later? Yes → Encryption
│
├─ Identify duplicate files?
│ └─ Use: MD5 or SHA-256 hash (checksums)
│
├─ Generate commit ID or content fingerprint?
│ └─ Use: SHA-256 hash (deterministic fingerprint)
│
└─ Protect data in transit (API, HTTPS)?
└─ Use: TLS/SSL encryption (handles automatically)Practical Tools
For quick hash generation:
- Hash/Checksum Generator - Compute MD5, SHA-1, SHA-256, SHA-512 hashes for text
- Server-side Hash Calculator - Enterprise-grade hash generation for large files with high performance
Command-line tools:
# Generate SHA-256 hash
echo -n "test content" | sha256sum
echo -n "test content" | openssl dgst -sha256
# Generate file checksum
sha256sum file.txt
md5sum file.txt
# bcrypt password (requires bcrypt tool)
htpasswd -bnBC 12 "" your_password | tr -d ':
'Security Best Practices
- For passwords: Always use bcrypt (rounds≥12), scrypt, or Argon2. Never use MD5, SHA-1, or SHA-256.
- For file integrity: Use SHA-256. Avoid MD5 and SHA-1 for security-critical verification.
- For encryption: Use AES-256 (symmetric) or RSA-2048+ (asymmetric). Never implement custom encryption.
- Key management: Store encryption keys in secure key management systems, not in code or config files.
- Salt passwords: Always use unique salt per password (bcrypt does this automatically).
- Review algorithms: MD5 and SHA-1 are deprecated for security use. Transition to SHA-256+.
Summary
- Cryptographic hashing (MD5, SHA-256): Fast, one-way fingerprints for file integrity, checksums, and deduplication
- Encryption (AES, RSA): Two-way protection for confidential data in transit or at rest
- Password hashing (bcrypt, Argon2): Slow, salted, one-way protection against brute-force password attacks
Use the Hash/Checksum Generator for quick text hashing or the Server-side Hash Calculator for high-performance file hashing. Choose the right algorithm for your use case—security depends on it.