| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546 |
- import base64
- import hashlib
- import hmac
- import secrets
- PBKDF2_ITERATIONS = 260_000
- PASSWORD_HASH_PREFIX = "pbkdf2_sha256"
- def hash_password(password: str) -> str:
- salt = secrets.token_bytes(16)
- digest = hashlib.pbkdf2_hmac(
- "sha256",
- password.encode("utf-8"),
- salt,
- PBKDF2_ITERATIONS)
- return "$".join(
- [
- PASSWORD_HASH_PREFIX,
- str(PBKDF2_ITERATIONS),
- base64.b64encode(salt).decode("ascii"),
- base64.b64encode(digest).decode("ascii"),
- ]
- )
- def verify_password(password: str, password_hash: str | None) -> bool:
- if not password_hash:
- return False
- try:
- algorithm, iterations_raw, salt_raw, digest_raw = password_hash.split("$", 3)
- if algorithm != PASSWORD_HASH_PREFIX:
- return False
- iterations = int(iterations_raw)
- salt = base64.b64decode(salt_raw.encode("ascii"))
- expected_digest = base64.b64decode(digest_raw.encode("ascii"))
- except (ValueError, TypeError):
- return False
- actual_digest = hashlib.pbkdf2_hmac(
- "sha256",
- password.encode("utf-8"),
- salt,
- iterations)
- return hmac.compare_digest(actual_digest, expected_digest)
|