hare

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

commit b34a4e0d313698d91961a5852bbb88a39c1e7158
parent 544fc96729a36099d3a02fa735e11e87f9f980a8
Author: Armin Preiml <apreiml@strohwolke.at>
Date:   Mon, 10 Jan 2022 12:53:38 +0100

crypto::hmac: use crypto::mac api instead of hash

Supporting mac now simplifies the code so that the hash function can now
be passed as argument to the init function and must not be created in
hmac.

Also the code has been simplified to avoid some of the allocations.

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

Diffstat:
Mcrypto/hmac/+test.ha | 44++++++++------------------------------------
Mcrypto/hmac/hmac.ha | 111+++++++++++++++++++++++++++++--------------------------------------------------
Mscripts/gen-stdlib | 6+++---
Mstdlib.mk | 4++--
4 files changed, 54 insertions(+), 111 deletions(-)

diff --git a/crypto/hmac/+test.ha b/crypto/hmac/+test.ha @@ -1,4 +1,5 @@ use bytes; +use crypto::mac; use crypto::sha1; use encoding::hex; use hash; @@ -7,17 +8,19 @@ use strings; fn assert_hmac_sha1(keystr: str, vectors: [](str, [20]u8)) void = { let key = strings::toutf8(keystr); - let hmac = hmac(&sha1::create, key); - defer io::close(&hmac); + let h = sha1::sha1(); for (let i = 0z; i < len(vectors); i += 1) { + hash::reset(&h); + let hmac = hmac(&h, key); + defer mac::finish(&hmac); + const vector = vectors[i]; - hash::reset(&hmac); - hash::write(&hmac, strings::toutf8(vector.0)); + mac::write(&hmac, strings::toutf8(vector.0)); let sum: [sha1::SIZE]u8 = [0...]; - hash::sum(&hmac, sum); + mac::sum(&hmac, sum); assert(bytes::equal(vector.1, sum)); }; @@ -122,34 +125,3 @@ fn assert_hmac_sha1(keystr: str, vectors: [](str, [20]u8)) void = { "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; assert_hmac_sha1(key, vectors); }; - -@test fn hmac_sha1_write_after_sum() void = { - const result: [2][20]u8 = [ - [ - 0x98, 0x66, 0x91, 0x5d, 0x9e, 0xa9, 0x29, 0x0c, 0xe3, - 0x07, 0x28, 0x5e, 0x6a, 0x86, 0xed, 0xe1, 0xca, 0x1a, - 0x0b, 0x6f, - ], - [ - 0x30, 0x81, 0xd5, 0x60, 0xa1, 0x81, 0x21, 0x1d, 0x25, - 0xb3, 0xe4, 0xf3, 0xa7, 0x1e, 0x3a, 0x76, 0xae, 0x27, - 0xce, 0xfa, - ], - ]; - - let sha = sha1::sha1(); - let hmac = hmac(&sha1::create, strings::toutf8("love")); - - hash::reset(&hmac); - hash::write(&hmac, strings::toutf8("abcdefghbcdefghicdefghijdefghij")); - - let sum: [sha1::SIZE]u8 = [0...]; - hash::sum(&hmac, sum); - - assert(bytes::equal(result[0], sum)); - - hash::write(&hmac, strings::toutf8("appendstuff")); - hash::finish(&hmac, sum); - - assert(bytes::equal(result[1], sum)); -}; diff --git a/crypto/hmac/hmac.ha b/crypto/hmac/hmac.ha @@ -1,105 +1,76 @@ use bytes; -use crypto::math; +use crypto::mac; use hash; use io; export type state = struct { - hash::hash, - hinner: *hash::hash, - houter: *hash::hash, - okeypad: []u8, - ikeypad: []u8, - sumbuf: []u8, + mac::mac, + h: *hash::hash, + keypad: []u8, }; -// Creates a [[hash::hash]] that computes an HMAC using the provided hash -// creation function, e.g. [[crypto::sha256::create]]. +// Creates a [[crypto::mac::mac]] that computes an HMAC using the provided hash +// function 'h'. // -// The caller must take extra care to call [[hash::close]] when they are -// finished using the hash, which, in addition to freeing state associated with -// the hash, will securely erase state which contains secret information. -export fn hmac(create: *hash::createfunc, key: []u8) state = { - let hinner = create(), houter = create(); - let bsz = hash::bsz(hinner); - let ikeypad: []u8 = bytes_alloc(bsz, 0); +// 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); - // use ikeypad to store the prepared key temporarly to avoid an - // additional allocation. if (len(key) > bsz) { - hash::write(hinner, key); - hash::sum(hinner, ikeypad); - hash::reset(hinner); + hash::write(h, key); + hash::sum(h, keypad); + hash::reset(h); } else { - ikeypad[..len(key)] = key[..]; + keypad[..len(key)] = key[..]; }; - let okeypad: []u8 = alloc([], bsz); for (let i = 0z; i < bsz; i += 1) { - append(okeypad, 0x5c ^ ikeypad[i]); + keypad[i] = 0x36 ^ keypad[i]; }; + hash::write(h, keypad); + for (let i = 0z; i < bsz; i += 1) { - ikeypad[i] = 0x36 ^ ikeypad[i]; + // keypad for the outer hash is xored with 0x5c instead of 0x36 + keypad[i] = keypad[i] ^ 0x36 ^ 0x5c; }; - hash::write(hinner, ikeypad); - return state { writer = &write, - reset = &reset, sum = &sum, - closer = &close, - sz = hash::sz(hinner), + finish = &finish, + sz = hash::sz(h), bsz = bsz, - hinner = hinner, - houter = houter, - okeypad = okeypad, - ikeypad = ikeypad, - sumbuf = bytes_alloc(hash::sz(hinner), 0), + h = h, + keypad = keypad, ... }; }; -fn close(s: *io::stream) void = { - let h: *state = s: *state; - bytes::zero(h.okeypad); - bytes::zero(h.ikeypad); - free(h.okeypad); - free(h.ikeypad); - free(h.sumbuf); - io::close(h.hinner); - io::close(h.houter); - free(h.hinner); - free(h.houter); -}; - -// TODO: https://todo.sr.ht/~sircmpwn/hare/285 -fn bytes_alloc(s: size, v: u8) []u8 = { - let b: []u8 = alloc([], s); - for (let i = 0z; i < s; i += 1) { - append(b, 0); - }; - return b; -}; - fn write(st: *io::stream, buf: const []u8) (size | io::error) = { - let h = st: *state; - return hash::write(h.hinner, buf); + let hm = st: *state; + return hash::write(hm.h, buf); }; -fn sum(hash: *hash::hash, buf: []u8) void = { - let h = hash: *state; +fn sum(mac: *mac::mac, buf: []u8) void = { + let hm = mac: *state; - hash::sum(h.hinner, h.sumbuf[0..h.hinner.sz]); + hash::sum(hm.h, buf); - hash::reset(h.houter); - hash::write(h.houter, h.okeypad); - hash::write(h.houter, h.sumbuf[0..h.hinner.sz]); - hash::sum(h.houter, buf); + hash::reset(hm.h); + hash::write(hm.h, hm.keypad); + hash::write(hm.h, buf); + hash::sum(hm.h, buf); }; -fn reset(hash: *hash::hash) void = { - let h = hash: *state; - hash::reset(h.hinner); - hash::write(h.hinner, h.ikeypad); +fn finish(mac: *mac::mac) void = { + let hm = mac: *state; + + bytes::zero(hm.keypad); + free(hm.keypad); + io::close(hm.h); }; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -255,13 +255,13 @@ crypto_hmac() { then gen_srcs crypto::hmac \ hmac.ha - gen_ssa crypto::hmac crypto::math hash io bytes + gen_ssa crypto::hmac crypto::mac hash io bytes else gen_srcs crypto::hmac \ hmac.ha \ +test.ha - gen_ssa crypto::hmac bytes crypto::math crypto::sha1 \ - encoding::hex hash io strings + gen_ssa crypto::hmac bytes crypto::mac hash crypto::sha1 \ + encoding::hex io strings fi } diff --git a/stdlib.mk b/stdlib.mk @@ -724,7 +724,7 @@ $(HARECACHE)/crypto/cipher/crypto_cipher-any.ssa: $(stdlib_crypto_cipher_any_src stdlib_crypto_hmac_any_srcs= \ $(STDLIB)/crypto/hmac/hmac.ha -$(HARECACHE)/crypto/hmac/crypto_hmac-any.ssa: $(stdlib_crypto_hmac_any_srcs) $(stdlib_rt) $(stdlib_crypto_math_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) +$(HARECACHE)/crypto/hmac/crypto_hmac-any.ssa: $(stdlib_crypto_hmac_any_srcs) $(stdlib_rt) $(stdlib_crypto_mac_$(PLATFORM)) $(stdlib_hash_$(PLATFORM)) $(stdlib_io_$(PLATFORM)) $(stdlib_bytes_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/crypto/hmac @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ncrypto::hmac \ @@ -2483,7 +2483,7 @@ testlib_crypto_hmac_any_srcs= \ $(STDLIB)/crypto/hmac/hmac.ha \ $(STDLIB)/crypto/hmac/+test.ha -$(TESTCACHE)/crypto/hmac/crypto_hmac-any.ssa: $(testlib_crypto_hmac_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_math_$(PLATFORM)) $(testlib_crypto_sha1_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) +$(TESTCACHE)/crypto/hmac/crypto_hmac-any.ssa: $(testlib_crypto_hmac_any_srcs) $(testlib_rt) $(testlib_bytes_$(PLATFORM)) $(testlib_crypto_mac_$(PLATFORM)) $(testlib_hash_$(PLATFORM)) $(testlib_crypto_sha1_$(PLATFORM)) $(testlib_encoding_hex_$(PLATFORM)) $(testlib_io_$(PLATFORM)) $(testlib_strings_$(PLATFORM)) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/crypto/hmac @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ncrypto::hmac \