#![forbid(unsafe_code)]
extern crate alloc;
pub mod hmac_streaming_hash;
pub use hmac_streaming_hash::{
hmac_with_streaming_hash, StreamingHashHmac, StreamingHashHmacSession,
};
use digest::KeyInit;
use hmac::Mac as HmacMac;
use oxicrypto_core::{CryptoError, Mac, StreamingMac};
use subtle::ConstantTimeEq;
#[derive(Debug, Default, Clone, Copy)]
pub struct HmacSha256;
impl Mac for HmacSha256 {
fn name(&self) -> &'static str {
"HMAC-SHA-256"
}
fn key_len(&self) -> usize {
32
}
fn output_len(&self) -> usize {
32
}
fn min_key_len(&self) -> usize {
32
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
if out.len() < 32 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac =
hmac::Hmac::<sha2::Sha256>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
mac.update(msg);
let result = mac.finalize().into_bytes();
out[..32].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 32 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 32];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl HmacSha256 {
pub const OUTPUT_LEN: usize = 32;
pub fn new_keyed(key: &[u8]) -> Result<HmacSha256Keyed, CryptoError> {
HmacSha256Keyed::new(key)
}
pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
let n = out.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut full = [0u8; 32];
self.mac(key, msg, &mut full)?;
out.copy_from_slice(&full[..n]);
Ok(())
}
pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
let n = tag.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut buf = [0u8; 32];
self.mac(key, msg, &mut buf)?;
if buf[..n].ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct HmacSha512;
impl Mac for HmacSha512 {
fn name(&self) -> &'static str {
"HMAC-SHA-512"
}
fn key_len(&self) -> usize {
64
}
fn output_len(&self) -> usize {
64
}
fn min_key_len(&self) -> usize {
64
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
if out.len() < 64 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac =
hmac::Hmac::<sha2::Sha512>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
mac.update(msg);
let result = mac.finalize().into_bytes();
out[..64].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 64 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 64];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl HmacSha512 {
pub const OUTPUT_LEN: usize = 64;
pub fn new_keyed(key: &[u8]) -> Result<HmacSha512Keyed, CryptoError> {
HmacSha512Keyed::new(key)
}
pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
let n = out.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut full = [0u8; 64];
self.mac(key, msg, &mut full)?;
out.copy_from_slice(&full[..n]);
Ok(())
}
pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
let n = tag.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut buf = [0u8; 64];
self.mac(key, msg, &mut buf)?;
if buf[..n].ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct HmacSha384;
impl Mac for HmacSha384 {
fn name(&self) -> &'static str {
"HMAC-SHA-384"
}
fn key_len(&self) -> usize {
48
}
fn output_len(&self) -> usize {
48
}
fn min_key_len(&self) -> usize {
48
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
if out.len() < 48 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac =
hmac::Hmac::<sha2::Sha384>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
mac.update(msg);
let result = mac.finalize().into_bytes();
out[..48].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 48 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 48];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl HmacSha384 {
pub const OUTPUT_LEN: usize = 48;
pub fn new_keyed(key: &[u8]) -> Result<HmacSha384Keyed, CryptoError> {
HmacSha384Keyed::new(key)
}
pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
let n = out.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut full = [0u8; 48];
self.mac(key, msg, &mut full)?;
out.copy_from_slice(&full[..n]);
Ok(())
}
pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
let n = tag.len();
if n < 16 {
return Err(CryptoError::BadInput);
}
let mut buf = [0u8; 48];
self.mac(key, msg, &mut buf)?;
if buf[..n].ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub struct HmacStreamingAdapter<D: hmac::digest::block_api::EagerHash>
where
hmac::Hmac<D>: HmacMac + KeyInit,
{
inner: hmac::Hmac<D>,
}
impl<D: hmac::digest::block_api::EagerHash> HmacStreamingAdapter<D>
where
hmac::Hmac<D>: HmacMac + KeyInit,
{
pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
let inner = hmac::Hmac::<D>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
Ok(Self { inner })
}
}
impl<D: hmac::digest::block_api::EagerHash + Send> StreamingMac for HmacStreamingAdapter<D>
where
hmac::Hmac<D>: HmacMac + KeyInit + Send,
{
fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}
fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
let tag = self.inner.finalize().into_bytes();
if out.len() < tag.len() {
return Err(CryptoError::BufferTooSmall);
}
out[..tag.len()].copy_from_slice(&tag);
Ok(())
}
fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
let tag = self.inner.finalize().into_bytes();
if tag.len() != expected.len() {
return Err(CryptoError::InvalidTag);
}
if tag.as_slice().ct_eq(expected).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub type HmacSha256Streaming = HmacStreamingAdapter<sha2::Sha256>;
pub type HmacSha384Streaming = HmacStreamingAdapter<sha2::Sha384>;
pub type HmacSha512Streaming = HmacStreamingAdapter<sha2::Sha512>;
pub struct HmacSha256Keyed(hmac::Hmac<sha2::Sha256>);
impl HmacSha256Keyed {
pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
hmac::Hmac::<sha2::Sha256>::new_from_slice(key)
.map(Self)
.map_err(|_| CryptoError::InvalidKey)
}
}
impl StreamingMac for HmacSha256Keyed {
fn update(&mut self, data: &[u8]) {
HmacMac::update(&mut self.0, data);
}
fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
let result = HmacMac::finalize(self.0).into_bytes();
if out.len() < result.len() {
return Err(CryptoError::BufferTooSmall);
}
out[..result.len()].copy_from_slice(&result);
Ok(())
}
fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
let tag = HmacMac::finalize(self.0).into_bytes();
if tag.len() != expected.len() {
return Err(CryptoError::InvalidTag);
}
if tag.as_slice().ct_eq(expected).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub struct HmacSha512Keyed(hmac::Hmac<sha2::Sha512>);
impl HmacSha512Keyed {
pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
hmac::Hmac::<sha2::Sha512>::new_from_slice(key)
.map(Self)
.map_err(|_| CryptoError::InvalidKey)
}
}
impl StreamingMac for HmacSha512Keyed {
fn update(&mut self, data: &[u8]) {
HmacMac::update(&mut self.0, data);
}
fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
let result = HmacMac::finalize(self.0).into_bytes();
if out.len() < result.len() {
return Err(CryptoError::BufferTooSmall);
}
out[..result.len()].copy_from_slice(&result);
Ok(())
}
fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
let tag = HmacMac::finalize(self.0).into_bytes();
if tag.len() != expected.len() {
return Err(CryptoError::InvalidTag);
}
if tag.as_slice().ct_eq(expected).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub struct HmacSha384Keyed(hmac::Hmac<sha2::Sha384>);
impl HmacSha384Keyed {
pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
hmac::Hmac::<sha2::Sha384>::new_from_slice(key)
.map(Self)
.map_err(|_| CryptoError::InvalidKey)
}
}
impl StreamingMac for HmacSha384Keyed {
fn update(&mut self, data: &[u8]) {
HmacMac::update(&mut self.0, data);
}
fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
let result = HmacMac::finalize(self.0).into_bytes();
if out.len() < result.len() {
return Err(CryptoError::BufferTooSmall);
}
out[..result.len()].copy_from_slice(&result);
Ok(())
}
fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
let tag = HmacMac::finalize(self.0).into_bytes();
if tag.len() != expected.len() {
return Err(CryptoError::InvalidTag);
}
if tag.as_slice().ct_eq(expected).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct HmacSha3_256;
impl Mac for HmacSha3_256 {
fn name(&self) -> &'static str {
"HMAC-SHA3-256"
}
fn key_len(&self) -> usize {
32
}
fn output_len(&self) -> usize {
32
}
fn min_key_len(&self) -> usize {
32
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use digest::KeyInit as _;
if out.len() < 32 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac = hmac::SimpleHmac::<sha3::Sha3_256>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKey)?;
HmacMac::update(&mut mac, msg);
let result = HmacMac::finalize(mac).into_bytes();
out[..32].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 32 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 32];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl HmacSha3_256 {
pub const OUTPUT_LEN: usize = 32;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct HmacSha3_512;
impl Mac for HmacSha3_512 {
fn name(&self) -> &'static str {
"HMAC-SHA3-512"
}
fn key_len(&self) -> usize {
64
}
fn output_len(&self) -> usize {
64
}
fn min_key_len(&self) -> usize {
64
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use digest::KeyInit as _;
if out.len() < 64 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac = hmac::SimpleHmac::<sha3::Sha3_512>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKey)?;
HmacMac::update(&mut mac, msg);
let result = HmacMac::finalize(mac).into_bytes();
out[..64].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 64 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 64];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl HmacSha3_512 {
pub const OUTPUT_LEN: usize = 64;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Poly1305Mac;
impl Mac for Poly1305Mac {
fn name(&self) -> &'static str {
"Poly1305"
}
fn key_len(&self) -> usize {
32
}
fn output_len(&self) -> usize {
16
}
fn min_key_len(&self) -> usize {
32
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use poly1305::universal_hash::KeyInit as _;
if key.len() != 32 {
return Err(CryptoError::InvalidKey);
}
if out.len() < 16 {
return Err(CryptoError::BufferTooSmall);
}
let key_arr = poly1305::Key::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
let mac = poly1305::Poly1305::new(&key_arr);
let tag = mac.compute_unpadded(msg);
out[..16].copy_from_slice(tag.as_slice());
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 16 {
return Err(CryptoError::InvalidTag);
}
let mut computed = [0u8; 16];
self.mac(key, msg, &mut computed)?;
if computed.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl Poly1305Mac {
pub const OUTPUT_LEN: usize = 16;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CmacAes128;
impl Mac for CmacAes128 {
fn name(&self) -> &'static str {
"CMAC-AES-128"
}
fn key_len(&self) -> usize {
16
}
fn output_len(&self) -> usize {
16
}
fn min_key_len(&self) -> usize {
16
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use cmac::Mac as _;
use digest::KeyInit as _;
if out.len() < 16 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac = cmac::Cmac::<aes_cipher05::Aes128>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKey)?;
mac.update(msg);
let result = mac.finalize().into_bytes();
out[..16].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 16 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 16];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl CmacAes128 {
pub const OUTPUT_LEN: usize = 16;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct CmacAes256;
impl Mac for CmacAes256 {
fn name(&self) -> &'static str {
"CMAC-AES-256"
}
fn key_len(&self) -> usize {
32
}
fn output_len(&self) -> usize {
16
}
fn min_key_len(&self) -> usize {
32
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use cmac::Mac as _;
use digest::KeyInit as _;
if out.len() < 16 {
return Err(CryptoError::BufferTooSmall);
}
let mut mac = cmac::Cmac::<aes_cipher05::Aes256>::new_from_slice(key)
.map_err(|_| CryptoError::InvalidKey)?;
mac.update(msg);
let result = mac.finalize().into_bytes();
out[..16].copy_from_slice(&result);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != 16 {
return Err(CryptoError::InvalidTag);
}
let mut expected = [0u8; 16];
self.mac(key, msg, &mut expected)?;
if expected.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
impl CmacAes256 {
pub const OUTPUT_LEN: usize = 16;
}
pub struct Kmac128 {
custom: alloc::vec::Vec<u8>,
output_len: usize,
}
impl Kmac128 {
pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
if output_len == 0 {
return Err(CryptoError::BadInput);
}
Ok(Self {
custom: custom.to_vec(),
output_len,
})
}
}
impl core::fmt::Debug for Kmac128 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Kmac128")
.field("output_len", &self.output_len)
.finish()
}
}
impl Mac for Kmac128 {
fn name(&self) -> &'static str {
"KMAC128"
}
fn key_len(&self) -> usize {
16
}
fn output_len(&self) -> usize {
self.output_len
}
fn min_key_len(&self) -> usize {
16
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use tiny_keccak::Hasher as _;
if out.len() < self.output_len {
return Err(CryptoError::BufferTooSmall);
}
let mut kmac = tiny_keccak::Kmac::v128(key, &self.custom);
kmac.update(msg);
kmac.finalize(&mut out[..self.output_len]);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != self.output_len {
return Err(CryptoError::InvalidTag);
}
let mut computed = alloc::vec![0u8; self.output_len];
self.mac(key, msg, &mut computed)?;
if computed.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub struct Kmac256 {
custom: alloc::vec::Vec<u8>,
output_len: usize,
}
impl Kmac256 {
pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
if output_len == 0 {
return Err(CryptoError::BadInput);
}
Ok(Self {
custom: custom.to_vec(),
output_len,
})
}
}
impl core::fmt::Debug for Kmac256 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Kmac256")
.field("output_len", &self.output_len)
.finish()
}
}
impl Mac for Kmac256 {
fn name(&self) -> &'static str {
"KMAC256"
}
fn key_len(&self) -> usize {
32
}
fn output_len(&self) -> usize {
self.output_len
}
fn min_key_len(&self) -> usize {
16
}
fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
use tiny_keccak::Hasher as _;
if out.len() < self.output_len {
return Err(CryptoError::BufferTooSmall);
}
let mut kmac = tiny_keccak::Kmac::v256(key, &self.custom);
kmac.update(msg);
kmac.finalize(&mut out[..self.output_len]);
Ok(())
}
fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
if tag.len() != self.output_len {
return Err(CryptoError::InvalidTag);
}
let mut computed = alloc::vec![0u8; self.output_len];
self.mac(key, msg, &mut computed)?;
if computed.ct_eq(tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
}
pub fn kmac128_xof(
key: &[u8],
custom: &[u8],
msg: &[u8],
output_len: usize,
) -> Result<alloc::vec::Vec<u8>, CryptoError> {
use tiny_keccak::Hasher as _;
if output_len == 0 {
return Err(CryptoError::BadInput);
}
let mut k = tiny_keccak::Kmac::v128(key, custom);
k.update(msg);
let mut out = alloc::vec![0u8; output_len];
k.finalize(&mut out);
Ok(out)
}
pub fn kmac256_xof(
key: &[u8],
custom: &[u8],
msg: &[u8],
output_len: usize,
) -> Result<alloc::vec::Vec<u8>, CryptoError> {
use tiny_keccak::Hasher as _;
if output_len == 0 {
return Err(CryptoError::BadInput);
}
let mut k = tiny_keccak::Kmac::v256(key, custom);
k.update(msg);
let mut out = alloc::vec![0u8; output_len];
k.finalize(&mut out);
Ok(out)
}
pub fn blake3_keyed_mac(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
*blake3::Hasher::new_keyed(key)
.update(msg)
.finalize()
.as_bytes()
}
pub fn blake3_keyed_mac_verify(
key: &[u8; 32],
msg: &[u8],
expected: &[u8; 32],
) -> Result<(), CryptoError> {
let actual = blake3_keyed_mac(key, msg);
if actual.ct_eq(expected).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
pub fn hmac_sha256_verify_truncated(
key: &[u8],
msg: &[u8],
truncated_tag: &[u8],
) -> Result<(), CryptoError> {
if truncated_tag.is_empty() || truncated_tag.len() > 32 {
return Err(CryptoError::BadInput);
}
let mut buf = [0u8; 32];
HmacSha256.mac(key, msg, &mut buf)?;
if buf[..truncated_tag.len()].ct_eq(truncated_tag).into() {
Ok(())
} else {
Err(CryptoError::InvalidTag)
}
}
pub mod tls;
pub use tls::{mac_name_for_suite, negotiate_mac, TlsCipherSuite};
#[must_use = "MAC result must be used or verified"]
pub fn hmac_sha256_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
let mut out = alloc::vec![0u8; 32];
HmacSha256.mac(key, msg, &mut out)?;
Ok(out)
}
#[must_use = "MAC result must be used or verified"]
pub fn hmac_sha384_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
let mut out = alloc::vec![0u8; 48];
HmacSha384.mac(key, msg, &mut out)?;
Ok(out)
}
#[must_use = "MAC result must be used or verified"]
pub fn hmac_sha512_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
let mut out = alloc::vec![0u8; 64];
HmacSha512.mac(key, msg, &mut out)?;
Ok(out)
}
#[cfg(test)]
mod tests {
include!("tests_inline.rs");
}