hashlib provides secure hash algorithms for integrity checking, password storage, and cryptographic operations.
Basic Hashing
import hashlib
# Create hash object and update
h = hashlib.sha256()
h.update(b"Hello ")
h.update(b"World")
# Get digest
print(h.hexdigest()) # Hex string
print(h.digest()) # Raw bytes
# One-liner
hashlib.sha256(b"Hello World").hexdigest()Available Algorithms
import hashlib
# Always available
hashlib.md5(b"data").hexdigest()
hashlib.sha1(b"data").hexdigest()
hashlib.sha256(b"data").hexdigest()
hashlib.sha384(b"data").hexdigest()
hashlib.sha512(b"data").hexdigest()
# SHA-3 family (Python 3.6+)
hashlib.sha3_256(b"data").hexdigest()
hashlib.sha3_512(b"data").hexdigest()
hashlib.shake_256(b"data").hexdigest(32) # Variable length
# BLAKE2 (fast, secure)
hashlib.blake2b(b"data").hexdigest()
hashlib.blake2s(b"data").hexdigest()
# List all available
print(hashlib.algorithms_available)
print(hashlib.algorithms_guaranteed)Hashing Files
import hashlib
def hash_file(path, algorithm="sha256", chunk_size=8192):
"""Hash a file without loading it entirely into memory."""
h = hashlib.new(algorithm)
with open(path, "rb") as f:
while chunk := f.read(chunk_size):
h.update(chunk)
return h.hexdigest()
# Usage
file_hash = hash_file("large_file.zip")
print(f"SHA-256: {file_hash}")
# Verify download
expected = "a1b2c3d4..."
if hash_file("download.zip") == expected:
print("Integrity verified")Hashing Strings
import hashlib
# Always encode strings to bytes first
text = "Hello World"
# Using encode()
hashlib.sha256(text.encode()).hexdigest()
hashlib.sha256(text.encode("utf-8")).hexdigest()
# Using bytes literal
hashlib.sha256(b"Hello World").hexdigest()Password Hashing
import hashlib
import os
# DON'T use plain hashing for passwords
# bad_hash = hashlib.sha256(password.encode()).hexdigest()
# DO use PBKDF2 with salt
def hash_password(password: str) -> tuple[bytes, bytes]:
"""Hash password with random salt."""
salt = os.urandom(32)
key = hashlib.pbkdf2_hmac(
"sha256",
password.encode(),
salt,
iterations=100_000
)
return salt, key
def verify_password(password: str, salt: bytes, key: bytes) -> bool:
"""Verify password against stored hash."""
new_key = hashlib.pbkdf2_hmac(
"sha256",
password.encode(),
salt,
iterations=100_000
)
return new_key == key
# Usage
salt, key = hash_password("secret123")
print(verify_password("secret123", salt, key)) # True
print(verify_password("wrong", salt, key)) # FalseHMAC (Hash-Based Message Authentication)
import hashlib
import hmac
# Create HMAC
key = b"secret-key"
message = b"Hello World"
# Using hmac module (preferred)
h = hmac.new(key, message, hashlib.sha256)
print(h.hexdigest())
# Verify HMAC (timing-safe comparison)
received_hmac = "..."
expected_hmac = hmac.new(key, message, hashlib.sha256).hexdigest()
if hmac.compare_digest(received_hmac, expected_hmac):
print("Message authentic")Digest Sizes
import hashlib
# Digest sizes in bytes
print(hashlib.md5().digest_size) # 16 (128 bits)
print(hashlib.sha1().digest_size) # 20 (160 bits)
print(hashlib.sha256().digest_size) # 32 (256 bits)
print(hashlib.sha512().digest_size) # 64 (512 bits)
print(hashlib.blake2b().digest_size) # 64 (512 bits)
print(hashlib.blake2s().digest_size) # 32 (256 bits)BLAKE2 (Modern Choice)
import hashlib
# BLAKE2b - optimized for 64-bit
h = hashlib.blake2b(b"data", digest_size=32) # Custom size
print(h.hexdigest())
# BLAKE2s - optimized for 32-bit/smaller
h = hashlib.blake2s(b"data")
print(h.hexdigest())
# With key (keyed hashing, like HMAC)
h = hashlib.blake2b(b"data", key=b"secret")
print(h.hexdigest())
# With personalization
h = hashlib.blake2b(b"data", person=b"myapp")
print(h.hexdigest())SHAKE (Variable-Length Output)
import hashlib
# SHAKE256 - extendable output
h = hashlib.shake_256(b"data")
print(h.hexdigest(32)) # 32 bytes output
print(h.hexdigest(64)) # 64 bytes output
print(h.hexdigest(128)) # 128 bytes outputCommon Patterns
import hashlib
import os
def content_hash(data: bytes) -> str:
"""Generate content-addressable hash."""
return hashlib.sha256(data).hexdigest()
def generate_token(length: int = 32) -> str:
"""Generate secure random token."""
return hashlib.sha256(os.urandom(length)).hexdigest()
def hash_dict(d: dict) -> str:
"""Hash a dictionary deterministically."""
import json
canonical = json.dumps(d, sort_keys=True)
return hashlib.sha256(canonical.encode()).hexdigest()
def checksum(path: str) -> str:
"""Generate file checksum."""
return hash_file(path, "sha256")
def verify_checksum(path: str, expected: str) -> bool:
"""Verify file against expected checksum."""
return hash_file(path, "sha256") == expected.lower()API Request Signing
import hashlib
import hmac
import time
def sign_request(method: str, path: str, body: str, secret: str) -> str:
"""Sign an API request."""
timestamp = str(int(time.time()))
message = f"{method}\n{path}\n{timestamp}\n{body}"
signature = hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return f"{timestamp}:{signature}"
def verify_request(
method: str, path: str, body: str,
secret: str, signature: str, max_age: int = 300
) -> bool:
"""Verify signed API request."""
timestamp_str, received_sig = signature.split(":")
timestamp = int(timestamp_str)
# Check age
if abs(time.time() - timestamp) > max_age:
return False
# Reconstruct and compare
message = f"{method}\n{path}\n{timestamp_str}\n{body}"
expected_sig = hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(received_sig, expected_sig)Cache Keys
import hashlib
import json
def cache_key(*args, **kwargs) -> str:
"""Generate cache key from arguments."""
data = json.dumps({"args": args, "kwargs": kwargs}, sort_keys=True)
return hashlib.sha256(data.encode()).hexdigest()[:16]
# Usage
key = cache_key("users", page=1, limit=20)
print(key) # Short hash for cache lookupSecurity Notes
# MD5 and SHA1 are broken for cryptographic purposes
# Use SHA-256 or BLAKE2 for new code
# For passwords, use these instead:
# - hashlib.pbkdf2_hmac()
# - argon2 (pip install argon2-cffi)
# - bcrypt (pip install bcrypt)
# Always use constant-time comparison
import hmac
hmac.compare_digest(a, b) # Safe
a == b # Vulnerable to timing attacksAlgorithm Selection
| Use Case | Recommended |
|---|---|
| General hashing | SHA-256, BLAKE2 |
| File checksums | SHA-256 |
| Password hashing | PBKDF2, argon2, bcrypt |
| HMAC | SHA-256, SHA-512 |
| Speed-critical | BLAKE2 |
| Legacy compatibility | SHA-1 (with caution) |
hashlib handles most hashing needs. Use it for integrity checks and HMAC, but reach for specialized libraries for password storage.
React to this post: