107 lines
3.1 KiB
Rust
107 lines
3.1 KiB
Rust
use super::{get_der_key, IPAD, OPAD};
|
|
use core::fmt;
|
|
use digest::{
|
|
crypto_common::{Block, BlockSizeUser, InvalidLength, Key, KeySizeUser},
|
|
Digest, FixedOutput, KeyInit, MacMarker, Output, OutputSizeUser, Update,
|
|
};
|
|
#[cfg(feature = "reset")]
|
|
use digest::{FixedOutputReset, Reset};
|
|
|
|
/// Simplified HMAC instance able to operate over hash functions
|
|
/// which do not expose block-level API and hash functions which
|
|
/// process blocks lazily (e.g. BLAKE2).
|
|
#[derive(Clone)]
|
|
pub struct SimpleHmac<D: Digest + BlockSizeUser> {
|
|
digest: D,
|
|
opad_key: Block<D>,
|
|
#[cfg(feature = "reset")]
|
|
ipad_key: Block<D>,
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser> KeySizeUser for SimpleHmac<D> {
|
|
type KeySize = D::BlockSize;
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser> MacMarker for SimpleHmac<D> {}
|
|
|
|
impl<D: Digest + BlockSizeUser> KeyInit for SimpleHmac<D> {
|
|
fn new(key: &Key<Self>) -> Self {
|
|
Self::new_from_slice(key.as_slice()).unwrap()
|
|
}
|
|
|
|
#[inline]
|
|
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
|
|
let der_key = get_der_key::<D>(key);
|
|
let mut ipad_key = der_key.clone();
|
|
for b in ipad_key.iter_mut() {
|
|
*b ^= IPAD;
|
|
}
|
|
let mut digest = D::new();
|
|
digest.update(&ipad_key);
|
|
|
|
let mut opad_key = der_key;
|
|
for b in opad_key.iter_mut() {
|
|
*b ^= OPAD;
|
|
}
|
|
|
|
Ok(Self {
|
|
digest,
|
|
opad_key,
|
|
#[cfg(feature = "reset")]
|
|
ipad_key,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser> Update for SimpleHmac<D> {
|
|
#[inline(always)]
|
|
fn update(&mut self, data: &[u8]) {
|
|
self.digest.update(data);
|
|
}
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser> OutputSizeUser for SimpleHmac<D> {
|
|
type OutputSize = D::OutputSize;
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser> FixedOutput for SimpleHmac<D> {
|
|
fn finalize_into(self, out: &mut Output<Self>) {
|
|
let mut h = D::new();
|
|
h.update(&self.opad_key);
|
|
h.update(&self.digest.finalize());
|
|
h.finalize_into(out);
|
|
}
|
|
}
|
|
|
|
impl<D: Digest + BlockSizeUser + fmt::Debug> fmt::Debug for SimpleHmac<D> {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("SimpleHmac")
|
|
.field("digest", &self.digest)
|
|
// TODO: replace with `finish_non_exhaustive` on MSRV
|
|
// bump to 1.53
|
|
.field("..", &"..")
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "reset")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "reset")))]
|
|
impl<D: Digest + BlockSizeUser + Reset> Reset for SimpleHmac<D> {
|
|
fn reset(&mut self) {
|
|
Reset::reset(&mut self.digest);
|
|
self.digest.update(&self.ipad_key);
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "reset")]
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "reset")))]
|
|
impl<D: Digest + BlockSizeUser + FixedOutputReset> FixedOutputReset for SimpleHmac<D> {
|
|
fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
|
|
let mut h = D::new();
|
|
Update::update(&mut h, &self.opad_key);
|
|
Update::update(&mut h, &self.digest.finalize_reset());
|
|
Update::update(&mut self.digest, &self.ipad_key);
|
|
Digest::finalize_into(h, out);
|
|
}
|
|
}
|