scrypt Password Hash And Verify

Hash passwords with scrypt and a per-user salt, then verify them with a constant-time comparison.

PythonSecurity Boundaries

Code

snippet
import hashlib
import hmac
import os

N = 2 ** 14
R = 8
P = 1
KEY_LEN = 32
SALT_LEN = 16

def hash_password(password: str) -> str:
    salt = os.urandom(SALT_LEN)
    digest = hashlib.scrypt(password.encode('utf-8'), salt=salt, n=N, r=R, p=P, dklen=KEY_LEN)
    return f'scrypt${N}${R}${P}${salt.hex()}${digest.hex()}'

def verify_password(password: str, encoded: str) -> bool:
    parts = encoded.split('$')
    if len(parts) != 5 or parts[0] != 'scrypt':
        return False
    _, n, r, p, rest = parts
    salt_hex, digest_hex = rest[:SALT_LEN * 2], rest[SALT_LEN * 2:]
    expected = bytes.fromhex(digest_hex)
    digest = hashlib.scrypt(password.encode('utf-8'), salt=bytes.fromhex(salt_hex),
                            n=int(n), r=int(r), p=int(p), dklen=len(expected))
    return hmac.compare_digest(digest, expected)