Hash and verify passwords using the PHC format.
const PhcFormatHasher = struct
const PhcFormatHasher = struct {
const alg_id = "bcrypt";
const BinValue = phc_format.BinValue;
const HashResult = struct {
alg_id: []const u8,
r: u6,
salt: BinValue(salt_length),
hash: BinValue(dk_length),
};
/// Return a non-deterministic hash of the password encoded as a PHC-format string.
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 as a PHC-format string.
/// Uses the provided salt instead of generating one randomly.
fn createWithSalt(
password: []const u8,
params: Params,
buf: []u8,
salt: [salt_length]u8,
) HasherError![]const u8 {
const hash = bcrypt(password, &salt, params);
return phc_format.serialize(HashResult{
.alg_id = alg_id,
.r = params.rounds_log,
.salt = try BinValue(salt_length).fromSlice(&salt),
.hash = try BinValue(dk_length).fromSlice(&hash),
}, buf);
}
/// Verify a password against a PHC-format encoded string
fn verify(
str: []const u8,
password: []const u8,
silently_truncate_password: bool,
) HasherError!void {
const hash_result = try phc_format.deserialize(HashResult, str);
if (!mem.eql(u8, hash_result.alg_id, alg_id)) return HasherError.PasswordVerificationFailed;
if (hash_result.salt.len != salt_length or hash_result.hash.len != dk_length)
return HasherError.InvalidEncoding;
const params: Params = .{
.rounds_log = hash_result.r,
.silently_truncate_password = silently_truncate_password,
};
const hash = bcrypt(password, &hash_result.salt.buf, params);
const expected_hash = hash_result.hash.constSlice();
if (!mem.eql(u8, &hash, expected_hash)) return HasherError.PasswordVerificationFailed;
}
}