Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Zozi96/hash-forge/llms.txt

Use this file to discover all available pages before exploring further.

PasswordHashPolicy is a frozen dataclass that encodes a complete set of rules for password hashing in a single, reusable object. It declares which algorithm is preferred for new hashes, which algorithms are permitted for legacy verification, and whether deprecated or digest-only algorithms are blocked. Attaching a policy to HashManager via HashManager.from_policy() lets you enforce consistent hashing behaviour across your entire application from one place, rather than scattering algorithm choices across request handlers.
For new projects with no legacy hashes, PasswordHashPolicy.recommended() is the right starting point. It selects Argon2 as the preferred algorithm and includes PBKDF2-SHA256, bcrypt-SHA256, and Scrypt as fallbacks for future migration flexibility.

Built-in Policy Profiles

Modern default profile. Argon2 is preferred with sensible parameters. PBKDF2-SHA256, bcrypt-SHA256, and Scrypt are included to support gradual migration of any existing hashes. Best choice for new projects.
from hash_forge import HashManager, PasswordHashPolicy

policy = PasswordHashPolicy.recommended()
manager = HashManager.from_policy(policy)

hashed = manager.hash("my_secure_password")

ok, replacement = manager.verify_and_update("my_secure_password", hashed)
if replacement is not None:
    save_to_db(replacement)
The recommended profile uses:
  • preferred_algorithm: argon2
  • algorithms: ("argon2", "pbkdf2_sha256", "bcrypt_sha256", "scrypt")
  • Argon2 options: time_cost=3, memory_cost=65536, parallelism=1, hash_len=32

PasswordHashPolicy.fips()

FIPS 140-2 compliant profile. Uses PBKDF2-HMAC-SHA256 at 600,000 iterations — the iteration count recommended by NIST SP 800-132 as of 2023. PBKDF2-SHA1 is retained solely for verifying existing hashes.
from hash_forge import HashManager, PasswordHashPolicy

policy = PasswordHashPolicy.fips()
manager = HashManager.from_policy(policy)

hashed = manager.hash("fips_compliant_password")
The fips profile uses:
  • preferred_algorithm: pbkdf2_sha256
  • algorithms: ("pbkdf2_sha256", "pbkdf2_sha1")
  • PBKDF2 options: iterations=600_000

PasswordHashPolicy.legacy_compat()

Compatibility profile for systems with a variety of historical hash formats. PBKDF2-SHA256 is the preferred algorithm for all new hashes. Verification is permitted for bcrypt, bcrypt-SHA256, Scrypt, PBKDF2-SHA1, and RIPEMD-160 hashes. allow_legacy_verify=True is set explicitly.
from hash_forge import HashManager, PasswordHashPolicy

policy = PasswordHashPolicy.legacy_compat()
manager = HashManager.from_policy(policy)

# New hashes use PBKDF2-SHA256
new_hash = manager.hash("user_password")

# Existing bcrypt/scrypt/ripemd160 hashes can still be verified
is_valid = manager.verify("user_password", legacy_bcrypt_hash)

PasswordHashPolicy.calibrate(target_ms=250)

Auto-tunes the PBKDF2 iteration count so that a single hash operation takes at least target_ms milliseconds on the current hardware. Useful for ensuring consistent security cost across machines with different CPU speeds.
from hash_forge import HashManager, PasswordHashPolicy

# Tune to ~250ms on this machine (default)
policy = PasswordHashPolicy.calibrate(target_ms=250)
manager = HashManager.from_policy(policy)
calibrate starts at the library default and doubles the iteration count until the measured runtime meets or exceeds target_ms. It never exceeds 2,000,000 iterations.

Creating a HashManager from a Policy

Pass any policy instance to HashManager.from_policy():
from hash_forge import HashManager, PasswordHashPolicy

manager = HashManager.from_policy(PasswordHashPolicy.recommended())
The manager’s preferred_hasher is set to the policy’s preferred_algorithm, and all remaining algorithms are registered in the order they appear in policy.algorithms. The policy object is stored on manager.policy and consulted automatically by hash(), verify(), and needs_rehash().

Algorithm Categories

Hash Forge classifies every algorithm into one of four categories. The category determines what operations are permitted when a policy is active.
CategoryAlgorithmsPermitted operations
passwordargon2, bcrypt, bcrypt_sha256, pbkdf2_sha256, scryptHash + verify
legacypbkdf2_sha1, ripemd160Verify only (unless it is the preferred algorithm)
digestblake2, blake2b, blake3, sha3_256, sha3_512Verify only (new hashing blocked by default)
deprecatedwhirlpoolNew hashing blocked by default
You can inspect a category programmatically using the module-level helpers:
from hash_forge.policy import classify_algorithm, canonical_algorithm

print(classify_algorithm("argon2"))       # password
print(classify_algorithm("pbkdf2_sha1"))  # legacy
print(classify_algorithm("blake2b"))      # digest
print(classify_algorithm("whirlpool"))    # deprecated

print(canonical_algorithm("blake2b"))     # blake2
print(canonical_algorithm("RIPEMD-160"))  # ripemd160
whirlpool is classified as deprecated. By default, PasswordHashPolicy blocks any attempt to hash new passwords with it. Attempting to call manager.hash() when whirlpool is the preferred algorithm will raise a ValueError unless allow_deprecated_hashing=True is set on the policy.

Policy Enforcement

When a policy is attached to a HashManager, three enforcement methods are called automatically at runtime.

validate_for_hashing

Called by hash() before delegating to the preferred hasher. Raises ValueError when:
  • The algorithm is deprecated and allow_deprecated_hashing=False
  • The algorithm is a digest and allow_digest_password_hashing=False
  • The algorithm is legacy and is not the designated preferred_algorithm

validate_for_verify

Called by verify() after identifying the hasher. Raises ValueError (and causes verify to return False) when:
  • The algorithm is legacy and allow_legacy_verify=False

needs_update

Called by needs_rehash(). Returns True when either:
  • The algorithm of the stored hash differs from the policy’s preferred_algorithm
  • The underlying hasher reports that parameters have changed

Custom Policy

PasswordHashPolicy is a frozen dataclass. Construct it directly to define a fully custom profile:
from hash_forge import HashManager, PasswordHashPolicy

policy = PasswordHashPolicy(
    preferred_algorithm="argon2",
    algorithms=("argon2", "pbkdf2_sha256", "bcrypt_sha256"),
    algorithm_options={
        "argon2": {"time_cost": 4, "memory_cost": 65536},
        "pbkdf2_sha256": {"iterations": 300_000},
    },
)

manager = HashManager.from_policy(policy)
All constructor parameters:
ParameterTypeDefaultDescription
preferred_algorithmstrAlgorithm used for all new hashes
algorithmstuple[str, ...]Full set of supported algorithms
algorithm_optionsdict[str, dict]{}Per-algorithm constructor kwargs
allow_legacy_verifyboolTruePermit legacy algorithm verification
allow_digest_password_hashingboolFalsePermit digest algorithms for new hashes
allow_deprecated_hashingboolFalsePermit deprecated algorithms for new hashes
max_verify_costsdict[str, dict]{}Upper-bound cost params for verify (Scrypt)

Build docs developers (and LLMs) love