use crypto_core::{CryptoError, KdfAlgorithm, KdfFailureKind, KdfProfile};
#[cfg(any(feature = "native", feature = "wasm"))]
use sha3_kmac::Kmac256;
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
pub const KMAC256_MIN_KEY_LENGTH: usize = 32;
pub const KMAC256_MAX_KEY_LENGTH: usize = 4_096;
pub const KMAC256_MAX_CONTEXT_LENGTH: usize = 65_536;
pub const KMAC256_MAX_CUSTOMIZATION_LENGTH: usize = 4_096;
pub const KMAC256_MAX_OUTPUT_LENGTH: usize = 65_536;
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Kmac256Key {
bytes: Zeroizing<Vec<u8>>,
}
impl Kmac256Key {
pub fn from_slice(input: &[u8]) -> Result<Self, CryptoError> {
if !(KMAC256_MIN_KEY_LENGTH..=KMAC256_MAX_KEY_LENGTH).contains(&input.len()) {
return Err(kmac_error(KdfFailureKind::InvalidSecretLength));
}
Ok(Self {
bytes: Zeroizing::new(input.to_vec()),
})
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Zeroize, ZeroizeOnDrop)]
pub struct Kmac256Output {
bytes: Zeroizing<Vec<u8>>,
}
impl Kmac256Output {
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
#[cfg(any(feature = "native", feature = "wasm"))]
pub fn derive_kmac256(
key: &Kmac256Key,
context: &[u8],
customization: &[u8],
output_length: usize,
) -> Result<Kmac256Output, CryptoError> {
if output_length == 0 || output_length > KMAC256_MAX_OUTPUT_LENGTH {
return Err(kmac_error(KdfFailureKind::InvalidOutputLength));
}
if context.len() > KMAC256_MAX_CONTEXT_LENGTH
|| customization.len() > KMAC256_MAX_CUSTOMIZATION_LENGTH
{
return Err(kmac_error(KdfFailureKind::InvalidParams));
}
let mut kmac = Kmac256::new(key.as_bytes(), customization)
.map_err(|_| kmac_error(KdfFailureKind::InvalidSecretLength))?;
kmac.update(context);
let mut output = Zeroizing::new(vec![0u8; output_length]);
kmac.finalize_into(&mut output);
Ok(Kmac256Output { bytes: output })
}
fn kmac_error(kind: KdfFailureKind) -> CryptoError {
CryptoError::Kdf {
algorithm: KdfAlgorithm::Kmac256,
profile: KdfProfile::Sp800185Kmac256,
kind,
}
}