use crate::classic::crypto_auth_hmac_impl::{
HmacState, hmac, hmac_final, hmac_init, hmac_keygen, hmac_update, hmac_verify,
};
use crate::constants::{CRYPTO_AUTH_HMACSHA512_BYTES, CRYPTO_AUTH_HMACSHA512_KEYBYTES};
use crate::error::Error;
use crate::sha512::Sha512;
pub type Key = [u8; CRYPTO_AUTH_HMACSHA512_KEYBYTES];
pub type Mac = [u8; CRYPTO_AUTH_HMACSHA512_BYTES];
pub struct HmacSha512State(HmacState<Sha512, 128, CRYPTO_AUTH_HMACSHA512_BYTES>);
pub fn crypto_auth_hmacsha512(mac: &mut Mac, message: &[u8], key: &Key) {
hmac::<Sha512, CRYPTO_AUTH_HMACSHA512_KEYBYTES, 128, CRYPTO_AUTH_HMACSHA512_BYTES>(
mac, message, key,
);
}
pub fn crypto_auth_hmacsha512_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
hmac_verify::<Sha512, CRYPTO_AUTH_HMACSHA512_KEYBYTES, 128, CRYPTO_AUTH_HMACSHA512_BYTES>(
mac, input, key,
)
}
pub fn crypto_auth_hmacsha512_keygen() -> Key {
hmac_keygen()
}
pub fn crypto_auth_hmacsha512_init(key: &[u8]) -> HmacSha512State {
HmacSha512State(hmac_init::<Sha512, 128, CRYPTO_AUTH_HMACSHA512_BYTES>(key))
}
pub fn crypto_auth_hmacsha512_update(state: &mut HmacSha512State, input: &[u8]) {
hmac_update(&mut state.0, input);
}
pub fn crypto_auth_hmacsha512_final(state: HmacSha512State, output: &mut Mac) {
hmac_final(state.0, output);
}
#[cfg(test)]
mod tests {
use super::*;
fn compute_hmac(key: &[u8], message: &[u8]) -> Mac {
let mut mac = [0u8; CRYPTO_AUTH_HMACSHA512_BYTES];
let mut state = crypto_auth_hmacsha512_init(key);
crypto_auth_hmacsha512_update(&mut state, message);
crypto_auth_hmacsha512_final(state, &mut mac);
mac
}
fn assert_hmac(key: &[u8], message: &[u8], expected_hex: &str) {
let mac = compute_hmac(key, message);
let expected = hex::decode(expected_hex).expect("hex failed");
assert_eq!(mac.as_slice(), expected.as_slice());
}
#[test]
fn test_rfc4231_case_1() {
let key = [0x0bu8; 20];
assert_hmac(
&key,
b"Hi There",
concat!(
"87aa7cdea5ef619d4ff0b4241a1d6cb0",
"2379f4e2ce4ec2787ad0b30545e17cde",
"daa833b7d6b8a702038b274eaea3f4e4",
"be9d914eeb61f1702e696c203a126854",
),
);
}
#[test]
fn test_rfc4231_short_key_case_2() {
assert_hmac(
b"Jefe",
b"what do ya want for nothing?",
concat!(
"164b7a7bfcf819e2e395fbe73b56e0a3",
"87bd64222e831fd610270cd7ea250554",
"9758bf75c05a994a6d034f65f8f0e6fd",
"caeab1a34d4a6b4b636e070a38bce737",
),
);
}
#[test]
fn test_rfc4231_long_message_case_3() {
let key = [0xaau8; 20];
let message = [0xddu8; 50];
assert_hmac(
&key,
&message,
concat!(
"fa73b0089d56a284efb0f0756c890be9",
"b1b5dbdd8ee81a3655f83e33b2279d39",
"bf3e848279a722c806b485a47e67c807",
"b946a337bee8942674278859e13292fb",
),
);
}
#[test]
fn test_rfc4231_long_key_case_6() {
let key = [0xaau8; 131];
assert_hmac(
&key,
b"Test Using Larger Than Block-Size Key - Hash Key First",
concat!(
"80b24263c7c1a3ebb71493c1dd7be8b4",
"9b46d1f41b4aeec1121b013783f8f352",
"6b56d037e05f2598bd0fd2215d6a1e52",
"95e64f73f63f0aec8b915a985d786598",
),
);
}
#[test]
fn test_rfc4231_long_key_and_message_case_7() {
let key = [0xaau8; 131];
assert_hmac(
&key,
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.",
concat!(
"e37b6a775dc87dbaa4dfa9f96e5e3ffd",
"debd71f8867289865df5a32d20cdc944",
"b6022cac3c4982b10d5eeb55c3e4de15",
"134676fb6de0446065c97440fa8c6a58",
),
);
}
#[test]
fn test_rfc4231_case_4() {
let key =
hex::decode("0102030405060708090a0b0c0d0e0f10111213141516171819").expect("hex failed");
let message = [0xcdu8; 50];
assert_hmac(
&key,
&message,
concat!(
"b0ba465637458c6990e5a8c5f61d4af7",
"e576d97ff94b872de76f8050361ee3db",
"a91ca5c11aa25eb4d679275cc5788063",
"a5f19741120c4f2de2adebeb10a298dd",
),
);
}
#[test]
fn test_rfc4231_case_1_matches_one_shot_for_keybytes_key() {
let key = [0x0bu8; CRYPTO_AUTH_HMACSHA512_KEYBYTES];
let message = b"Hi There";
let mut one_shot = [0u8; CRYPTO_AUTH_HMACSHA512_BYTES];
crypto_auth_hmacsha512(&mut one_shot, message, &key);
assert_eq!(one_shot, compute_hmac(&key, message));
}
#[cfg(dryoc_native_tests)]
#[test]
fn test_libsodium_compatibility() {
use sodiumoxide::crypto::auth::hmacsha512;
let key = crypto_auth_hmacsha512_keygen();
let message = b"message to authenticate";
let so_key = hmacsha512::Key::from_slice(&key).expect("key failed");
let so_mac = hmacsha512::authenticate(message, &so_key);
let mut mac = [0u8; CRYPTO_AUTH_HMACSHA512_BYTES];
crypto_auth_hmacsha512(&mut mac, message, &key);
assert_eq!(mac.as_slice(), so_mac.as_ref());
crypto_auth_hmacsha512_verify(&mac, message, &key).expect("verify failed");
let mut state = crypto_auth_hmacsha512_init(&key);
crypto_auth_hmacsha512_update(&mut state, b"message ");
crypto_auth_hmacsha512_update(&mut state, b"to authenticate");
let mut state_mac = [0u8; CRYPTO_AUTH_HMACSHA512_BYTES];
crypto_auth_hmacsha512_final(state, &mut state_mac);
assert_eq!(state_mac.as_slice(), so_mac.as_ref());
}
}