authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-04 02:45:54-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-10-04 02:45:54-04:00
log5fda4fe4c80011aa1a440aecdeaa281f846c7a0d
tree6e201c0e72cc67d4143280c3c7833a8157a5f5a1
parent538d485782629a358c2dd0f8e34d74813e3c9526
parentd75d6e7f774c6236eb11a5a6b0277561a3b42a22
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6454 from jedisct1/hkdf

std/crypto: implement the HKDF construction

2 files changed, 111 insertions(+), 40 deletions(-)

lib/std/crypto.zig+45-40
......@@ -4,6 +4,48 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66
7/// Authenticated Encryption with Associated Data
8pub const aead = struct {
9 const chacha20 = @import("crypto/chacha20.zig");
10
11 pub const Gimli = @import("crypto/gimli.zig").Aead;
12 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
13 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
14 pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
15 pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
16};
17
18/// Authentication (MAC) functions.
19pub const auth = struct {
20 pub const hmac = @import("crypto/hmac.zig");
21 pub const siphash = @import("crypto/siphash.zig");
22};
23
24/// Core functions, that should rarely be used directly by applications.
25pub const core = struct {
26 pub const aes = @import("crypto/aes.zig");
27 pub const Gimli = @import("crypto/gimli.zig").State;
28
29 /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
30 ///
31 /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
32 ///
33 /// Most applications may want to use AEADs instead.
34 pub const modes = @import("crypto/modes.zig");
35};
36
37/// Diffie-Hellman key exchange functions.
38pub const dh = struct {
39 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
40};
41
42/// Elliptic-curve arithmetic.
43pub const ecc = struct {
44 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
45 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
46 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
47};
48
749/// Hash functions.
850pub const hash = struct {
951 pub const Md5 = @import("crypto/md5.zig").Md5;
......@@ -15,21 +57,9 @@ pub const hash = struct {
1557 pub const Gimli = @import("crypto/gimli.zig").Hash;
1658};
1759
18/// Authentication (MAC) functions.
19pub const auth = struct {
20 pub const hmac = @import("crypto/hmac.zig");
21 pub const siphash = @import("crypto/siphash.zig");
22};
23
24/// Authenticated Encryption with Associated Data
25pub const aead = struct {
26 const chacha20 = @import("crypto/chacha20.zig");
27
28 pub const Gimli = @import("crypto/gimli.zig").Aead;
29 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
30 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
31 pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
32 pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
60/// Key derivation functions.
61pub const kdf = struct {
62 pub const hkdf = @import("crypto/hkdf.zig");
3363};
3464
3565/// MAC functions requiring single-use secret keys.
......@@ -57,31 +87,6 @@ pub const pwhash = struct {
5787 pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
5888};
5989
60/// Core functions, that should rarely be used directly by applications.
61pub const core = struct {
62 pub const aes = @import("crypto/aes.zig");
63 pub const Gimli = @import("crypto/gimli.zig").State;
64
65 /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
66 ///
67 /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
68 ///
69 /// Most applications may want to use AEADs instead.
70 pub const modes = @import("crypto/modes.zig");
71};
72
73/// Elliptic-curve arithmetic.
74pub const ecc = struct {
75 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
76 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
77 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
78};
79
80/// Diffie-Hellman key exchange functions.
81pub const dh = struct {
82 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
83};
84
8590/// Digital signature functions.
8691pub const sign = struct {
8792 pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
lib/std/crypto/hkdf.zig created+66
......@@ -0,0 +1,66 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const hmac = std.crypto.auth.hmac;
4const mem = std.mem;
5
6/// HKDF-SHA256
7pub const HkdfSha256 = Hkdf(hmac.sha2.HmacSha256);
8
9/// HKDF-SHA512
10pub const HkdfSha512 = Hkdf(hmac.sha2.HmacSha512);
11
12/// The Hkdf construction takes some source of initial keying material and
13/// derives one or more uniform keys from it.
14pub fn Hkdf(comptime Hmac: type) type {
15 return struct {
16 /// Return a master key from a salt and initial keying material.
17 fn extract(salt: []const u8, ikm: []const u8) [Hmac.mac_length]u8 {
18 var prk: [Hmac.mac_length]u8 = undefined;
19 Hmac.create(&prk, ikm, salt);
20 return prk;
21 }
22
23 /// Derive a subkey from a master key `prk` and a subkey description `ctx`.
24 fn expand(out: []u8, ctx: []const u8, prk: [Hmac.mac_length]u8) void {
25 assert(out.len < Hmac.mac_length * 255); // output size is too large for the Hkdf construction
26 var i: usize = 0;
27 var counter = [1]u8{1};
28 while (i + Hmac.mac_length <= out.len) : (i += Hmac.mac_length) {
29 var st = Hmac.init(&prk);
30 if (i != 0) {
31 st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
32 }
33 st.update(ctx);
34 st.update(&counter);
35 st.final(out[i..][0..Hmac.mac_length]);
36 counter[0] += 1;
37 }
38 const left = out.len % Hmac.mac_length;
39 if (left > 0) {
40 var st = Hmac.init(&prk);
41 if (i != 0) {
42 st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
43 }
44 st.update(ctx);
45 st.update(&counter);
46 var tmp: [Hmac.mac_length]u8 = undefined;
47 st.final(tmp[0..Hmac.mac_length]);
48 mem.copy(u8, out[i..][0..left], tmp[0..left]);
49 }
50 }
51 };
52}
53
54const htest = @import("test.zig");
55
56test "Hkdf" {
57 const ikm = [_]u8{0x0b} ** 22;
58 const salt = [_]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
59 const context = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
60 const kdf = HkdfSha256;
61 const prk = kdf.extract(&salt, &ikm);
62 htest.assertEqual("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", &prk);
63 var out: [42]u8 = undefined;
64 kdf.expand(&out, &context, prk);
65 htest.assertEqual("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", &out);
66}