Hash and verify passwords using the modular crypt format.
const CryptFormatHasher = struct
const CryptFormatHasher = struct {
/// Length of a string returned by the create() function
const pwhash_str_length: usize = hash_length;
/// Return a non-deterministic hash of the password encoded into the modular crypt format
fn create(
password: []const u8,
params: Params,
buf: []u8,
io: std.Io,
) HasherError![]const u8 {
var salt: [salt_length]u8 = undefined;
io.random(&salt);
return createWithSalt(password, params, buf, &salt);
}
/// Return a deterministic hash of the password encoded into the modular crypt format.
/// Uses the provided salt instead of generating one randomly.
fn createWithSalt(
password: []const u8,
params: Params,
buf: []u8,
salt: *const [salt_length]u8,
) HasherError![]const u8 {
if (buf.len < pwhash_str_length) return HasherError.NoSpaceLeft;
const hash = crypt_format.strHashInternal(password, salt, params);
@memcpy(buf[0..hash.len], &hash);
return buf[0..pwhash_str_length];
}
/// Verify a password against a string in modular crypt format
fn verify(
str: []const u8,
password: []const u8,
silently_truncate_password: bool,
) HasherError!void {
if (str.len != pwhash_str_length or str[3] != '$' or str[6] != '$')
return HasherError.InvalidEncoding;
const rounds_log_str = str[4..][0..2];
const rounds_log = fmt.parseInt(u6, rounds_log_str[0..], 10) catch
return HasherError.InvalidEncoding;
const salt_str = str[7..][0..salt_str_length];
var salt: [salt_length]u8 = undefined;
crypt_format.Codec.Decoder.decode(&salt, salt_str) catch return HasherError.InvalidEncoding;
const wanted_s = crypt_format.strHashInternal(password, &salt, .{
.rounds_log = rounds_log,
.silently_truncate_password = silently_truncate_password,
});
if (!mem.eql(u8, wanted_s[0..], str[0..])) return HasherError.PasswordVerificationFailed;
}
}