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.

src/password.qz:22

Class methods

def self.hash(password: String, *, params: Crypto::Argon2::Params = …) -> String

The hash of password, with a fresh 16-byte salt.

src/password.qz:24

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.

src/password.qz:32

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.

src/password.qz:37