hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 280907287633f7bc1f5be24ec16986ed6bc51864
parent 4340c27a87e0ccf376150cf98cdbf18a3873953e
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Thu,  9 May 2024 13:31:00 +0200

crypto::ecdsa: implement hmac_drbg

The algorithm is required to create deterministic signatures according
to RFC 6979.

Signed-off-by: Armin Preiml <apreiml@strohwolke.at>

Diffstat:
Acrypto/ecdsa/hmac_drbg.ha | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+), 0 deletions(-)

diff --git a/crypto/ecdsa/hmac_drbg.ha b/crypto/ecdsa/hmac_drbg.ha @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MPL-2.0 +// (c) Hare authors <https://harelang.org> + +use bytes; +use crypto::hmac; +use crypto::mac; +use crypto::sha1; +use hash; + +// Partial HMAC_DRBG implementation as describe in RFC6979 Section 3.1.1 + +type drbg = struct { + h: *hash::hash, + k: []u8, + v: []u8, + initgen: bool, + buf: []u8, +}; + +// 'buf' must be at least 2 * hash::sz(h) + hash::bsz(h) +fn hmac_drbg(h: *hash::hash, seed: const []u8, buf: []u8) drbg = { + const hlen = hash::sz(h); + assert(len(buf) >= 2 * hlen + hash::bsz(h)); + + let s = drbg { + h = h, + k = buf[..hlen], + v = buf[hlen..2*hlen], + initgen = true, + buf = buf[2*hlen..], + }; + + s.k[..] = [0...]; + s.v[..] = [1...]; + + hash::reset(h); + let hm = hmac::hmac(h, s.k, s.buf); + mac::write(&hm, s.v); + mac::write(&hm, [0x00]); + mac::write(&hm, seed); + mac::sum(&hm, s.k); + + hmac_drbg_update(&s); + + hash::reset(h); + let hm = hmac::hmac(h, s.k, s.buf); + mac::write(&hm, s.v); + mac::write(&hm, [0x01]); + mac::write(&hm, seed); + mac::sum(&hm, s.k); + + hmac_drbg_update(&s); + + return s; +}; + +fn hmac_drbg_update(s: *drbg) void = { + hash::reset(s.h); + let hm = hmac::hmac(s.h, s.k, s.buf); + mac::write(&hm, s.v); + mac::sum(&hm, s.v); +}; + +fn hmac_drbg_generate(s: *drbg, dest: []u8) void = { + if (!s.initgen) { + hash::reset(s.h); + let hm = hmac::hmac(s.h, s.k, s.buf); + mac::write(&hm, s.v); + mac::write(&hm, [0x00]); + mac::sum(&hm, s.k); + + hmac_drbg_update(s); + }; + s.initgen = false; + + let n = 0z; + for (n < len(dest)) { + hmac_drbg_update(s); + + const remain = len(dest) - n; + let max = if (remain > len(s.v)) len(s.v) else remain; + + dest[n..n+max] = s.v[..max]; + n += max; + }; +}; + +@test fn hmac_drbg() void = { + const seed: [_]u8 = [ + 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, + 0x86, 0x66, 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, + 0xbf, 0x8c, 0x35, 0xc8, + ]; + + let h = sha1::sha1(); + let buf: [sha1::SZ * 2 + sha1::BLOCKSZ]u8 = [0...]; + let s = hmac_drbg(&h, seed, buf); + + let dest: [30]u8 = [0...]; + hmac_drbg_generate(&s, dest); + const expect: [_]u8 = [ + 0x4e, 0xea, 0xad, 0x22, 0xb1, 0xbc, 0x51, 0x9e, 0xe6, 0xaa, + 0x5a, 0x56, 0xd7, 0xab, 0x29, 0xc3, 0x39, 0xc4, 0xea, 0x10, + 0x11, 0x2e, 0xe5, 0x4e, 0x2a, 0x6f, 0x81, 0xcd, 0x19, 0x7a, + ]; + assert(bytes::equal(expect, dest)); + + const expect: [_]u8 = [ + 0xe2, 0x1f, 0x3a, 0x90, 0x38, 0xc4, 0xc6, 0xe1, 0xa5, 0x0c, + 0x72, 0x6c, 0x04, 0x90, 0xe0, 0x6a, 0xa3, 0xcb, 0x8c, 0xce, + 0xd2, 0x89, 0x1d, 0x01, 0xf3, + ]; + hmac_drbg_generate(&s, dest); + assert(bytes::equal(expect, dest[..25])); +};