The hashlib module in the Python standard library computes cryptographic hash digests. A hash function takes input data of any size and produces a fixed-size output called a digest. The same input always produces the same digest, but even a tiny change in the input produces a completely different digest.
Use hashes to verify file integrity, detect duplicate data, and create unique keys.
import hashlib
message = b"Hello, Python"
digest = hashlib.sha256(message).hexdigest()
print(digest) # 13796e71cca404af8be4e1a094de45557bed2e91bf4cd54056056bc83746186chashlib.sha256() creates a SHA-256 hash object. Passing the data directly to the constructor or calling .hexdigest() returns the hash as a 64-character hexadecimal string.
Hashing strings and bytes
Most real text starts out as a string, not raw bytes, so you need one extra step before hashing it. Hash functions operate on bytes, not strings, so encode strings before hashing.
import hashlib
text = "hello"
encoded = text.encode("utf-8")
digest = hashlib.sha256(encoded).hexdigest()
print(digest) # 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824text.encode("utf-8") converts the string to bytes. hexdigest() returns the hash as a 64-character hex string. The same input always produces the same output.
Available hash algorithms
hashlib supports many algorithms. Use hashlib.algorithms_available to see what your Python installation provides.
import hashlib
print(sorted(hashlib.algorithms_available)[:10])The exact list depends on the OpenSSL build your Python installation links against, but a typical result looks like this:
['blake2b', 'blake2s', 'md5', 'md5-sha1', 'sha1', 'sha224', 'sha256', 'sha384', 'sha3_224', 'sha3_256']| Algorithm | Digest size | Use case |
|---|---|---|
| SHA-256 | 32 bytes | General-purpose hashing (recommended) |
| SHA-384 | 48 bytes | Higher security margin |
| SHA-512 | 64 bytes | Maximum SHA-2 security |
| SHA-3-256 | 32 bytes | Newer standard, alternative to SHA-2 |
| BLAKE2b | Configurable | High performance, same security as SHA-3 |
| MD5 | 16 bytes | Legacy checksums only; broken for security |
| SHA-1 | 20 bytes | Deprecated; broken for security |
Avoid MD5 and SHA-1 for any security-sensitive code. They are vulnerable to collision attacks where two different inputs produce the same hash. SHA-256 and BLAKE2 are safe choices for new code.
Incremental hashing for large data
Hash large files in chunks to avoid loading the entire file into memory.
import hashlib
def file_checksum(path, algorithm="sha256"):
hasher = hashlib.new(algorithm)
with open(path, "rb") as file:
while chunk := file.read(8192):
hasher.update(chunk)
return hasher.hexdigest()hasher.update(chunk) feeds each chunk into the hash. The hash accumulates incrementally. After the entire file is processed, hexdigest() returns the final hash.
You can also build a hash incrementally from multiple sources:
import hashlib
hasher = hashlib.sha256()
hasher.update(b"Hello, ")
hasher.update(b"world!")
print(hasher.hexdigest()) # 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
print(hashlib.sha256(b"Hello, world!").hexdigest()) # 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3Incremental updates produce the same digest as hashing the concatenated data all at once.
Raw bytes vs hex digest
digest() returns the hash as raw bytes. hexdigest() returns it as a hexadecimal string.
| digest() | hexdigest() | |
|---|---|---|
| Return type | bytes | str |
| Length for SHA-256 | 32 bytes | 64 characters |
| Best for | Compact storage, further crypto operations | Display, logging, JSON |
import hashlib
digest_bytes = hashlib.sha256(b"data").digest()
digest_hex = hashlib.sha256(b"data").hexdigest()
print(len(digest_bytes)) # 32
print(digest_hex) # 3a6eb0790f39ac87c94f3856b2dd2c5d110e6811602261a9a923d3bb23adc8b7Use digest() when you need compact storage or need to pass the hash to another cryptographic function. Use hexdigest() for display, logging, and human-readable output.
Using BLAKE2 for performance
BLAKE2 is faster than SHA-256 with the same security level. It also supports keyed hashing and variable-length digests.
import hashlib
data = b"Large data payload" * 1000
h1 = hashlib.blake2b(data).hexdigest()
h2 = hashlib.sha256(data).hexdigest()
print(f"BLAKE2b: {h1[:40]}...")
print(f"SHA-256: {h2[:40]}...")Both lines hash the exact same 19 KB payload, so the difference in the printed prefixes comes only from the algorithm, not the input:
BLAKE2b: 64c755d5ebdd5a46556337e137fa5eed6d7ee828...
SHA-256: b33259c2f3a9f109bf530bbf413a3c48ab2154a2...BLAKE2b produces a 64-byte digest by default, but unlike SHA-256, you can configure the output length to any size up to that maximum by passing digest_size:
hasher = hashlib.blake2b(digest_size=16)
hasher.update(b"data")
print(hasher.hexdigest()) # 82f64e6be809763df98195dfa5de656cThis produces a 16-byte (32 hex character) digest. SHA-256 is fixed at 32 bytes.
Password hashing with scrypt
Hash functions like SHA-256 are designed to be fast, which makes them unsuitable for password storage. A fast hash means an attacker can try billions of passwords per second. hashlib.scrypt() is intentionally slow and memory-intensive to resist brute-force attacks.
import hashlib
import os
password = b"correct horse battery staple"
salt = os.urandom(16)
hashed = hashlib.scrypt(password, salt=salt, n=16384, r=8, p=1)
print(hashed.hex())scrypt takes a password, a random salt, and cost parameters that control how slow and memory-intensive the computation is. Store the salt and the hash together for later verification. For production password storage, also consider using the bcrypt or argon2 libraries, which provide simpler interfaces with built-in salt generation.
Practical example: verifying downloaded files
A common use of hashing is verifying that a downloaded file has not been corrupted or tampered with.
import hashlib
def verify_file(filepath, expected_hash, algorithm="sha256"):
hasher = hashlib.new(algorithm)
with open(filepath, "rb") as file:
while chunk := file.read(8192):
hasher.update(chunk)
actual = hasher.hexdigest()
if actual != expected_hash:
print(f"Mismatch! Expected: {expected_hash[:16]}..., got: {actual[:16]}...")
return False
print("File verified successfully.")
return TrueCalling the function checks a downloaded file against the hash published by the file's distributor, printing a clear success or mismatch message depending on whether the computed digest matches:
verify_file("python-3.14.tar.xz", "d3b5c8...")The function reads the file in 8 KB chunks, computes the SHA-256 hash, and compares it with the expected value published by the file distributor. A mismatch indicates either corruption or tampering.
Common mistakes
Using MD5 or SHA-1 for security. Both are broken for collision resistance. Use SHA-256 or BLAKE2 for integrity verification and any security-sensitive hashing.
Hashing passwords with SHA-256. SHA-256 is designed to be fast. Password hashing should be slow to resist brute-force attacks. Use hashlib.scrypt(), bcrypt, or argon2 for passwords.
Forgetting to encode strings. Hash functions work on bytes. Always call .encode("utf-8") on strings before hashing, or pass bytes directly.
Comparing hashes with compare_digest when the expected hash is public. secrets.compare_digest prevents timing attacks, but if the expected hash is already known to the attacker (like a published file checksum), there is no secret to protect. Regular == is fine for public integrity checks.
Rune AI
Key Insights
- Use
hashlib.sha256(data).hexdigest()to compute a SHA-256 hash as a hex string. - Hash files in chunks with
.update()to avoid loading the entire file into memory. - Use
hashlib.blake2b()for faster hashing with the same security as SHA-256. - Do not use SHA-256 or MD5 for password storage; use
hashlib.scrypt()or a dedicated library. hashlib.algorithms_availablelists every hash algorithm your Python installation supports.- The
.digest()method returns raw bytes;.hexdigest()returns a hex string.
Frequently Asked Questions
Which hash algorithm should I use?
Can I use hashlib for password storage?
How do I hash a large file without loading it into memory?
Conclusion
The hashlib module is the standard way to compute cryptographic hashes in Python. Use SHA-256 for integrity checks and file verification, BLAKE2 for high-performance hashing, and scrypt for password storage. Avoid MD5 and SHA-1 for any new security-sensitive code. Always read large files in chunks when computing hashes.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.