How to mock Argon2 password hashing in Python

This code demonstrates a mock Argon2 password hasher using HMAC-SHA256 iterations, providing hash and verify methods that mimic Argon2's salted, iterated derivation.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 14 views 0 copies

Python code

43 lines
Python 3.9+
import hashlib
import hmac
import os


class Argon2Mock:
    def __init__(self, salt_size=16, hash_len=32):
        self.salt_size = salt_size
        self.hash_len = hash_len
        
    def hash(self, password: str, salt: bytes = None) -> str:
        if salt is None:
            salt = os.urandom(self.salt_size)
        elif len(salt) != self.salt_size:
            raise ValueError(f"Salt must be {self.salt_size} bytes")
            
        # Mock Argon2 derivation: iterate HMAC-SHA256 to simulate hashing
        derived = salt
        for _ in range(10000):  # Simple iteration count
            derived = hmac.new(derived, password.encode(), hashlib.sha256).digest()
        
        derived = derived[:self.hash_len]
        return f"argon2$v=19$m=65536,t=3,p=4$" \
            f"{salt.hex()}$" \
            f"{derived.hex()}"
    
    def verify(self, password: str, encoded: str) -> bool:
        try:
            parts = encoded.split("$")
            salt_hex, hash_hex = parts[-2], parts[-1]
            salt = bytes.fromhex(salt_hex)
            expected = self.hash(password, salt)
            return hmac.compare_digest(expected, encoded)
        except Exception:
            return False


if __name__ == "__main__":
    argon = Argon2Mock()
    hashed = argon.hash("mySecretPass!42")
    print("Encoded:", hashed)
    print("Valid password:", argon.verify("mySecretPass!42", hashed))
    print("Invalid password:", argon.verify("wrongPass", hashed))

Output

stdout
Encoded: argon2$v=19$m=65536,t=3,p=4$<salt_hex>$<hash_hex>
Valid password: True
Invalid password: False

How it works

This mock simulates Argon2's core idea: a salt, iterative hashing, and a formatted output string. The HMAC-SHA256 loop repeats 10,000 times to emulate the CPU cost. The salt prevents rainbow table attacks, and the output format includes parameters for potential verification. Real Argon2 uses specialized algorithms (Argon2d, Argon2i, Argon2id) tuned for memory hardness; this mock is for education or prototyping only. The verify method extracts the salt and re-derives the hash, then compares with hmac.compare_digest to prevent timing attacks.

Common mistakes

  • Using a fixed salt, which defeats the purpose of salting
  • Forgetting to check the salt length before hashing
  • Comparing hashes with plain equality instead of hmac.compare_digest
  • Treating this mock as secure for production

Variations

  1. Use the 'argon2-cffi' library (pip install argon2-cffi) for real Argon2 hashing
  2. Implement a different iteration count or use 'hashlib.pbkdf2_hmac' for a more standard KDF

Real-world use cases

  • Prototyping a user registration flow before integrating with a real password hashing library.
  • Writing unit tests for authentication logic without requiring external Argon2 dependencies.
  • Teaching password hashing concepts in a controlled environment where security is not the goal.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.