use hmac::{Hmac, Mac};
use sha2::{Sha256, Sha512};
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum CryptoError {
#[error("HMAC key has an invalid length")]
InvalidKeyLength,
}
pub fn hmac_sha256(key: &[u8], message: &[u8]) -> Result<[u8; 32], CryptoError> {
let mut mac =
<Hmac<Sha256> as Mac>::new_from_slice(key).map_err(|_| CryptoError::InvalidKeyLength)?;
mac.update(message);
Ok(mac.finalize().into_bytes().into())
}
pub fn hmac_sha512(key: &[u8], message: &[u8]) -> Result<[u8; 64], CryptoError> {
let mut mac =
<Hmac<Sha512> as Mac>::new_from_slice(key).map_err(|_| CryptoError::InvalidKeyLength)?;
mac.update(message);
Ok(mac.finalize().into_bytes().into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hmac_sha256_rfc4231_case1() {
let key = [0x0bu8; 20];
let data = b"Hi There";
let expected =
hex::decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")
.unwrap();
assert_eq!(hmac_sha256(&key, data).unwrap().to_vec(), expected);
}
#[test]
fn hmac_sha256_rfc4231_case2() {
let key = b"Jefe";
let data = b"what do ya want for nothing?";
let expected =
hex::decode("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")
.unwrap();
assert_eq!(hmac_sha256(key, data).unwrap().to_vec(), expected);
}
#[test]
fn hmac_sha256_rfc4231_case6() {
let key = [0xaau8; 131];
let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
let expected =
hex::decode("60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54")
.unwrap();
assert_eq!(hmac_sha256(&key, data).unwrap().to_vec(), expected);
}
#[test]
fn hmac_sha512_rfc4231_case1() {
let key = [0x0bu8; 20];
let data = b"Hi There";
let expected = hex::decode(
"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854",
)
.unwrap();
assert_eq!(hmac_sha512(&key, data).unwrap().to_vec(), expected);
}
#[test]
fn empty_key_is_accepted_per_hmac_semantics() {
assert!(hmac_sha256(&[], b"message").is_ok());
}
}