//! Hash-based Key Derivation Function //! We just repackage other crates use ::hkdf::Hkdf; use ::sha3::Sha3_256; use ::zeroize::Zeroize; use crate::enc::sym::Secret; // Hack & tricks: // HKDF are pretty important, but this lib don't zero out the data. // we can't use #[derive(Zeroing)] either. // So we craete a union with a Zeroing object, and drop both manually. #[derive(Zeroize)] #[zeroize(drop)] struct Zeroable([u8; ::core::mem::size_of::>()]); union HkdfInner { hkdf: ::core::mem::ManuallyDrop>, zeroable: ::core::mem::ManuallyDrop, } impl Drop for HkdfInner { fn drop(&mut self) { #[allow(unsafe_code)] unsafe { drop(&mut self.hkdf); drop(&mut self.zeroable); } } } impl Clone for HkdfInner { fn clone(&self) -> Self { #[allow(unsafe_code)] unsafe { Self { hkdf: self.hkdf.clone(), } } } } /// Sha3 based HKDF #[derive(Clone)] pub struct HkdfSha3 { inner: HkdfInner, } impl HkdfSha3 { /// Instantiate a new HKDF with Sha3-256 pub fn new(salt: &[u8], key: Secret) -> Self { let hkdf = Hkdf::::new(Some(salt), key.as_ref()); Self { inner: HkdfInner { hkdf: ::core::mem::ManuallyDrop::new(hkdf), }, } } /// Get a secret generated from the key and a given context pub fn get_secret(&self, context: &[u8]) -> Secret { let mut out: [u8; 32] = [0; 32]; #[allow(unsafe_code)] unsafe { self.inner.hkdf.expand(context, &mut out); } out.into() } } // Fake debug implementation to avoid leaking secrets impl ::core::fmt::Debug for HkdfSha3 { fn fmt( &self, f: &mut core::fmt::Formatter<'_>, ) -> Result<(), ::std::fmt::Error> { ::core::fmt::Debug::fmt("[hidden hkdf]", f) } }