1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
//!Minimal `no_std` hashing library
//!
//!## Provided Algorithms
//!
//!These are also names of features to be used to include algorithm code.
//!
//!- `sha1`
//!- `md5`
//!- `sha256`
//!- `sha512`
//!
//!It also includes generic hmac implementation
#![no_std]
#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
mod fmt;
pub use fmt::DigestFmt;
///Hashing algorithm interface
pub trait Digest {
///Output type
type OutputType: AsRef<[u8]> + AsMut<[u8]> + Copy;
///Block type
type BlockType: AsRef<[u8]> + AsMut<[u8]> + Copy;
///Creates new instance.
fn new() -> Self;
///Resets algorithm's state.
fn reset(&mut self);
///Hashes input
fn update(&mut self, input: &[u8]);
///Finalizes algorithm and returns output.
fn result(&mut self) -> Self::OutputType;
}
///Represents key used to sign content in `hmac` algorithm.
///
///Comparing to `hmac` function it allows to pre-compute key and just sign input directly.
///
///`Digest` is only used in methods, making user to be responsible for using correct algorithm.
pub struct HmacKey<D: Digest> {
key: D::BlockType,
}
impl<D: Digest> HmacKey<D> {
///Creates new hmac key, using provided secret.
///
///If `secret` size is above that of `Digest::BlockType` then it is hashed,
///reducing potential quality of hmac properties.
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,
}
}
///Signs provided `input` with the key.
pub fn sign(&self, input: &[u8]) -> D::OutputType {
let mut key = self.key;
let key = key.as_mut();
//inner
let mut algo = D::new();
algo.update(key);
algo.update(input);
let inner_result = algo.result();
algo.reset();
//outer
for byte in key.iter_mut() {
*byte ^= 0x36 ^ 0x5C;
}
algo.update(key);
algo.update(inner_result.as_ref());
algo.result()
}
}
///Creates HMAC using provided `Digest` algorithm.
///
///- `input` - Data to hash.
///- `secret` - Data to derive HMAC's key.
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};