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:
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);
};