Hash and verify passwords using the modular crypt format.
const CryptFormatHasher = struct
const CryptFormatHasher = struct {
const BinValue = crypt_format.BinValue;
const HashResult = crypt_format.HashResult(max_hash_len);
/// Length of a string returned by the create() function
pub const pwhash_str_length: usize = 101;
/// Return a non-deterministic hash of the password encoded into the modular crypt format
pub fn create(
allocator: mem.Allocator,
password: []const u8,
params: Params,
buf: []u8,
io: std.Io,
) HasherError![]const u8 {
var salt_bin: [default_salt_len]u8 = undefined;
io.random(&salt_bin);
return createWithSalt(allocator, password, params, buf, &salt_bin);
}
/// Return a deterministic hash of the password encoded into the modular crypt format.
/// Uses the provided salt instead of generating one randomly.
pub fn createWithSalt(
allocator: mem.Allocator,
password: []const u8,
params: Params,
buf: []u8,
salt_bin: *const [default_salt_len]u8,
) HasherError![]const u8 {
const salt = crypt_format.saltFromBin(salt_bin.len, salt_bin.*);
var hash: [default_hash_len]u8 = undefined;
try kdf(allocator, &hash, password, &salt, params);
return crypt_format.serialize(HashResult{
.ln = params.ln,
.r = params.r,
.p = params.p,
.salt = &salt,
.hash = try BinValue(max_hash_len).fromSlice(&hash),
}, buf);
}
/// Verify a password against a string in modular crypt format
pub fn verify(
allocator: mem.Allocator,
str: []const u8,
password: []const u8,
) HasherError!void {
const hash_result = try crypt_format.deserialize(HashResult, str);
const params = Params{ .ln = hash_result.ln, .r = hash_result.r, .p = hash_result.p };
const expected_hash = hash_result.hash.constSlice();
var hash_buf: [max_hash_len]u8 = undefined;
if (expected_hash.len > hash_buf.len) return HasherError.InvalidEncoding;
const hash = hash_buf[0..expected_hash.len];
try kdf(allocator, hash, password, hash_result.salt, params);
if (!mem.eql(u8, hash, expected_hash)) return HasherError.PasswordVerificationFailed;
}
}