hare

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

commit 5a31153ab18a4d08c61ce4b6113b7022c519e772
parent 75f5e023944b0a68186d2235670a534a5532259e
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Wed, 19 Jan 2022 11:41:48 +0100

crypto::hmac: require caller provided buffer

Also refactor internally to support hash specific functions.

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

Diffstat:
Mcrypto/hmac/+test.ha | 3++-
Mcrypto/hmac/hmac.ha | 59+++++++++++++++++++++++++++++++++++------------------------
2 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/crypto/hmac/+test.ha b/crypto/hmac/+test.ha @@ -9,10 +9,11 @@ use strings; fn assert_hmac_sha1(keystr: str, vectors: [](str, [20]u8)) void = { let key = strings::toutf8(keystr); let h = sha1::sha1(); + let buf: [sha1::BLOCKSIZE]u8 = [0...]; for (let i = 0z; i < len(vectors); i += 1) { hash::reset(&h); - let hmac = hmac(&h, key); + let hmac = hmac(&h, key, buf); defer mac::finish(&hmac); const vector = vectors[i]; diff --git a/crypto/hmac/hmac.ha b/crypto/hmac/hmac.ha @@ -10,16 +10,37 @@ export type state = struct { }; // Creates a [[crypto::mac::mac]] that computes an HMAC using the provided hash -// function 'h'. +// function 'h' with given 'key'. The caller must provide a 'buf' of +// [[hash::bsz]] bytes. Use the BLOCKSIZE constant of the given hash function to +// allocate the memory statically. // // The caller must take extra care to call [[mac::finish]] when they are // finished using the MAC function, which, in addition to freeing state // associated with the MAC, will securely erase state which contains secret // information. -export fn hmac(h: *hash::hash, key: []u8) state = { - let bsz = hash::bsz(h); - let keypad: []u8 = alloc([0...], bsz); +export fn hmac(h: *hash::hash, key: []u8, buf: []u8) state = { + const bsz = hash::bsz(h); + assert(len(buf) >= bsz, "buf must be at least the size of one " + "block of the given hash function"); + let keypad = buf[..bsz]; + + init(h, key, keypad); + + return state { + h = h, + sz = hash::sz(h), + bsz = bsz, + writer = &write, + sum = &gensum, + finish = &finish, + keypad = keypad, + ... + }; +}; + +fn init(h: *hash::hash, key: []u8, keypad: []u8) void = { + const bsz = hash::bsz(h); if (len(key) > bsz) { hash::write(h, key); hash::sum(h, keypad); @@ -38,17 +59,6 @@ export fn hmac(h: *hash::hash, key: []u8) state = { // keypad for the outer hash is xored with 0x5c instead of 0x36 keypad[i] = keypad[i] ^ 0x36 ^ 0x5c; }; - - return state { - writer = &write, - sum = &sum, - finish = &finish, - sz = hash::sz(h), - bsz = bsz, - h = h, - keypad = keypad, - ... - }; }; fn write(st: *io::stream, buf: const []u8) (size | io::error) = { @@ -56,21 +66,22 @@ fn write(st: *io::stream, buf: const []u8) (size | io::error) = { return hash::write(hm.h, buf); }; -fn sum(mac: *mac::mac, buf: []u8) void = { - let hm = mac: *state; +fn sum(h: *hash::hash, keypad: []u8, dest: []u8) void = { + hash::sum(h, dest); - hash::sum(hm.h, buf); + hash::reset(h); + hash::write(h, keypad); + hash::write(h, dest); + hash::sum(h, dest); +}; - hash::reset(hm.h); - hash::write(hm.h, hm.keypad); - hash::write(hm.h, buf); - hash::sum(hm.h, buf); +fn gensum(mac: *mac::mac, dest: []u8) void = { + let hm = mac: *state; + sum(hm.h, hm.keypad, dest); }; fn finish(mac: *mac::mac) void = { let hm = mac: *state; - bytes::zero(hm.keypad); - free(hm.keypad); io::close(hm.h); };