refactor: update hash_password and verify_password to use algorithm interface

This commit is contained in:
2025-11-13 13:18:22 +00:00
parent 6ca905cd1e
commit c85c68f859
2 changed files with 15 additions and 25 deletions

34
salt.py
View File

@@ -19,22 +19,15 @@ DEFAULT_ITERATIONS = int(os.environ.get("PBKDF2_ITERATIONS", "200000"))
def hash_password( def hash_password(
password: str, password: str,
*, *,
algorithm: str = "pbkdf2",
iterations: int | None = None, iterations: int | None = None,
salt_bytes: int = DEFAULT_SALT_BYTES, salt_bytes: int = DEFAULT_SALT_BYTES,
) -> tuple[str, str]: ) -> tuple[str, str]:
"""Return a base64 encoded salt and hash for ``password``.""" """Return a base64 encoded salt and hash for ``password``."""
iterations = iterations or DEFAULT_ITERATIONS from algorithms import get_algorithm
salt = os.urandom(salt_bytes)
derived = hashlib.pbkdf2_hmac( algo = get_algorithm(algorithm)
"sha256", return algo.hash(password, iterations=iterations, salt_bytes=salt_bytes)
password.encode("utf-8"),
salt,
iterations,
)
return (
base64.b64encode(salt).decode("utf-8"),
base64.b64encode(derived).decode("utf-8"),
)
def verify_password( def verify_password(
@@ -42,23 +35,14 @@ def verify_password(
salt_b64: str, salt_b64: str,
hash_b64: str, hash_b64: str,
*, *,
algorithm: str = "pbkdf2",
iterations: int | None = None, iterations: int | None = None,
) -> bool: ) -> bool:
"""Validate ``password`` against the provided base64 salt + hash pair.""" """Validate ``password`` against the provided base64 salt + hash pair."""
iterations = iterations or DEFAULT_ITERATIONS from algorithms import get_algorithm
try:
salt = base64.b64decode(salt_b64, validate=True)
stored_hash = base64.b64decode(hash_b64, validate=True)
except (binascii.Error, ValueError):
return False
derived = hashlib.pbkdf2_hmac( algo = get_algorithm(algorithm)
"sha256", return algo.verify(password, salt_b64, hash_b64, iterations=iterations)
password.encode("utf-8"),
salt,
iterations,
)
return hmac.compare_digest(derived, stored_hash)
def _build_parser() -> argparse.ArgumentParser: def _build_parser() -> argparse.ArgumentParser:

View File

@@ -18,3 +18,9 @@ def test_hash_password_returns_base64() -> None:
def test_verify_password_handles_invalid_base64() -> None: def test_verify_password_handles_invalid_base64() -> None:
assert verify_password("secret", "**invalid**", "???") is False assert verify_password("secret", "**invalid**", "???") is False
def test_hash_password_with_algorithm_parameter():
"""Verify hash_password accepts algorithm parameter."""
salt, hashed = hash_password("test", algorithm="pbkdf2")
assert verify_password("test", salt, hashed, algorithm="pbkdf2")