use crate::error::FastCryptoError;
#[cfg(any(test, feature = "experimental"))]
use crate::hash::ReverseWrapper;
#[cfg(any(test, feature = "experimental"))]
use crate::traits::{KeyPair, SigningKey};
use crate::{hash::Digest, traits::ToFromBytes};
use digest::OutputSizeUser;
#[cfg(any(test, feature = "experimental"))]
use digest::{
block_buffer::Eager,
consts::U256,
core_api::{BlockSizeUser, BufferKindUser, CoreProxy, FixedOutputCore, UpdateCore},
typenum::{IsLess, Le, NonZero},
HashMarker,
};
use crate::private_seed::PrivateSeed;
use hkdf::hmac::{Hmac, Mac};
#[cfg(any(test, feature = "experimental"))]
pub fn hkdf_generate_from_ikm<H, K>(
ikm: &[u8], salt: &[u8], info: &[u8], ) -> Result<K, FastCryptoError>
where
H: ReverseWrapper,
<<H as ReverseWrapper>::Variant as CoreProxy>::Core: HashMarker
+ UpdateCore
+ FixedOutputCore
+ BufferKindUser<BufferKind = Eager>
+ Default
+ Clone,
<<<H as ReverseWrapper>::Variant as CoreProxy>::Core as BlockSizeUser>::BlockSize: IsLess<U256>,
Le<<<<H as ReverseWrapper>::Variant as CoreProxy>::Core as BlockSizeUser>::BlockSize, U256>:
NonZero,
K: KeyPair,
{
let hk = hkdf::Hkdf::<H::Variant, Hmac<H::Variant>>::new(Some(salt), ikm);
let mut okm = vec![0u8; K::PrivKey::LENGTH];
hk.expand(info, &mut okm)
.map_err(|_| FastCryptoError::GeneralOpaqueError)?;
let secret_key = K::PrivKey::from_bytes(&okm[..]).unwrap();
let keypair = K::from(secret_key);
Ok(keypair)
}
const HMAC_KEY_RECOMMENDED_LENGTH: usize = 32;
const HKDF_KEY_RECOMMENDED_LENGTH: usize = 32;
pub type HmacKey = PrivateSeed<HMAC_KEY_RECOMMENDED_LENGTH, false>;
pub fn hmac_sha3_256(key: &HmacKey, message: &[u8]) -> Digest<32> {
let mut hash = Hmac::<sha3::Sha3_256>::new_from_slice(key.as_bytes())
.expect("HMAC can take key of any size");
hash.update(message);
let output = hash.finalize();
Digest {
digest: output.into_bytes().into(),
}
}
pub type HkdfIkm = PrivateSeed<HKDF_KEY_RECOMMENDED_LENGTH, false>;
pub fn hkdf_sha3_256(
ikm: &HkdfIkm,
salt: &[u8],
info: &[u8],
output_length: usize,
) -> Result<Vec<u8>, FastCryptoError> {
if output_length > sha3::Sha3_256::output_size() * 255 {
return Err(FastCryptoError::InputTooLong(
sha3::Sha3_256::output_size() * 255,
));
}
let hk = hkdf::Hkdf::<sha3::Sha3_256, Hmac<sha3::Sha3_256>>::new(Some(salt), ikm.as_bytes());
let mut output: Vec<u8> = vec![0; output_length];
hk.expand(info, output.as_mut_slice())
.map_err(|_| FastCryptoError::GeneralOpaqueError)?;
Ok(output)
}