use alloc::vec::Vec;
use crate::{
error::{CryptoError, Result},
mac::Mac,
};
pub fn hkdf_extract<M: Mac>(salt: &[u8], ikm: &[u8]) -> Result<Vec<u8>> {
let actual_salt = if salt.is_empty() {
alloc::vec![0u8; M::output_size()]
} else {
salt.to_vec()
};
let mut mac = M::new(&actual_salt)?;
mac.update(ikm);
Ok(mac.finalize())
}
pub fn hkdf_expand<M: Mac>(prk: &[u8], info: &[u8], length: usize) -> Result<Vec<u8>> {
let hash_len = M::output_size();
if length > 255 * hash_len {
return Err(CryptoError::InvalidLength);
}
let n = length.div_ceil(hash_len);
let mut okm = Vec::with_capacity(length);
let mut t = Vec::new();
for i in 1..=n {
let mut mac = M::new(prk)?;
mac.update(&t);
mac.update(info);
mac.update(&[i as u8]);
t = mac.finalize();
okm.extend_from_slice(&t);
}
okm.truncate(length);
Ok(okm)
}
pub fn hkdf<M: Mac>(salt: &[u8], ikm: &[u8], info: &[u8], length: usize) -> Result<Vec<u8>> {
let prk = hkdf_extract::<M>(salt, ikm)?;
hkdf_expand::<M>(&prk, info, length)
}