diff options
Diffstat (limited to 'vendor/hmac/src')
-rw-r--r-- | vendor/hmac/src/lib.rs | 131 | ||||
-rw-r--r-- | vendor/hmac/src/optim.rs | 280 | ||||
-rw-r--r-- | vendor/hmac/src/simple.rs | 106 |
3 files changed, 517 insertions, 0 deletions
diff --git a/vendor/hmac/src/lib.rs b/vendor/hmac/src/lib.rs new file mode 100644 index 0000000..e79c068 --- /dev/null +++ b/vendor/hmac/src/lib.rs @@ -0,0 +1,131 @@ +//! Generic implementation of Hash-based Message Authentication Code (HMAC). +//! +//! To use it you will need a cryptographic hash function implementation which +//! implements the [`digest`] crate traits. You can find compatible crates +//! (e.g. [`sha2`]) in the [`RustCrypto/hashes`] repository. +//! +//! This crate provides two HMAC implementation [`Hmac`] and [`SimpleHmac`]. +//! The first one is a buffered wrapper around block-level [`HmacCore`]. +//! Internally it uses efficient state representation, but works only with +//! hash functions which expose block-level API and consume blocks eagerly +//! (e.g. it will not work with the BLAKE2 family of hash functions). +//! On the other hand, [`SimpleHmac`] is a bit less efficient memory-wise, +//! but works with all hash functions which implement the [`Digest`] trait. +//! +//! # Examples +//! Let us demonstrate how to use HMAC using the SHA-256 hash function. +//! +//! In the following examples [`Hmac`] is interchangeable with [`SimpleHmac`]. +//! +//! To get authentication code: +//! +//! ```rust +//! use sha2::Sha256; +//! use hmac::{Hmac, Mac}; +//! use hex_literal::hex; +//! +//! // Create alias for HMAC-SHA256 +//! type HmacSha256 = Hmac<Sha256>; +//! +//! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key") +//! .expect("HMAC can take key of any size"); +//! mac.update(b"input message"); +//! +//! // `result` has type `CtOutput` which is a thin wrapper around array of +//! // bytes for providing constant time equality check +//! let result = mac.finalize(); +//! // To get underlying array use `into_bytes`, but be careful, since +//! // incorrect use of the code value may permit timing attacks which defeats +//! // the security provided by the `CtOutput` +//! let code_bytes = result.into_bytes(); +//! let expected = hex!(" +//! 97d2a569059bbcd8ead4444ff99071f4 +//! c01d005bcefe0d3567e1be628e5fdcd9 +//! "); +//! assert_eq!(code_bytes[..], expected[..]); +//! ``` +//! +//! To verify the message: +//! +//! ```rust +//! # use sha2::Sha256; +//! # use hmac::{Hmac, Mac}; +//! # use hex_literal::hex; +//! # type HmacSha256 = Hmac<Sha256>; +//! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key") +//! .expect("HMAC can take key of any size"); +//! +//! mac.update(b"input message"); +//! +//! let code_bytes = hex!(" +//! 97d2a569059bbcd8ead4444ff99071f4 +//! c01d005bcefe0d3567e1be628e5fdcd9 +//! "); +//! // `verify_slice` will return `Ok(())` if code is correct, `Err(MacError)` otherwise +//! mac.verify_slice(&code_bytes[..]).unwrap(); +//! ``` +//! +//! # Block and input sizes +//! Usually it is assumed that block size is larger than output size. Due to the +//! generic nature of the implementation, this edge case must be handled as well +//! to remove potential panic. This is done by truncating hash output to the hash +//! block size if needed. +//! +//! [`digest`]: https://docs.rs/digest +//! [`sha2`]: https://docs.rs/sha2 +//! [`RustCrypto/hashes`]: https://github.com/RustCrypto/hashes + +#![no_std] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_root_url = "https://docs.rs/hmac/0.12.1" +)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "std")] +extern crate std; + +pub use digest; +pub use digest::Mac; + +use digest::{ + core_api::{Block, BlockSizeUser}, + Digest, +}; + +mod optim; +mod simple; + +pub use optim::{Hmac, HmacCore}; +pub use simple::SimpleHmac; + +const IPAD: u8 = 0x36; +const OPAD: u8 = 0x5C; + +fn get_der_key<D: Digest + BlockSizeUser>(key: &[u8]) -> Block<D> { + let mut der_key = Block::<D>::default(); + // The key that HMAC processes must be the same as the block size of the + // underlying hash function. If the provided key is smaller than that, + // we just pad it with zeros. If its larger, we hash it and then pad it + // with zeros. + if key.len() <= der_key.len() { + der_key[..key.len()].copy_from_slice(key); + } else { + let hash = D::digest(key); + // All commonly used hash functions have block size bigger + // than output hash size, but to be extra rigorous we + // handle the potential uncommon cases as well. + // The condition is calcualted at compile time, so this + // branch gets removed from the final binary. + if hash.len() <= der_key.len() { + der_key[..hash.len()].copy_from_slice(&hash); + } else { + let n = der_key.len(); + der_key.copy_from_slice(&hash[..n]); + } + } + der_key +} diff --git a/vendor/hmac/src/optim.rs b/vendor/hmac/src/optim.rs new file mode 100644 index 0000000..32d6277 --- /dev/null +++ b/vendor/hmac/src/optim.rs @@ -0,0 +1,280 @@ +use super::{get_der_key, IPAD, OPAD}; +use core::{fmt, slice}; +#[cfg(feature = "reset")] +use digest::Reset; +use digest::{ + block_buffer::Eager, + core_api::{ + AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreProxy, CoreWrapper, + FixedOutputCore, OutputSizeUser, UpdateCore, + }, + crypto_common::{Key, KeySizeUser}, + generic_array::typenum::{IsLess, Le, NonZero, U256}, + HashMarker, InvalidLength, KeyInit, MacMarker, Output, +}; + +/// Generic HMAC instance. +pub type Hmac<D> = CoreWrapper<HmacCore<D>>; + +/// Generic core HMAC instance, which operates over blocks. +pub struct HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + digest: D::Core, + opad_digest: D::Core, + #[cfg(feature = "reset")] + ipad_digest: D::Core, +} + +impl<D> Clone for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + fn clone(&self) -> Self { + Self { + digest: self.digest.clone(), + opad_digest: self.opad_digest.clone(), + #[cfg(feature = "reset")] + ipad_digest: self.ipad_digest.clone(), + } + } +} + +impl<D> MacMarker for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ +} + +impl<D> BufferKindUser for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + type BufferKind = Eager; +} + +impl<D> KeySizeUser for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + type KeySize = <<D as CoreProxy>::Core as BlockSizeUser>::BlockSize; +} + +impl<D> BlockSizeUser for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + type BlockSize = <<D as CoreProxy>::Core as BlockSizeUser>::BlockSize; +} + +impl<D> OutputSizeUser for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + type OutputSize = <<D as CoreProxy>::Core as OutputSizeUser>::OutputSize; +} + +impl<D> KeyInit for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + #[inline(always)] + fn new(key: &Key<Self>) -> Self { + Self::new_from_slice(key.as_slice()).unwrap() + } + + #[inline(always)] + fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> { + let mut buf = get_der_key::<CoreWrapper<D::Core>>(key); + for b in buf.iter_mut() { + *b ^= IPAD; + } + let mut digest = D::Core::default(); + digest.update_blocks(slice::from_ref(&buf)); + + for b in buf.iter_mut() { + *b ^= IPAD ^ OPAD; + } + + let mut opad_digest = D::Core::default(); + opad_digest.update_blocks(slice::from_ref(&buf)); + + Ok(Self { + #[cfg(feature = "reset")] + ipad_digest: digest.clone(), + opad_digest, + digest, + }) + } +} + +impl<D> UpdateCore for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + #[inline(always)] + fn update_blocks(&mut self, blocks: &[Block<Self>]) { + self.digest.update_blocks(blocks); + } +} + +impl<D> FixedOutputCore for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + #[inline(always)] + fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) { + let mut hash = Output::<D::Core>::default(); + self.digest.finalize_fixed_core(buffer, &mut hash); + // finalize_fixed_core should reset the buffer as well, but + // to be extra safe we reset it explicitly again. + buffer.reset(); + #[cfg(not(feature = "reset"))] + let h = &mut self.opad_digest; + #[cfg(feature = "reset")] + let mut h = self.opad_digest.clone(); + buffer.digest_blocks(&hash, |b| h.update_blocks(b)); + h.finalize_fixed_core(buffer, out); + } +} + +#[cfg(feature = "reset")] +#[cfg_attr(docsrs, doc(cfg(feature = "reset")))] +impl<D> Reset for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + #[inline(always)] + fn reset(&mut self) { + self.digest = self.ipad_digest.clone(); + } +} + +impl<D> AlgorithmName for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + AlgorithmName + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Hmac<")?; + <D::Core as AlgorithmName>::write_alg_name(f)?; + f.write_str(">") + } +} + +impl<D> fmt::Debug for HmacCore<D> +where + D: CoreProxy, + D::Core: HashMarker + + AlgorithmName + + UpdateCore + + FixedOutputCore + + BufferKindUser<BufferKind = Eager> + + Default + + Clone, + <D::Core as BlockSizeUser>::BlockSize: IsLess<U256>, + Le<<D::Core as BlockSizeUser>::BlockSize, U256>: NonZero, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("HmacCore<")?; + <D::Core as AlgorithmName>::write_alg_name(f)?; + f.write_str("> { ... }") + } +} diff --git a/vendor/hmac/src/simple.rs b/vendor/hmac/src/simple.rs new file mode 100644 index 0000000..e28c4c3 --- /dev/null +++ b/vendor/hmac/src/simple.rs @@ -0,0 +1,106 @@ +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); + } +} |