2023-02-17 13:59:02 +00:00
|
|
|
//! Hash-based Key Derivation Function
|
|
|
|
//! We just repackage other crates
|
|
|
|
|
|
|
|
use ::sha3::Sha3_256;
|
|
|
|
use ::zeroize::Zeroize;
|
|
|
|
|
|
|
|
use crate::enc::sym::Secret;
|
|
|
|
|
2023-05-30 11:47:08 +00:00
|
|
|
/// Kind of HKDF
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, ::num_derive::FromPrimitive)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub enum HkdfKind {
|
|
|
|
/// Sha3
|
|
|
|
Sha3 = 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generic wrapper on Hkdfs
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum Hkdf {
|
|
|
|
/// Sha3 based
|
|
|
|
Sha3(HkdfSha3),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fake debug implementation to avoid leaking secrets
|
|
|
|
impl ::core::fmt::Debug for Hkdf {
|
|
|
|
fn fmt(
|
|
|
|
&self,
|
|
|
|
f: &mut core::fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), ::std::fmt::Error> {
|
|
|
|
::core::fmt::Debug::fmt("[hidden hkdf]", f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Hkdf {
|
|
|
|
/// New Hkdf
|
|
|
|
pub fn new(kind: HkdfKind, salt: &[u8], key: Secret) -> Self {
|
|
|
|
match kind {
|
|
|
|
HkdfKind::Sha3 => Self::Sha3(HkdfSha3::new(salt, key)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Get a secret generated from the key and a given context
|
|
|
|
pub fn get_secret(&self, context: &[u8]) -> Secret {
|
|
|
|
match self {
|
|
|
|
Hkdf::Sha3(sha3) => sha3.get_secret(context),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 13:59:02 +00:00
|
|
|
// Hack & tricks:
|
2023-02-17 22:09:49 +00:00
|
|
|
// 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.
|
2023-02-17 13:59:02 +00:00
|
|
|
|
|
|
|
#[derive(Zeroize)]
|
|
|
|
#[zeroize(drop)]
|
2023-05-30 11:47:08 +00:00
|
|
|
struct Zeroable([u8; ::core::mem::size_of::<::hkdf::Hkdf<Sha3_256>>()]);
|
2023-02-17 13:59:02 +00:00
|
|
|
|
|
|
|
union HkdfInner {
|
2023-05-30 11:47:08 +00:00
|
|
|
hkdf: ::core::mem::ManuallyDrop<::hkdf::Hkdf<Sha3_256>>,
|
2023-02-17 13:59:02 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-22 20:10:00 +00:00
|
|
|
impl Clone for HkdfInner {
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
#[allow(unsafe_code)]
|
|
|
|
unsafe {
|
|
|
|
Self {
|
|
|
|
hkdf: self.hkdf.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-17 13:59:02 +00:00
|
|
|
|
|
|
|
/// Sha3 based HKDF
|
2023-02-22 20:10:00 +00:00
|
|
|
#[derive(Clone)]
|
2023-02-17 13:59:02 +00:00
|
|
|
pub struct HkdfSha3 {
|
2023-02-17 22:09:49 +00:00
|
|
|
inner: HkdfInner,
|
2023-02-17 13:59:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl HkdfSha3 {
|
|
|
|
/// Instantiate a new HKDF with Sha3-256
|
2023-02-17 22:09:49 +00:00
|
|
|
pub fn new(salt: &[u8], key: Secret) -> Self {
|
2023-05-30 11:47:08 +00:00
|
|
|
let hkdf = ::hkdf::Hkdf::<Sha3_256>::new(Some(salt), key.as_ref());
|
2023-05-27 08:57:15 +00:00
|
|
|
Self {
|
|
|
|
inner: HkdfInner {
|
|
|
|
hkdf: ::core::mem::ManuallyDrop::new(hkdf),
|
|
|
|
},
|
2023-02-17 22:09:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/// 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);
|
2023-02-17 13:59:02 +00:00
|
|
|
}
|
2023-02-17 22:09:49 +00:00
|
|
|
out.into()
|
2023-02-17 13:59:02 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-22 20:10:00 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|