NAME
Punk::Auth::Password - password hashing
SYNOPSIS
use Punk::Auth::Password;
my $stored = Punk::Auth::Password::hash($plain);
my $ok = Punk::Auth::Password::verify($plain, $stored);
if ($ok && Punk::Auth::Password::needs_rehash($stored)) {
$stored = Punk::Auth::Password::hash($plain); # upgrade in place
}
my $token = Punk::Auth::Password::token; # to mail
my $digest = Punk::Auth::Password::token_digest($token); # to store
DESCRIPTION
PBKDF2-HMAC-SHA256 in C, over the SHA-256 this distribution already bundles for sessions. No library dependency; salts come from the same entropy source the CSRF tokens use (getentropy where the build found it, /dev/urandom otherwise - a failure croaks rather than degrade).
The stored form is
pbkdf2-sha256$<iterations>$<salt base64>$<key base64>
with a 16-byte salt and a 32-byte derived key. The iteration count travels in the string, so verify always uses the cost a hash was created with and raising the default needs no migration: needs_rehash reports the old rows and a login re-hashes with the plaintext in hand.
Every function is also callable as a class method (Punk::Auth::Password->verify(...)); the invocant is skipped.
FUNCTIONS
hash($plain, $iterations?)
The stored string. Cost is the explicit argument, else the localizable $Punk::Auth::Password::ITERATIONS (default 60_000).
verify($plain, $stored)
True when the password matches. Constant-time over the derived key; an unparseable or undef stored value is simply false, so a user row with no password (an invited or federated-only account) can be handed straight in.
needs_rehash($stored, $iterations?)
True when the stored cost is below the current one, and true for anything unparseable or missing - failing toward a rehash is always safe, because the caller only acts on it after a successful verify.
token
32 random bytes as unpadded url-safe base64 - 43 characters. The plaintext half of a single-use token: mail it, never store it.
token_digest($token)
Lowercase SHA-256 hex of the token - the only form storage sees. Looking a token up by its digest means a leaked table cannot be replayed.
SEE ALSO
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)