Skip to main content

Module password

Module password 

Source
Expand description

Password hashing (PBKDF2-HMAC-SHA256).

Like Rails’ has_secure_password, without bcrypt: Workers have no CPU budget for bcrypt or argon2 in WebAssembly (10 ms per request on the free plan), but WebCrypto (crypto.subtle.deriveBits) runs PBKDF2 natively, outside the WebAssembly module. Workers cap it at 100,000 iterations; Ocre uses the cap (ITERATIONS). Native builds (tests, tools) compute the same function in pure Rust.

Digests are self-describing, like Django’s: pbkdf2_sha256$100000$<salt, base64>$<hash, base64> (16-byte random salt, 32-byte hash, standard base64 without padding). The iteration count is stored, so it can grow later without invalidating existing passwords (iterations reads it back).

Cost: one hash measured at 5.5 ms of CPU in wrangler dev (README, “Authentication”), about half of the free plan’s 10 ms per request, so only sign-up, login and password changes should hash. hash and verify each run PBKDF2 once. Passwords are never logged: errors name the operation only.

use axum::{Form, extract::State};
use ocre::{Ctx, Error, Result};

// Sign up: store the digest, never the password.
async fn sign_up(Form(form): Form<Login>) -> Result<String> {
    let password_digest = ocre::password::hash(&form.password).await?;
    Ok(password_digest) // INSERT INTO users (email, password_digest) ...
}

// Log in: compare in constant time.
async fn log_in(State(ctx): State<Ctx>, Form(form): Form<Login>) -> Result<&'static str> {
    let user = find_by_email(&ctx, &form.email).await?.ok_or(Error::Unauthorized)?;
    if ocre::password::verify(&form.password, &user.password_digest).await? {
        Ok("signed in")
    } else {
        Err(Error::Unauthorized)
    }
}

Constants§

ITERATIONS
Iterations for new digests: 100,000, the most Workers’ WebCrypto accepts.

Functions§

hash
Hashes password with a new random 16-byte salt into a self-describing digest.
iterations
The iteration count stored in digest, or None when it is not in Ocre’s format.
verify
Whether password matches digest (made by hash), compared in constant time.