use hmac::{Hmac, KeyInit, Mac};
use sha3::Sha3_256;
use subtle::ConstantTimeEq;
type HmacSha3_256 = Hmac<Sha3_256>;
#[must_use]
pub fn hmac_sha3_256(key: &[u8], data: &[u8]) -> [u8; 32] {
let mut mac = HmacSha3_256::new_from_slice(key).expect("HMAC accepts any key length");
mac.update(data);
mac.finalize().into_bytes().into()
}
#[must_use]
pub fn hmac_sha3_256_verify_raw(a: &[u8; 32], b: &[u8; 32]) -> bool {
a.ct_eq(b).into()
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn case1() {
let key = [0x0b; 20];
let data = b"Hi There";
let expected = hex!("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb");
assert_eq!(hmac_sha3_256(&key, data), expected);
}
#[test]
fn case2() {
let key = b"Jefe";
let data = b"what do ya want for nothing?";
let expected = hex!("c7d4072e788877ae3596bbb0da73b887c9171f93095b294ae857fbe2645e1ba5");
assert_eq!(hmac_sha3_256(key, data), expected);
}
#[test]
fn case3() {
let key = [0xaa; 20];
let data = [0xdd; 50];
let expected = hex!("84ec79124a27107865cedd8bd82da9965e5ed8c37b0ac98005a7f39ed58a4207");
assert_eq!(hmac_sha3_256(&key, &data), expected);
}
#[test]
fn case4() {
let key = hex!("0102030405060708090a0b0c0d0e0f10111213141516171819");
let data = [0xcd; 50];
let expected = hex!("57366a45e2305321a4bc5aa5fe2ef8a921f6af8273d7fe7be6cfedb3f0aea6d7");
assert_eq!(hmac_sha3_256(&key, &data), expected);
}
#[test]
fn case6() {
let key = [0xaa; 131];
let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
let expected = hex!("ed73a374b96c005235f948032f09674a58c0ce555cfc1f223b02356560312c3b");
assert_eq!(hmac_sha3_256(&key, data), expected);
}
#[test]
fn case7() {
let key = [0xaa; 131];
let data = b"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.";
let expected = hex!("65c5b06d4c3de32a7aef8763261e49adb6e2293ec8e7c61e8de61701fc63e123");
assert_eq!(hmac_sha3_256(&key, data), expected);
}
#[test]
fn verify_raw_correct() {
let mac = hmac_sha3_256(b"key", b"data");
assert!(hmac_sha3_256_verify_raw(&mac, &mac));
}
#[test]
fn verify_raw_wrong() {
let mac_a = hmac_sha3_256(b"key", b"data");
let mac_b = hmac_sha3_256(b"key", b"other");
assert!(!hmac_sha3_256_verify_raw(&mac_a, &mac_b));
}
#[test]
fn verify_raw_single_bit_diff() {
let mac = hmac_sha3_256(b"key", b"data");
let mut flipped = mac;
flipped[0] ^= 0x01;
assert!(!hmac_sha3_256_verify_raw(&mac, &flipped));
}
#[test]
fn empty_key() {
let mac = hmac_sha3_256(b"", b"data");
assert!(mac.iter().any(|&b| b != 0));
}
#[test]
fn empty_data() {
let mac = hmac_sha3_256(b"key", b"");
assert!(mac.iter().any(|&b| b != 0));
}
#[test]
fn empty_key_and_empty_data() {
let mac = hmac_sha3_256(b"", b"");
assert!(mac.iter().any(|&b| b != 0));
}
}