From 3b009e0b5095e2e629bb0cbfefe3763d6a9cc38d Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 28 Sep 2024 23:28:11 +0200 Subject: [PATCH] Added generic HMAC. --- lib/std/hash/hmac.c3 | 55 ++++++++++++++++++++++++++++++++++++++++++++ lib/std/hash/md5.c3 | 11 +++++++-- lib/std/hash/sha1.c3 | 27 +++++++++++++++++----- releasenotes.md | 1 + 4 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 lib/std/hash/hmac.c3 diff --git a/lib/std/hash/hmac.c3 b/lib/std/hash/hmac.c3 new file mode 100644 index 000000000..1bfaca771 --- /dev/null +++ b/lib/std/hash/hmac.c3 @@ -0,0 +1,55 @@ +module std::hash::hmac(); + +struct Hmac +{ + HashAlg a, b; +} + +fn char[HASH_BYTES] hash(char[] key, char[] message) +{ + Hmac hmac @noinit; + hmac.init(key); + hmac.update(message); + return hmac.final(); +} + +fn void Hmac.init(&self, char[] key) +{ + char[BLOCK_BYTES] buffer; + if (key.len > BLOCK_BYTES) + { + self.a.init(); + self.a.update(key); + buffer[:HASH_BYTES] = self.a.final()[..]; + } + else + { + buffer[:key.len] = key[..]; + } + + foreach (&b : buffer) *b ^= IPAD; + + self.a.init(); + self.a.update(&buffer); + + foreach (&b : buffer) *b ^= IPAD ^ OPAD; + + self.b.init(); + self.b.update(&buffer); + + buffer = {}; +} + +fn void Hmac.update(&self, char[] data) +{ + self.a.update(data); +} + +fn char[HASH_BYTES] Hmac.final(&self) +{ + self.b.update(&&self.a.final()); + return self.b.final(); +} + +const IPAD @private = 0x36; +const OPAD @private = 0x5C; diff --git a/lib/std/hash/md5.c3 b/lib/std/hash/md5.c3 index 8f80930d7..b2749c058 100644 --- a/lib/std/hash/md5.c3 +++ b/lib/std/hash/md5.c3 @@ -1,6 +1,10 @@ module std::hash::md5; +import std::hash::hmac; import std::bits; +const BLOCK_BYTES = 64; +const HASH_BYTES = 16; + struct Md5 { uint lo, hi; @@ -9,7 +13,10 @@ struct Md5 uint[16] block; } -fn char[16] hash(char[] data) +def HmacMd5 = Hmac(); +def hmac = hmac::hash(); + +fn char[HASH_BYTES] hash(char[] data) { Md5 md5; md5.init(); @@ -58,7 +65,7 @@ fn void Md5.update(&ctx, char[] data) ctx.buffer[:data.len] = data[..]; } -fn char[16] Md5.final(&ctx) +fn char[HASH_BYTES] Md5.final(&ctx) { usz used = (usz)ctx.lo & 0x3f; ctx.buffer[used++] = 0x80; diff --git a/lib/std/hash/sha1.c3 b/lib/std/hash/sha1.c3 index 9f51bf690..51c15e0ea 100644 --- a/lib/std/hash/sha1.c3 +++ b/lib/std/hash/sha1.c3 @@ -5,13 +5,28 @@ // Implementation was off Steve Reid's SHA-1 C implementation module std::hash::sha1; +import std::hash::hmac; import std::bits; +const BLOCK_BYTES = 64; +const HASH_BYTES = 20; + struct Sha1 { uint[5] state; uint[2] count; - char[64] buffer; + char[BLOCK_BYTES] buffer; +} + +def HmacSha1 = Hmac(); +def hmac = hmac::hash(); + +fn char[HASH_BYTES] hash(char[] data) +{ + Sha1 sha1 @noinit; + sha1.init(); + sha1.update(data); + return sha1.final(); } fn void Sha1.init(&self) @@ -55,7 +70,7 @@ fn void Sha1.update(&self, char[] data) } -fn char[20] Sha1.final(&self) +fn char[HASH_BYTES] Sha1.final(&self) { char[8] finalcount; for (uint i = 0; i < 8; i++) @@ -69,21 +84,21 @@ fn char[20] Sha1.final(&self) } self.update(&finalcount); - char[20] digest; - for (uint i = 0; i < 20; i++) + char[HASH_BYTES] digest; + for (uint i = 0; i < HASH_BYTES; i++) { digest[i] = (char)((self.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xFF); } // Clear mem - mem::clear(self, Sha1.sizeof); + *self = {}; finalcount = {}; return digest; } union Long16 @local { - char[64] c; + char[BLOCK_BYTES] c; uint[16] l; } diff --git a/releasenotes.md b/releasenotes.md index 192cd58c6..d639f4091 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -73,6 +73,7 @@ - Add `rnd` and `rand_in_range` default random functions. - Additional timezone related functions for `datetime`. - Added MD5 and crypto::safe_compare. +- Added generic HMAC. ## 0.6.2 Change list