zig/lib/std/crypto/hmac.zig
Frank Denis cb44f27104 std/crypto/hmac: remove HmacBlake2s256 definition
HMAC is a generic construction, so we allow it to be instantiated
with any hash function.

In practice, HMAC is almost exclusively used with MD5, SHA1 and SHA2,
so it makes sense to define some shortcuts for them.

However, defining `HmacBlake2s256` is a bit weird (and why
specifically that one, and not other hash functions we also support?).
There would be nothing wrong with that construction, but it's not
used in any standard protocol and would be a curious choice.

BLAKE2 being a keyed hash function, it doesn't need HMAC to be used as
a MAC, so that also doesn't make it a good example of a possible hash
function for HMAC.

This commit doesn't remove the ability to use a Hmac(Blake2s256) type
if, for some reason, applications really need this, but it removes
HmacBlake2s256 as a constant.
2020-10-15 20:50:34 -04:00

109 lines
3.8 KiB
Zig

// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 Zig Contributors
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
const std = @import("../std.zig");
const crypto = std.crypto;
const debug = std.debug;
const mem = std.mem;
pub const HmacMd5 = Hmac(crypto.hash.Md5);
pub const HmacSha1 = Hmac(crypto.hash.Sha1);
pub const sha2 = struct {
pub const HmacSha224 = Hmac(crypto.hash.sha2.Sha224);
pub const HmacSha256 = Hmac(crypto.hash.sha2.Sha256);
pub const HmacSha384 = Hmac(crypto.hash.sha2.Sha384);
pub const HmacSha512 = Hmac(crypto.hash.sha2.Sha512);
};
pub fn Hmac(comptime Hash: type) type {
return struct {
const Self = @This();
pub const mac_length = Hash.digest_length;
pub const minimum_key_length = 0;
o_key_pad: [Hash.block_length]u8,
i_key_pad: [Hash.block_length]u8,
scratch: [Hash.block_length]u8,
hash: Hash,
// HMAC(k, m) = H(o_key_pad | H(i_key_pad | msg)) where | is concatenation
pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
var ctx = Self.init(key);
ctx.update(msg);
ctx.final(out[0..]);
}
pub fn init(key: []const u8) Self {
var ctx: Self = undefined;
// Normalize key length to block size of hash
if (key.len > Hash.block_length) {
Hash.hash(key, ctx.scratch[0..mac_length], .{});
mem.set(u8, ctx.scratch[mac_length..Hash.block_length], 0);
} else if (key.len < Hash.block_length) {
mem.copy(u8, ctx.scratch[0..key.len], key);
mem.set(u8, ctx.scratch[key.len..Hash.block_length], 0);
} else {
mem.copy(u8, ctx.scratch[0..], key);
}
for (ctx.o_key_pad) |*b, i| {
b.* = ctx.scratch[i] ^ 0x5c;
}
for (ctx.i_key_pad) |*b, i| {
b.* = ctx.scratch[i] ^ 0x36;
}
ctx.hash = Hash.init(.{});
ctx.hash.update(ctx.i_key_pad[0..]);
return ctx;
}
pub fn update(ctx: *Self, msg: []const u8) void {
ctx.hash.update(msg);
}
pub fn final(ctx: *Self, out: []u8) void {
debug.assert(Hash.block_length >= out.len and out.len >= mac_length);
ctx.hash.final(ctx.scratch[0..mac_length]);
var ohash = Hash.init(.{});
ohash.update(ctx.o_key_pad[0..]);
ohash.update(ctx.scratch[0..mac_length]);
ohash.final(out[0..mac_length]);
}
};
}
const htest = @import("test.zig");
test "hmac md5" {
var out: [HmacMd5.mac_length]u8 = undefined;
HmacMd5.create(out[0..], "", "");
htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]);
HmacMd5.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]);
}
test "hmac sha1" {
var out: [HmacSha1.mac_length]u8 = undefined;
HmacSha1.create(out[0..], "", "");
htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]);
HmacSha1.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]);
}
test "hmac sha256" {
var out: [sha2.HmacSha256.mac_length]u8 = undefined;
sha2.HmacSha256.create(out[0..], "", "");
htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
sha2.HmacSha256.create(out[0..], "The quick brown fox jumps over the lazy dog", "key");
htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
}