use crypto_core::{CryptoError, MacAlgorithm, MacFailureKind};
use hmac::{Hmac, KeyInit, Mac};
use sha2::{Sha256, Sha384, Sha512};
use crate::types::{mac_hash, HmacKey, HmacTag};
type HmacSha256 = Hmac<Sha256>;
type HmacSha384 = Hmac<Sha384>;
type HmacSha512 = Hmac<Sha512>;
pub fn authenticate(
algorithm: MacAlgorithm,
key: &HmacKey,
message: &[u8],
) -> Result<HmacTag, CryptoError> {
match algorithm {
MacAlgorithm::HmacSha256 => authenticate_sha256(key, message),
MacAlgorithm::HmacSha384 => authenticate_sha384(key, message),
MacAlgorithm::HmacSha512 => authenticate_sha512(key, message),
}
}
pub fn verify(
algorithm: MacAlgorithm,
key: &HmacKey,
message: &[u8],
expected_tag: &[u8],
) -> Result<(), CryptoError> {
let expected_tag = HmacTag::from_slice(algorithm, expected_tag)?;
match algorithm {
MacAlgorithm::HmacSha256 => verify_sha256(key, message, expected_tag.as_bytes()),
MacAlgorithm::HmacSha384 => verify_sha384(key, message, expected_tag.as_bytes()),
MacAlgorithm::HmacSha512 => verify_sha512(key, message, expected_tag.as_bytes()),
}
}
fn authenticate_sha256(key: &HmacKey, message: &[u8]) -> Result<HmacTag, CryptoError> {
let mut mac = HmacSha256::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha256),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
let bytes = mac.finalize().into_bytes();
HmacTag::from_slice(MacAlgorithm::HmacSha256, &bytes)
}
fn authenticate_sha384(key: &HmacKey, message: &[u8]) -> Result<HmacTag, CryptoError> {
let mut mac = HmacSha384::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha384),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
let bytes = mac.finalize().into_bytes();
HmacTag::from_slice(MacAlgorithm::HmacSha384, &bytes)
}
fn authenticate_sha512(key: &HmacKey, message: &[u8]) -> Result<HmacTag, CryptoError> {
let mut mac = HmacSha512::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha512),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
let bytes = mac.finalize().into_bytes();
HmacTag::from_slice(MacAlgorithm::HmacSha512, &bytes)
}
fn verify_sha256(key: &HmacKey, message: &[u8], expected_tag: &[u8]) -> Result<(), CryptoError> {
let mut mac = HmacSha256::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha256),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
mac.verify_slice(expected_tag)
.map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha256),
kind: MacFailureKind::VerificationFailed,
})
}
fn verify_sha384(key: &HmacKey, message: &[u8], expected_tag: &[u8]) -> Result<(), CryptoError> {
let mut mac = HmacSha384::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha384),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
mac.verify_slice(expected_tag)
.map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha384),
kind: MacFailureKind::VerificationFailed,
})
}
fn verify_sha512(key: &HmacKey, message: &[u8], expected_tag: &[u8]) -> Result<(), CryptoError> {
let mut mac = HmacSha512::new_from_slice(key.as_bytes()).map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha512),
kind: MacFailureKind::InvalidKeyLength,
})?;
mac.update(message);
mac.verify_slice(expected_tag)
.map_err(|_| CryptoError::Mac {
hash: mac_hash(MacAlgorithm::HmacSha512),
kind: MacFailureKind::VerificationFailed,
})
}