"""Argon2 algorithm implementation.""" from __future__ import annotations import base64 import binascii from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError, InvalidHashError class Argon2Algorithm: """Argon2id password hashing algorithm.""" identifier = "argon2" def __init__(self): """Initialize with default Argon2 parameters.""" self._hasher = PasswordHasher() def hash(self, password: str, **kwargs) -> tuple[str, str]: """Hash a password using Argon2id. Note: Argon2 generates its own salt internally and returns a complete hash string that includes the salt and parameters. We return empty string for salt_b64 and the full hash as hash_b64. """ hash_string = self._hasher.hash(password) # Return empty salt since Argon2 embeds salt in hash return ("", base64.b64encode(hash_string.encode("utf-8")).decode("utf-8")) def verify( self, password: str, salt_b64: str, hash_b64: str, **kwargs, ) -> bool: """Verify a password against Argon2 hash. Note: salt_b64 is ignored since Argon2 embeds salt in the hash. """ try: hash_string = base64.b64decode(hash_b64, validate=True).decode("utf-8") self._hasher.verify(hash_string, password) return True except (VerifyMismatchError, InvalidHashError, binascii.Error, ValueError, UnicodeDecodeError): return False from algorithms import register_algorithm # Auto-register when module is imported register_algorithm(Argon2Algorithm())