Skip to main content

How to Generate an MD5 Hash in Python

MD5 (Message-Digest Algorithm 5) is a cryptographic hash function that produces a fixed 128-bit (16-byte) hash value, typically represented as a 32-character hexadecimal string. While MD5 is no longer considered secure for cryptographic purposes due to known collision vulnerabilities, it remains widely used for non-security-critical tasks like file integrity verification, duplicate detection, and quick checksums.

In this guide, you will learn how to generate MD5 hashes in Python using the built-in hashlib module, understand the key methods involved, and see practical use cases with complete examples.

Understanding the Key Methods​

Python's hashlib module provides a straightforward interface for generating MD5 hashes. Here are the essential methods:

MethodDescriptionOutput Format
encode()Converts a string to bytes (required by hashlib)Byte sequence
hashlib.md5(data)Creates an MD5 hash object from byte dataHash object
digest()Returns the hash as raw bytes (16 bytes)Binary (not human-readable)
hexdigest()Returns the hash as a hexadecimal string (32 characters)Human-readable string

Generating an MD5 Hash From a String​

The most common use case is hashing a string. Since hashlib.md5() requires bytes as input, you must encode the string first:

import hashlib

text = "TutorialReference"
md5_hash = hashlib.md5(text.encode())

print(md5_hash.hexdigest())

Output:

8a891e375972f4d9421056b201e7610c

The hexdigest() method returns the hash as a readable 32-character hexadecimal string, which is the format you will use most often.

Generating an MD5 Hash From Bytes​

If your data is already in bytes (e.g., read from a binary file), you can pass it directly without encoding:

import hashlib

data = b'TutorialReference'
md5_hash = hashlib.md5(data)

print("Hex digest:", md5_hash.hexdigest())
print("Raw digest:", md5_hash.digest())

Output:

Hex digest: 8a891e375972f4d9421056b201e7610c
Raw digest: b'\x8a\x89\x1e7Yr\xf4\xd9B\x10V\xb2\x01\xe7a\x0c'

The digest() method returns the raw 16-byte binary hash. This is primarily used in cryptographic protocols or when the hash needs to be stored as compact binary data.

Common mistake: forgetting to encode strings

Passing a string directly to hashlib.md5() without encoding raises a TypeError:

import hashlib

# ❌ Raises TypeError: Unicode-objects must be encoded before hashing
md5_hash = hashlib.md5("TutorialReference")
# TypeError: Strings must be encoded before hashing

Fix: Always call .encode() on strings:

import hashlib

# ✅ Correct
md5_hash = hashlib.md5("TutorialReference".encode())

Hashing Large Data With update()​

For large files or streaming data, loading everything into memory at once is impractical. Use the update() method to feed data to the hash function incrementally:

import hashlib

md5_hash = hashlib.md5()

# Feed data in chunks
md5_hash.update(b"Hello, ")
md5_hash.update(b"World!")

print(md5_hash.hexdigest())

Output:

65a8e27d8879283831b664bd8b7f0ad4
note

This produces the same result as hashing b"Hello, World!" all at once. The update() method is cumulative: each call appends data to the internal state.

Practical Use Cases​

Computing the MD5 Hash of a File​

File hashing is one of the most common applications of MD5. Reading the file in chunks ensures memory efficiency even for very large files:

import hashlib

def md5_of_file(filepath, chunk_size=8192):
"""Compute the MD5 hash of a file."""
md5_hash = hashlib.md5()

with open(filepath, 'rb') as f:
while chunk := f.read(chunk_size):
md5_hash.update(chunk)

return md5_hash.hexdigest()


# Usage
file_hash = md5_of_file("example.txt")
print(f"MD5: {file_hash}")
tip

The walrus operator (:=) used in while chunk := f.read(chunk_size) reads chunks until the file is exhausted. For Python versions before 3.8, use:

while True:
chunk = f.read(chunk_size)
if not chunk:
break
md5_hash.update(chunk)

Verifying Data Integrity​

Compare the MD5 hash of downloaded data against a known hash to verify it was not corrupted during transfer:

import hashlib

expected_hash = "8a891e375972f4d9421056b201e7610c"
data = "TutorialReference"

actual_hash = hashlib.md5(data.encode()).hexdigest()

if actual_hash == expected_hash:
print("✅ Data integrity verified.")
else:
print("❌ Data may be corrupted!")

Output:

✅ Data integrity verified.

Detecting Duplicate Files​

MD5 hashes can quickly identify duplicate files by comparing their hash values instead of their full contents:

import hashlib
import os

def find_duplicates(directory):
"""Find duplicate files in a directory based on MD5 hash."""
hash_map = {}
duplicates = []

for filename in os.listdir(directory):
filepath = os.path.join(directory, filename)
if os.path.isfile(filepath):
file_hash = md5_of_file(filepath)
if file_hash in hash_map:
duplicates.append((filename, hash_map[file_hash]))
else:
hash_map[file_hash] = filename

return duplicates

Generating a Simple Cache Key​

MD5 is useful for generating cache keys from complex inputs:

import hashlib
import json

def make_cache_key(params):
"""Generate a cache key from a dictionary of parameters."""
param_string = json.dumps(params, sort_keys=True)
return hashlib.md5(param_string.encode()).hexdigest()


key = make_cache_key({"user": "alice", "page": 3, "sort": "date"})
print(f"Cache key: {key}")

Output:

Cache key: 9eba11e47e8275bae11cb3747ece8e68

MD5 Properties at a Glance​

PropertyValue
Hash length128 bits (16 bytes)
Hex digest length32 characters
SpeedVery fast
Collision resistance❌ Broken: collisions can be generated
Suitable for passwords❌ No
Suitable for checksums✅ Yes (non-security contexts)
Suitable for digital signatures❌ No

Limitations and Security Concerns​

Do NOT use MD5 for security-sensitive applications

MD5 has well-documented vulnerabilities:

  • Collision attacks: Researchers have demonstrated that two different inputs can produce the same MD5 hash. This makes MD5 unsuitable for digital signatures, certificate validation, or any scenario where uniqueness is critical.
  • Speed enables brute force: MD5's fast computation speed makes it easy for attackers to generate millions of hashes per second, making password cracking trivial.

For security-sensitive tasks, use these alternatives instead:

import hashlib

# ✅ SHA-256: suitable for data integrity in security contexts
sha256 = hashlib.sha256("data".encode()).hexdigest()

# ✅ SHA-3: latest standard, strong security
sha3 = hashlib.sha3_256("data".encode()).hexdigest()

# ✅ For password hashing, use bcrypt or argon2
# pip install bcrypt
import bcrypt
hashed_password = bcrypt.hashpw("password".encode(), bcrypt.gensalt())

Conclusion​

Python's hashlib module makes generating MD5 hashes simple and efficient.

Use hashlib.md5(data.encode()).hexdigest() for quick string hashing, and update() for streaming large files in chunks. MD5 remains a practical tool for file integrity checks, duplicate detection, cache key generation, and other non-security tasks where speed and simplicity matter more than cryptographic strength.

For any application where security is a concern, such as passwords, digital signatures, or tamper detection, always choose a stronger algorithm like SHA-256 or bcrypt.