Apply scrypt to generate a key from a password.
scrypt is defined in RFC 7914.
allocator: mem.Allocator.
derived_key: Slice of appropriate size for generated key. Generally 16 or 32 bytes in length.
May be uninitialized. All bytes will be overwritten.
Maximum size is derived_key.len / 32 == 0xffff_ffff.
password: Arbitrary sequence of bytes of any length.
salt: Arbitrary sequence of bytes of any length.
params: Params.
pub fn kdf(
allocator: mem.Allocator,
derived_key: []u8,
password: []const u8,
salt: []const u8,
params: Params,
) KdfError!void
pub fn kdf(
allocator: mem.Allocator,
derived_key: []u8,
password: []const u8,
salt: []const u8,
params: Params,
) KdfError!void {
if (derived_key.len == 0) return KdfError.WeakParameters;
if (derived_key.len / 32 > 0xffff_ffff) return KdfError.OutputTooLong;
if (params.ln == 0 or params.r == 0 or params.p == 0) return KdfError.WeakParameters;
const n64 = @as(u64, 1) << params.ln;
if (n64 > max_size) return KdfError.WeakParameters;
const n = @as(usize, @intCast(n64));
if (@as(u64, params.r) * @as(u64, params.p) >= 1 << 30 or
params.r > max_int / 128 / @as(u64, params.p) or
params.r > max_int / 256 or
n > max_int / 128 / @as(u64, params.r)) return KdfError.WeakParameters;
const xy = try allocator.alignedAlloc(u32, .@"16", 64 * params.r);
defer allocator.free(xy);
const v = try allocator.alignedAlloc(u32, .@"16", 32 * n * params.r);
defer allocator.free(v);
var dk = try allocator.alignedAlloc(u8, .@"16", params.p * 128 * params.r);
defer allocator.free(dk);
try pwhash.pbkdf2(dk, password, salt, 1, HmacSha256);
var i: u32 = 0;
while (i < params.p) : (i += 1) {
smix(@alignCast(dk[i * 128 * params.r ..]), params.r, n, v, xy);
}
try pwhash.pbkdf2(derived_key, password, dk, 1, HmacSha256);
}