hmac_drbg.ha (2526B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bytes; 5 use crypto::hmac; 6 use crypto::mac; 7 use crypto::sha1; 8 use hash; 9 10 // Partial HMAC_DRBG implementation as describe in RFC6979 Section 3.1.1 11 12 type drbg = struct { 13 h: *hash::hash, 14 k: []u8, 15 v: []u8, 16 initgen: bool, 17 buf: []u8, 18 }; 19 20 // 'buf' must be at least 2 * hash::sz(h) + hash::bsz(h) 21 fn hmac_drbg(h: *hash::hash, seed: const []u8, buf: []u8) drbg = { 22 const hlen = hash::sz(h); 23 assert(len(buf) >= 2 * hlen + hash::bsz(h)); 24 25 let s = drbg { 26 h = h, 27 k = buf[..hlen], 28 v = buf[hlen..2*hlen], 29 initgen = true, 30 buf = buf[2*hlen..], 31 }; 32 33 s.k[..] = [0...]; 34 s.v[..] = [1...]; 35 36 hash::reset(h); 37 let hm = hmac::hmac(h, s.k, s.buf); 38 mac::write(&hm, s.v); 39 mac::write(&hm, [0x00]); 40 mac::write(&hm, seed); 41 mac::sum(&hm, s.k); 42 43 hmac_drbg_update(&s); 44 45 hash::reset(h); 46 let hm = hmac::hmac(h, s.k, s.buf); 47 mac::write(&hm, s.v); 48 mac::write(&hm, [0x01]); 49 mac::write(&hm, seed); 50 mac::sum(&hm, s.k); 51 52 hmac_drbg_update(&s); 53 54 return s; 55 }; 56 57 fn hmac_drbg_update(s: *drbg) void = { 58 hash::reset(s.h); 59 let hm = hmac::hmac(s.h, s.k, s.buf); 60 mac::write(&hm, s.v); 61 mac::sum(&hm, s.v); 62 }; 63 64 fn hmac_drbg_generate(s: *drbg, dest: []u8) void = { 65 if (!s.initgen) { 66 hash::reset(s.h); 67 let hm = hmac::hmac(s.h, s.k, s.buf); 68 mac::write(&hm, s.v); 69 mac::write(&hm, [0x00]); 70 mac::sum(&hm, s.k); 71 72 hmac_drbg_update(s); 73 }; 74 s.initgen = false; 75 76 let n = 0z; 77 for (n < len(dest)) { 78 hmac_drbg_update(s); 79 80 const remain = len(dest) - n; 81 let max = if (remain > len(s.v)) len(s.v) else remain; 82 83 dest[n..n+max] = s.v[..max]; 84 n += max; 85 }; 86 }; 87 88 @test fn hmac_drbg() void = { 89 const seed: [_]u8 = [ 90 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 91 0x86, 0x66, 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 92 0xbf, 0x8c, 0x35, 0xc8, 93 ]; 94 95 let h = sha1::sha1(); 96 let buf: [sha1::SZ * 2 + sha1::BLOCKSZ]u8 = [0...]; 97 let s = hmac_drbg(&h, seed, buf); 98 99 let dest: [30]u8 = [0...]; 100 hmac_drbg_generate(&s, dest); 101 const expect: [_]u8 = [ 102 0x4e, 0xea, 0xad, 0x22, 0xb1, 0xbc, 0x51, 0x9e, 0xe6, 0xaa, 103 0x5a, 0x56, 0xd7, 0xab, 0x29, 0xc3, 0x39, 0xc4, 0xea, 0x10, 104 0x11, 0x2e, 0xe5, 0x4e, 0x2a, 0x6f, 0x81, 0xcd, 0x19, 0x7a, 105 ]; 106 assert(bytes::equal(expect, dest)); 107 108 const expect: [_]u8 = [ 109 0xe2, 0x1f, 0x3a, 0x90, 0x38, 0xc4, 0xc6, 0xe1, 0xa5, 0x0c, 110 0x72, 0x6c, 0x04, 0x90, 0xe0, 0x6a, 0xa3, 0xcb, 0x8c, 0xce, 111 0xd2, 0x89, 0x1d, 0x01, 0xf3, 112 ]; 113 hmac_drbg_generate(&s, dest); 114 assert(bytes::equal(expect, dest[..25])); 115 };