Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
Password hashing in Python with pbkdf2#
I was researching password hashing for datasette-auth-passwords. I wanted very secure defaults that would work using the Python standard library without any extra dependencies.
I ended up following Django’s example and implementing pbkdf2_sha256 with 260,000 iterations. Here’s my version of the way Django does this - I chose to use the same hashed password format (algorithm$iterations$salt$hash) in case I wanted to change the hashing algorithm used in the future.
1import base642import hashlib3import secrets4
5ALGORITHM = "pbkdf2_sha256"6
7
8def hash_password(password, salt=None, iterations=260000):9 if salt is None:10 salt = secrets.token_hex(16)11 assert salt and isinstance(salt, str) and "$" not in salt12 assert isinstance(password, str)13 pw_hash = hashlib.pbkdf2_hmac(14 "sha256", password.encode("utf-8"), salt.encode("utf-8"), iterations15 )16 b64_hash = base64.b64encode(pw_hash).decode("ascii").strip()17 return "{}${}${}${}".format(ALGORITHM, iterations, salt, b64_hash)18
19
20def verify_password(password, password_hash):21 if (password_hash or "").count("$") != 3:22 return False23 algorithm, iterations, salt, b64_hash = password_hash.split("$", 3)24 iterations = int(iterations)25 assert algorithm == ALGORITHM26 compare_hash = hash_password(password, salt, iterations)27 return secrets.compare_digest(password_hash, compare_hash)Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.