impl/python/hash_password.py
1,184 bytes · the Python implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import Sequence
from .crypto_pbkdf2_sha256 import pbkdf2_sha256 ← from crypto.pbkdf2-sha256 ^1.0.0 · built alongside by fune
from .encoding_base64_base64_encode import base64_encode
from .encoding_utf8_utf8_encode import utf8_encode
def hash_password(password: str, salt: Sequence[int], iterations: int) -> str:
"""A password as pbkdf2_sha256$<iterations>$<salt>$<hash>.
The salt is passed in because a capability may not read randomness:
pass list(secrets.token_bytes(16)) (or the bytes themselves), fresh for
every call.
"""
if not isinstance(password, str):
raise TypeError("password must be a string")
if isinstance(salt, (str, dict)) or not hasattr(salt, "__len__"):
raise TypeError("salt must be a list of integers from 0 to 255")
if len(salt) < 16:
raise ValueError("salt must be at least 16 bytes, received %d" % len(salt))
if isinstance(iterations, bool) or not isinstance(iterations, int) or iterations < 1000:
raise ValueError("iterations must be a whole number of at least 1000")
derived = pbkdf2_sha256(utf8_encode(password), salt, iterations, 32)
return "pbkdf2_sha256$%d$%s$%s" % (iterations, base64_encode(salt), base64_encode(derived))