1use crypto_core::{CryptoError, KdfAlgorithm, KdfFailureKind, KdfProfile};
8#[cfg(any(feature = "native", feature = "wasm"))]
9use sha3_kmac::Kmac256;
10use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
11
12pub const KMAC256_MIN_KEY_LENGTH: usize = 32;
15
16pub const KMAC256_MAX_KEY_LENGTH: usize = 4_096;
22
23pub const KMAC256_MAX_CONTEXT_LENGTH: usize = 65_536;
25
26pub const KMAC256_MAX_CUSTOMIZATION_LENGTH: usize = 4_096;
28
29pub const KMAC256_MAX_OUTPUT_LENGTH: usize = 65_536;
35
36#[derive(Zeroize, ZeroizeOnDrop)]
38pub struct Kmac256Key {
39 bytes: Zeroizing<Vec<u8>>,
40}
41
42impl Kmac256Key {
43 pub fn from_slice(input: &[u8]) -> Result<Self, CryptoError> {
51 if !(KMAC256_MIN_KEY_LENGTH..=KMAC256_MAX_KEY_LENGTH).contains(&input.len()) {
52 return Err(kmac_error(KdfFailureKind::InvalidSecretLength));
53 }
54
55 Ok(Self {
56 bytes: Zeroizing::new(input.to_vec()),
57 })
58 }
59
60 pub fn as_bytes(&self) -> &[u8] {
62 &self.bytes
63 }
64}
65
66#[derive(Zeroize, ZeroizeOnDrop)]
68pub struct Kmac256Output {
69 bytes: Zeroizing<Vec<u8>>,
70}
71
72impl Kmac256Output {
73 pub fn as_bytes(&self) -> &[u8] {
75 &self.bytes
76 }
77
78 pub fn len(&self) -> usize {
80 self.bytes.len()
81 }
82
83 pub fn is_empty(&self) -> bool {
85 self.bytes.is_empty()
86 }
87}
88
89#[cfg(any(feature = "native", feature = "wasm"))]
101pub fn derive_kmac256(
102 key: &Kmac256Key,
103 context: &[u8],
104 customization: &[u8],
105 output_length: usize,
106) -> Result<Kmac256Output, CryptoError> {
107 if output_length == 0 || output_length > KMAC256_MAX_OUTPUT_LENGTH {
108 return Err(kmac_error(KdfFailureKind::InvalidOutputLength));
109 }
110 if context.len() > KMAC256_MAX_CONTEXT_LENGTH
111 || customization.len() > KMAC256_MAX_CUSTOMIZATION_LENGTH
112 {
113 return Err(kmac_error(KdfFailureKind::InvalidParams));
114 }
115
116 let mut kmac = Kmac256::new(key.as_bytes(), customization)
117 .map_err(|_| kmac_error(KdfFailureKind::InvalidSecretLength))?;
118 kmac.update(context);
119 let mut output = Zeroizing::new(vec![0u8; output_length]);
120 kmac.finalize_into(&mut output);
121 Ok(Kmac256Output { bytes: output })
122}
123
124fn kmac_error(kind: KdfFailureKind) -> CryptoError {
125 CryptoError::Kdf {
126 algorithm: KdfAlgorithm::Kmac256,
127 profile: KdfProfile::Sp800185Kmac256,
128 kind,
129 }
130}