"""Password hashing with Argon2id. Handles user password storage for the auth DB. Uses argon2-cffi (C implementation of the Argon2id memory-hard KDF). Random 16-byte salt is generated per hash by the library. Argon2id is used for auth user passwords ONLY. Nginx basic-auth htpasswd files continue to use sha256_crypt (passlib) — that's a separate concern with different constraints (htpasswd format is standardized). """ from __future__ import annotations from argon2 import PasswordHasher from argon2.exceptions import InvalidHashError, VerifyMismatchError from argon2.low_level import Type # Argon2id: OWASP recommended parameters # 64 MiB memory, 3 iterations, 4 parallel threads _PH = PasswordHasher( time_cost=3, memory_cost=65536, # 64 MiB parallelism=4, hash_len=32, salt_len=16, type=Type.ID, ) def hash_password(password: str) -> str: """Generate an Argon2id hash of *password*. A random 16-byte salt is generated automatically by argon2. The resulting hash string starts with ``$argon2id$`` and encodes the algorithm version, parameters, salt, and hash output. Args: password: Plain-text password string. Returns: Full Argon2id hash string (e.g. ``$argon2id$v=19$m=65536,t=3,p=4$...``). Raises: TypeError: If *password* is not a string or contains NUL bytes. """ return _PH.hash(password) def verify_password(password: str, hash_string: str) -> bool: """Verify *password* against an Argon2id *hash_string*. The hash string must have been produced by :func:`hash_password`. Args: password: Plain-text password to verify. hash_string: Argon2id hash string to compare against. Returns: ``True`` if the password matches, ``False`` otherwise. Raises: TypeError: If *hash_string* is not a valid Argon2id hash. """ try: _PH.verify(hash_string, password) return True except (InvalidHashError, VerifyMismatchError, ValueError): return False def needs_rehash(hash_string: str) -> bool: """Check if *hash_string* needs to be rehashed with updated parameters. Returns True if the hash was not produced with the current parameters of the hasher, indicating it should be rehashed on next login. Args: hash_string: Argon2id hash string to check. Returns: ``True`` if the hash parameters should be upgraded. """ return _PH.check_needs_rehash(hash_string)