hmac/lib.rs
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 127 128 129 130 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
}