libFenrir/src/enc/hkdf.rs

83 lines
2.0 KiB
Rust

//! 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::<Hkdf<Sha3_256>>()]);
union HkdfInner {
hkdf: ::core::mem::ManuallyDrop<Hkdf<Sha3_256>>,
zeroable: ::core::mem::ManuallyDrop<Zeroable>,
}
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::<Sha3_256>::new(Some(salt), key.as_ref());
#[allow(unsafe_code)]
unsafe {
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)
}
}