use crate::hash::{ Md2, Md4, Md5, Sm3, Sha1, Sha224, Sha256, Sha384, Sha512, };
const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5C;
macro_rules! impl_hmac_with_hasher {
($name:tt, $hasher:tt) => {
#[derive(Clone)]
pub struct $name {
okey: [u8; Self::BLOCK_LEN],
hasher: $hasher,
}
impl $name {
pub const BLOCK_LEN: usize = $hasher::BLOCK_LEN;
pub const TAG_LEN: usize = $hasher::DIGEST_LEN;
pub fn new(key: &[u8]) -> Self {
let mut ikey = [0u8; Self::BLOCK_LEN];
let mut okey = [0u8; Self::BLOCK_LEN];
if key.len() > Self::BLOCK_LEN {
let hkey = $hasher::oneshot(key);
ikey[..Self::TAG_LEN].copy_from_slice(&hkey[..Self::TAG_LEN]);
okey[..Self::TAG_LEN].copy_from_slice(&hkey[..Self::TAG_LEN]);
} else {
ikey[..key.len()].copy_from_slice(&key);
okey[..key.len()].copy_from_slice(&key);
}
for idx in 0..Self::BLOCK_LEN {
ikey[idx] ^= IPAD;
okey[idx] ^= OPAD;
}
let mut hasher = $hasher::new();
hasher.update(&ikey);
Self { okey, hasher }
}
pub fn update(&mut self, m: &[u8]) {
self.hasher.update(m);
}
pub fn finalize(self) -> [u8; Self::TAG_LEN] {
let h1 = self.hasher.finalize();
let mut hasher = $hasher::new();
hasher.update(&self.okey);
hasher.update(&h1);
let h2 = hasher.finalize();
return h2;
}
pub fn oneshot(key: &[u8], m: &[u8]) -> [u8; Self::TAG_LEN] {
let mut mac = Self::new(key);
mac.update(m);
mac.finalize()
}
}
}
}
impl_hmac_with_hasher!(HmacMd2, Md2);
impl_hmac_with_hasher!(HmacMd4, Md4);
impl_hmac_with_hasher!(HmacMd5, Md5);
impl_hmac_with_hasher!(HmacSm3, Sm3);
impl_hmac_with_hasher!(HmacSha1, Sha1);
impl_hmac_with_hasher!(HmacSha224, Sha224);
impl_hmac_with_hasher!(HmacSha256, Sha256);
impl_hmac_with_hasher!(HmacSha384, Sha384);
impl_hmac_with_hasher!(HmacSha512, Sha512);
pub fn hmac_md2(key: &[u8], m: &[u8]) -> [u8; HmacMd2::TAG_LEN] {
HmacMd2::oneshot(key, m)
}
pub fn hmac_md4(key: &[u8], m: &[u8]) -> [u8; HmacMd4::TAG_LEN] {
HmacMd4::oneshot(key, m)
}
pub fn hmac_md5(key: &[u8], m: &[u8]) -> [u8; HmacMd5::TAG_LEN] {
HmacMd5::oneshot(key, m)
}
pub fn hmac_sm3(key: &[u8], m: &[u8]) -> [u8; HmacSm3::TAG_LEN] {
HmacSm3::oneshot(key, m)
}
pub fn hmac_sha1(key: &[u8], m: &[u8]) -> [u8; HmacSha1::TAG_LEN] {
HmacSha1::oneshot(key, m)
}
pub fn hmac_sha256(key: &[u8], m: &[u8]) -> [u8; HmacSha256::TAG_LEN] {
HmacSha256::oneshot(key, m)
}
pub fn hmac_sha384(key: &[u8], m: &[u8]) -> [u8; HmacSha384::TAG_LEN] {
HmacSha384::oneshot(key, m)
}
pub fn hmac_sha512(key: &[u8], m: &[u8]) -> [u8; HmacSha512::TAG_LEN] {
HmacSha512::oneshot(key, m)
}
#[test]
fn test_hmac_md5() {
let b16 = [0x0b; 16]; let aa16 = [0xaa; 16]; let dd50 = [0xdd; 50];
let suites: &[(&[u8], &[u8], &str)] = &[
(b"key", b"The quick brown fox jumps over the lazy dog", "80070713463e7749b90c2dc24911e275"),
(&b16, b"Hi There", "9294727a3638bb1c13f48ef8158bfc9d"),
(b"Jefe", b"what do ya want for nothing?", "750c783e6ab0b503eaa86e310a5db738"),
(&aa16, &dd50, "56be34521d144c88dbb8c733f0e8b3f6"),
];
for (key, data, result) in suites.iter() {
assert_eq!(&hex::encode(&HmacMd5::oneshot(key, data)), result);
}
}
#[test]
fn test_hmac_sha1() {
let key = b"key";
let data = b"The quick brown fox jumps over the lazy dog";
let result = "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9";
assert_eq!(&hex::encode(&HmacSha1::oneshot(key, data)), result);
}
#[test]
fn test_hmac_sha2_256() {
let key = b"key";
let data = b"The quick brown fox jumps over the lazy dog";
let result = "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8";
assert_eq!(&hex::encode(&HmacSha256::oneshot(key, data)), result);
}
#[test]
fn test_hmac_sha2_384() {
let key = b"key";
let data = b"The quick brown fox jumps over the lazy dog";
let result = "d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae50700582a96cf35e1e554995fe4e03381c237";
assert_eq!(&hex::encode(&HmacSha384::oneshot(key, data)), result);
}
#[test]
fn test_hmac_sha2_512() {
let key = b"key";
let data = b"The quick brown fox jumps over the lazy dog";
let result = "b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a";
assert_eq!(&hex::encode(&HmacSha512::oneshot(key, data)), result);
}