mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
107 lines
2.0 KiB
Plaintext
107 lines
2.0 KiB
Plaintext
module std::hash::hmac(<HashAlg, HASH_BYTES, BLOCK_BYTES>);
|
|
import std::crypto;
|
|
|
|
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();
|
|
}
|
|
|
|
/**
|
|
* @require output.len > 0 "Output must be greater than zero"
|
|
* @require output.len < int.max / HASH_BYTES "Output is too large"
|
|
**/
|
|
fn void pbkdf2(char[] pw, char[] salt, uint iterations, char[] output)
|
|
{
|
|
usz l = output.len / HASH_BYTES;
|
|
usz r = output.len % HASH_BYTES;
|
|
|
|
Hmac hmac;
|
|
hmac.init(pw);
|
|
|
|
char[] dst_curr = output;
|
|
for (usz i = 1; i <= l; i++)
|
|
{
|
|
@derive(&hmac, salt, iterations, i, dst_curr[:HASH_BYTES]);
|
|
dst_curr = dst_curr[HASH_BYTES..];
|
|
}
|
|
|
|
if (r > 0)
|
|
{
|
|
char[HASH_BYTES] tmp;
|
|
@derive(&hmac, salt, iterations, l + 1, &tmp);
|
|
dst_curr[..] = tmp[:dst_curr.len];
|
|
mem::zero_volatile(&tmp);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
mem::zero_volatile(&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;
|
|
|
|
macro @derive(Hmac *hmac_start, char[] salt, uint iterations, usz index, char[] out)
|
|
{
|
|
assert(out.len == HASH_BYTES);
|
|
char[HASH_BYTES] tmp @noinit;
|
|
defer mem::zero_volatile(&tmp);
|
|
Hmac hmac = *hmac_start;
|
|
hmac.update(salt);
|
|
UIntBE be = { (uint)index };
|
|
hmac.update(&&bitcast(be, char[4]));
|
|
tmp = hmac.final();
|
|
out[..] = tmp;
|
|
for (int it = 1; it < iterations; it++)
|
|
{
|
|
hmac = *hmac_start;
|
|
hmac.update(&tmp);
|
|
tmp = hmac.final();
|
|
foreach (i, v : tmp)
|
|
{
|
|
out[i] ^= v;
|
|
}
|
|
}
|
|
} |