hashlib
The hashlib module provides secure hash functions for password storage, data integrity verification, and digital signatures. It includes implementations of MD5, SHA-1, SHA-256, SHA-512, and many other algorithms.
Syntax
import hashlib
# Create a hash object
h = hashlib.sha256()
h.update(b"data to hash")
digest = h.hexdigest()
Or using the one-shot API (Python 3.8+):
hashlib.sha256(b"data to hash").hexdigest()
Available Hash Algorithms
SHA-256
The most common choice for general-purpose hashing. Provides 256-bit output.
import hashlib
# One-shot API (Python 3.8+)
result = hashlib.sha256(b"hello world").hexdigest()
print(result)
# 94ee059335e587e501cc4bf83d831f5e077e7ec4aebedb208b4cd4e21d8e3917
# Using update for streaming
h = hashlib.sha256()
h.update(b"hello ")
h.update(b"world")
print(h.hexdigest())
# 94ee059335e587e501cc4bf83d831f5e077e7ec4aebedb208b4cd4e21d8e3917
# Binary digest (raw bytes)
print(hashlib.sha256(b"hello").digest())
# b'\x2c\x26\x93\x92...'
SHA-512
Provides 512-bit output. Slower than SHA-256 but more secure against collision attacks.
import hashlib
result = hashlib.sha512(b"hello world").hexdigest()
print(result)
# 2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae5a71e4452e994e1b4b0361e52ca67867c54a8b3d64e9a2c1c6c7c8e4e52ca678
SHA-1
Deprecated for security purposes. Use SHA-256 or SHA-512 instead.
import hashlib
import warnings
# Still works but deprecated
result = hashlib.sha1(b"hello world").hexdigest()
print(result)
# 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
MD5
Deprecated for security purposes. Use SHA-256 instead. Still useful for non-security purposes like quick checksums for file integrity.
import hashlib
result = hashlib.md5(b"hello world").hexdigest()
print(result)
# 5eb63bbbe01eeed093cb22bb8f5acdc3
Using hashlib.new()
Create a hash object with any available algorithm by name:
import hashlib
# blake2b - modern, fast, and cryptographically secure
h = hashlib.new("blake2b")
h.update(b"data")
print(h.hexdigest())
# 1a0e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e9f7e
# Check available algorithms
print(hashlib.algorithms_available)
# {'sha256', 'sha512', 'blake2b', 'blake2s', 'md5', ...}
Using hashlib.pbkdf2_hmac()
Derive a key from a password using PBKDF2 (Password-Based Key Derivation Function 2):
import hashlib
import os
password = b"my secure password"
salt = os.urandom(16) # Random salt
# Key derivation with 100,000 iterations
key = hashlib.pbkdf2_hmac('sha256', password, salt, 100000)
print(key.hex())
# 3d2e1c0a7c1f4e5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9
# Verify by re-computing with same salt
key2 = hashlib.pbkdf2_hmac('sha256', password, salt, 100000)
print(key == key2)
# True
Common Patterns
Password Hashing
Never store plain-text passwords. Always hash with a salt:
import hashlib
import secrets
def hash_password(password: str) -> tuple[str, str]:
"""Hash a password with a random salt."""
salt = secrets.token_hex(16)
pwd_bytes = password.encode('utf-8')
salt_bytes = bytes.fromhex(salt)
# Use many iterations for security
hashed = hashlib.pbkdf2_hmac('sha256', pwd_bytes, salt_bytes, 100000)
return hashed.hex(), salt
def verify_password(password: str, stored_hash: str, salt: str) -> bool:
"""Verify a password against a stored hash."""
pwd_bytes = password.encode('utf-8')
salt_bytes = bytes.fromhex(salt)
new_hash = hashlib.pbkdf2_hmac('sha256', pwd_bytes, salt_bytes, 100000)
return new_hash.hex() == stored_hash
# Usage
hashed, salt = hash_password("mypassword")
print(verify_password("mypassword", hashed, salt)) # True
print(verify_password("wrongpassword", hashed, salt)) # False
File Checksum
Verify file integrity by computing a hash:
import hashlib
def file_hash(filepath: str, algorithm: str = "sha256") -> str:
"""Compute hash of a file."""
h = hashlib.new(algorithm)
with open(filepath, "rb") as f:
while chunk := f.read(8192):
h.update(chunk)
return h.hexdigest()
# Usage
# print(file_hash("large_file.zip"))
Constant-Time Comparison
Use secrets.compare_digest to compare hashes safely (prevents timing attacks):
import hashlib
import secrets
stored_hash = hashlib.sha256(b"password123").hexdigest()
input_hash = hashlib.sha256(b"password123").hexdigest()
# Safe comparison
if secrets.compare_digest(stored_hash, input_hash):
print("Passwords match!")
Security Notes
- SHA-1 and MD5 are deprecated for security. Use for checksums only.
- SHA-256 is the minimum recommended for new applications.
- PBKDF2 with 100,000+ iterations is recommended for password hashing.
- bcrypt or argon2 are better choices for password storage than raw PBKDF2.
- Always use a unique random salt for each password.