#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
mod fmt;
pub use fmt::DigestFmt;
pub trait Digest {
type OutputType: AsRef<[u8]> + AsMut<[u8]> + Copy;
type BlockType: AsRef<[u8]> + AsMut<[u8]> + Copy;
fn new() -> Self;
fn reset(&mut self);
fn update(&mut self, input: &[u8]);
fn result(&mut self) -> Self::OutputType;
}
pub struct HmacKey<D: Digest> {
key: D::BlockType,
}
impl<D: Digest> HmacKey<D> {
pub fn new(secret: &[u8]) -> Self {
let mut inner: D::BlockType = unsafe {
core::mem::MaybeUninit::zeroed().assume_init()
};
let key = inner.as_mut();
if secret.len() <= key.len() {
key[..secret.len()].copy_from_slice(secret);
} else {
let mut algo = D::new();
algo.update(secret);
let hash = algo.result();
let hash = hash.as_ref();
key[..hash.len()].copy_from_slice(hash);
algo.reset();
}
for byte in key.iter_mut() {
*byte ^= 0x36;
}
Self {
key: inner,
}
}
pub fn sign(&self, input: &[u8]) -> D::OutputType {
let mut key = self.key;
let key = key.as_mut();
let mut algo = D::new();
algo.update(key);
algo.update(input);
let inner_result = algo.result();
algo.reset();
for byte in key.iter_mut() {
*byte ^= 0x36 ^ 0x5C;
}
algo.update(key);
algo.update(inner_result.as_ref());
algo.result()
}
}
pub fn hmac<D: Digest>(input: &[u8], secret: &[u8]) -> D::OutputType {
let key = HmacKey::<D>::new(secret);
key.sign(input)
}
#[cfg(feature = "sha1")]
mod sha1;
#[cfg(feature = "sha1")]
pub use sha1::{sha1, Sha1};
#[cfg(feature = "md5")]
mod md5;
#[cfg(feature = "md5")]
pub use md5::{md5, Md5};
#[cfg(feature = "sha256")]
mod sha256;
#[cfg(feature = "sha256")]
pub use sha256::{sha256, Sha256};
#[cfg(feature = "sha512")]
mod sha512;
#[cfg(feature = "sha512")]
pub use sha512::{sha512, Sha512};