"""Хеширование паролей (PBKDF2-SHA256, без внешних зависимостей).""" from __future__ import annotations import hashlib import hmac import secrets _ITERATIONS = 210_000 _SALT_BYTES = 16 _DKLEN = 32 def hash_password(password: str) -> str: salt = secrets.token_bytes(_SALT_BYTES) digest = hashlib.pbkdf2_hmac( "sha256", password.encode("utf-8"), salt, _ITERATIONS, dklen=_DKLEN, ) return f"pbkdf2_sha256${_ITERATIONS}${salt.hex()}${digest.hex()}" def verify_password(password: str, password_hash: str) -> bool: try: algo, iters_s, salt_hex, digest_hex = password_hash.split("$", 3) if algo != "pbkdf2_sha256": return False iterations = int(iters_s) salt = bytes.fromhex(salt_hex) expected = bytes.fromhex(digest_hex) except (ValueError, TypeError): return False got = hashlib.pbkdf2_hmac( "sha256", password.encode("utf-8"), salt, iterations, dklen=len(expected), ) return hmac.compare_digest(got, expected) def new_session_token() -> str: return secrets.token_urlsafe(32)