Skip to main content

Module password

Module password 

Source
Expand description

Password hashing for the web admin’s operators.

PBKDF2-HMAC-SHA256 over ring::pbkdf2, which is already this crate’s crypto backend everywhere else. Deliberately not Argon2id, which is the stronger primitive: it would add four crates (argon2, password-hash, base64ct, blake2) to a certificate authority’s dependency graph – all of them audited on every cargo deny check, since deny.toml runs with all-features = true – for a subsystem that is enabled = false by default and whose password is the bootstrap credential in a design that ends in a second factor. PBKDF2-HMAC-SHA256 at 600 000 iterations is OWASP’s current recommendation for the non-Argon2 case.

The stored form is self-describing, so that trade can be revisited without a migration: raising the iteration count, or swapping the algorithm outright, needs a new branch in verify_password and nothing else – needs_rehash then re-encodes each row on its owner’s next successful login.

pbkdf2-sha256$600000$<salt-b64url>$<hash-b64url>

The other half of this module is check_password_policy, which is the single place every rule about an acceptable password lives. Three of them: length, a list of words naming this deployment (PasswordContext), and a corpus of common passwords compiled in from corpus/common-passwords.txt. The last two are ASVS 5.0 V6.2.11 and V6.2.4/V6.2.12, and both rest on the same observation – the length rule has already refused everything short, so a corpus filtered at MIN_PASSWORD_LEN is 195 KB where the list it was derived from is 8.5 MB. corpus/README.md has the provenance and the budget.

This module holds no database access and no I/O: it is shared by the CLI (admin user create/passwd) and the web login path, which is why it lives under admin:: beside the other logic both front ends use rather than inside webadmin::.

Structs§

PasswordContext
The words that name this deployment, barred from an operator’s password.

Enums§

PasswordError
A stored hash that could not be read back.

Constants§

MAX_PASSWORD_LEN
Longest password accepted. A DoS control, not a security one: without it a login request could hand 600 000 iterations a multi-megabyte input.
MIN_PASSWORD_LEN
Shortest password accepted. Length is the only rule – composition rules (“one digit, one symbol”) measurably push people towards weaker, more guessable passwords, and this is an operator-facing surface with a handful of accounts, not a consumer signup.
RECOVERY_ITERATIONS
The cost hash_generated_secret uses. Named so the reasoning above has something to point at.

Functions§

check_password_policy
Rejects a password before it is ever hashed.
dummy_hash
A well-formed hash of nothing, verified against when the username is unknown so a miss costs the same KDF time as a wrong password.
hash_generated_secret
Hashes a high-entropy generated secret, at a cost matched to the fact that it is one.
hash_password
Hashes password under the current parameters, returning the encoded form to store.
hash_password_off_runtime
hash_password on tokio’s blocking pool, for the login path’s rehash. None only when the runtime is shutting down; the rehash then waits for the next login.
needs_rehash
Whether stored was written under parameters this build has since moved past – a different algorithm, or a lower iteration count.
verify_password
Verifies password against a stored hash, in constant time (ring::pbkdf2::verify compares that way).
verify_password_off_runtime
verify_password on tokio’s blocking pool.