From 257c5b534839d75092909f604bb2663e883a290f Mon Sep 17 00:00:00 2001 From: Rob Napier Date: Sun, 13 Sep 2020 10:50:46 -0400 Subject: [PATCH 1/4] Explicitly reference std.crypto.kdf in test case --- lib/std/crypto.zig | 6 +++++- lib/std/crypto/pbkdf2.zig | 14 +++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index 2b42942824..c375c02906 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -35,7 +35,11 @@ pub const onetimeauth = struct { pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; }; -/// Key derivation functions +/// A Key Derivation Function (KDF) is intended to turn a weak, human generated password into a +/// strong key, suitable for cryptographic uses. It does this by salting and stretching the +/// password. Salting injects non-secret random data, so that identical passwords will be converted +/// into unique keys. Stretching applies a deliberately slow hashing function to frustrate +/// brute-force guessing. pub const kdf = struct { pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2; }; diff --git a/lib/std/crypto/pbkdf2.zig b/lib/std/crypto/pbkdf2.zig index 2f9b720220..dfa6b1c022 100644 --- a/lib/std/crypto/pbkdf2.zig +++ b/lib/std/crypto/pbkdf2.zig @@ -10,14 +10,6 @@ const debug = std.debug; const assert = debug.assert; const mem = std.mem; -//! PBKDF2 (Password-Based Key Derivation Function 2) is intended to turn a weak, human generated -//! password into a strong key, suitable for cryptographic uses. It does this by salting and -//! stretching the password. Salting injects non-secret random data, so that identical passwords -//! will be converted into unique keys. Stretching applies a deliberately slow hashing function to -//! frustrate brute-force guessing. -//! -//! PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132. - // RFC 2898 Section 5.2 // // FromSpec: @@ -48,6 +40,8 @@ const mem = std.mem; /// Apply PBKDF2 to generate a key from a password. /// +/// PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132. +/// /// derivedKey: Slice of appropriate size for generated key. Generally 16 or 32 bytes in length. /// May be uninitialized. All bytes will be written. /// Maximum size is (2^32 - 1) * Hash.digest_length @@ -62,6 +56,8 @@ const mem = std.mem; /// the derivedKey. It is common to tune this parameter to achieve approximately 100ms. /// /// Prf: Pseudo-random function to use. A common choice is std.crypto.auth.hmac.HmacSha256. +/// +/// PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132. pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) void { assert(rounds >= 1); @@ -161,7 +157,7 @@ test "RFC 6070 one iteration" { var derivedKey: [dkLen]u8 = undefined; - pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1); + std.crypto.kdf.pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1); const expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6"; From 8a1a40276fb1577f46b89e3aefc17f9e82a933d6 Mon Sep 17 00:00:00 2001 From: Rob Napier Date: Sun, 13 Sep 2020 11:08:06 -0400 Subject: [PATCH 2/4] Extract kdf.zig to provide namespace documentation --- lib/std/crypto.zig | 11 ++--------- lib/std/crypto/kdf.zig | 17 +++++++++++++++++ lib/std/crypto/pbkdf2.zig | 2 -- 3 files changed, 19 insertions(+), 11 deletions(-) create mode 100644 lib/std/crypto/kdf.zig diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig index c375c02906..64ec22894c 100644 --- a/lib/std/crypto.zig +++ b/lib/std/crypto.zig @@ -35,14 +35,7 @@ pub const onetimeauth = struct { pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; }; -/// A Key Derivation Function (KDF) is intended to turn a weak, human generated password into a -/// strong key, suitable for cryptographic uses. It does this by salting and stretching the -/// password. Salting injects non-secret random data, so that identical passwords will be converted -/// into unique keys. Stretching applies a deliberately slow hashing function to frustrate -/// brute-force guessing. -pub const kdf = struct { - pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2; -}; +pub const kdf = @import("crypto/kdf.zig"); /// Core functions, that should rarely be used directly by applications. pub const core = struct { @@ -86,7 +79,7 @@ test "crypto" { _ = @import("crypto/gimli.zig"); _ = @import("crypto/hmac.zig"); _ = @import("crypto/md5.zig"); - _ = @import("crypto/pbkdf2.zig"); + _ = @import("crypto/kdf.zig"); _ = @import("crypto/poly1305.zig"); _ = @import("crypto/sha1.zig"); _ = @import("crypto/sha2.zig"); diff --git a/lib/std/crypto/kdf.zig b/lib/std/crypto/kdf.zig new file mode 100644 index 0000000000..06bf67bbbd --- /dev/null +++ b/lib/std/crypto/kdf.zig @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +//! A Key Derivation Function (KDF) is intended to turn a weak, human generated password into a +//! strong key, suitable for cryptographic uses. It does this by salting and stretching the +//! password. Salting injects non-secret random data, so that identical passwords will be converted +//! into unique keys. Stretching applies a deliberately slow hashing function to frustrate +//! brute-force guessing. + +pub const pbkdf2 = @import("pbkdf2.zig").pbkdf2; + +test "kdf" { + _ = @import("pbkdf2.zig"); +} diff --git a/lib/std/crypto/pbkdf2.zig b/lib/std/crypto/pbkdf2.zig index dfa6b1c022..424e2d6f62 100644 --- a/lib/std/crypto/pbkdf2.zig +++ b/lib/std/crypto/pbkdf2.zig @@ -56,8 +56,6 @@ const mem = std.mem; /// the derivedKey. It is common to tune this parameter to achieve approximately 100ms. /// /// Prf: Pseudo-random function to use. A common choice is std.crypto.auth.hmac.HmacSha256. -/// -/// PBKDF2 is defined in RFC 2898, and is a recommendation of NIST SP 800-132. pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) void { assert(rounds >= 1); From 2f9c9662ba0bdc306c1b80534187251491ffdb17 Mon Sep 17 00:00:00 2001 From: Rob Napier Date: Sun, 13 Sep 2020 11:15:28 -0400 Subject: [PATCH 3/4] Use comptime to expose public method to doc system --- lib/std/crypto/pbkdf2.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/std/crypto/pbkdf2.zig b/lib/std/crypto/pbkdf2.zig index 424e2d6f62..809fff13ad 100644 --- a/lib/std/crypto/pbkdf2.zig +++ b/lib/std/crypto/pbkdf2.zig @@ -10,6 +10,11 @@ const debug = std.debug; const assert = debug.assert; const mem = std.mem; +// Exports +comptime { + _ = crypto.kdf.pbkdf2; +} + // RFC 2898 Section 5.2 // // FromSpec: @@ -155,7 +160,7 @@ test "RFC 6070 one iteration" { var derivedKey: [dkLen]u8 = undefined; - std.crypto.kdf.pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1); + pbkdf2(&derivedKey, p, s, c, crypto.auth.hmac.HmacSha1); const expected = "0c60c80f961f0e71f3a9b524af6012062fe037a6"; From 85366771ea21a0dcd93e58b35738489d773590fc Mon Sep 17 00:00:00 2001 From: Rob Napier Date: Sun, 13 Sep 2020 12:36:32 -0400 Subject: [PATCH 4/4] pbkdf2 offset into dk should be usize, not u64. --- lib/std/crypto/pbkdf2.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/crypto/pbkdf2.zig b/lib/std/crypto/pbkdf2.zig index 809fff13ad..2bbf0f15d8 100644 --- a/lib/std/crypto/pbkdf2.zig +++ b/lib/std/crypto/pbkdf2.zig @@ -130,7 +130,7 @@ pub fn pbkdf2(derivedKey: []u8, password: []const u8, salt: []const u8, rounds: ctx.final(prevBlock[0..]); // Choose portion of DK to write into (T_n) and initialize - const offset: u64 = @as(u64, block) * hLen; + const offset: usize = @as(usize, block) * hLen; const blockLen = if (block != l - 1) hLen else r; var dkBlock = derivedKey[offset..(offset + blockLen)]; mem.copy(u8, dkBlock, prevBlock[0..dkBlock.len]);