diff options
Diffstat (limited to 'vendor/hmac/src/lib.rs')
-rw-r--r-- | vendor/hmac/src/lib.rs | 131 |
1 files changed, 131 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 +} |