module Bezel::Password
Password hashes: argon2id (Crypto::Argon2), as PHC strings
($argon2id$v=19$m=19456,t=2,p=1$<salt>$<hash>) that name their
parameters, with a random salt and a check in constant time.
cheap = Crypto::Argon2::Params.new(memory_kib: 64, iterations: 1, parallelism: 1)
h = Bezel::Password.hash("correct horse", params: cheap)
Bezel::Password.verify?("correct horse", h) # => true
Bezel::Password.verify?("wrong horse", h) # => false
Bezel::Password.needs_rehash?(h) # => true
The parameters are the application's Config#password_params
(Settings's password_params:, Crypto::Argon2::Params::DEFAULT
unless set): give them to hash and needs_rehash?, and after a
successful login hash the password again when needs_rehash? says so.
A hash takes tens of milliseconds and memory_kib of memory (19 MiB by
default) on a helper thread: a server that takes many logins at once
should bound how many it checks together; an application's test:
settings can give cheap ones (Crypto::Argon2::Params.new(memory_kib: 64, iterations: 1, parallelism: 1)) to keep its tests fast.
Class methods
def self.hash(password: String, *, params: Crypto::Argon2::Params = …) -> String
The hash of password, with a fresh 16-byte salt.
def self.verify?(password: String, hashed: String) -> Bool
Whether password is the one hashed was made from. A string that
is not an argon2id hash (another scheme, garbage) raises
Crypto::Error, so that a broken stored hash is noticed rather than
taken for a wrong password.
def self.needs_rehash?(hashed: String, params: Crypto::Argon2::Params = …) -> Bool
Whether hashed was made with parameters below params, or is of
another scheme: hash the password again after a login. An argon2id
string that does not parse raises Crypto::Error.