[go: up one dir, main page]

hmac/
lib.rs

1//! Generic implementation of Hash-based Message Authentication Code (HMAC).
2//!
3//! To use it you will need a cryptographic hash function implementation which
4//! implements the [`digest`] crate traits. You can find compatible crates
5//! (e.g. [`sha2`]) in the [`RustCrypto/hashes`] repository.
6//!
7//! This crate provides two HMAC implementation [`Hmac`] and [`SimpleHmac`].
8//! The first one is a buffered wrapper around block-level [`HmacCore`].
9//! Internally it uses efficient state representation, but works only with
10//! hash functions which expose block-level API and consume blocks eagerly
11//! (e.g. it will not work with the BLAKE2 family of  hash functions).
12//! On the other hand, [`SimpleHmac`] is a bit less efficient memory-wise,
13//! but works with all hash functions which implement the [`Digest`] trait.
14//!
15//! # Examples
16//! Let us demonstrate how to use HMAC using the SHA-256 hash function.
17//!
18//! In the following examples [`Hmac`] is interchangeable with [`SimpleHmac`].
19//!
20//! To get authentication code:
21//!
22//! ```rust
23//! use sha2::Sha256;
24//! use hmac::{Hmac, KeyInit, Mac};
25//! use hex_literal::hex;
26//!
27//! // Create alias for HMAC-SHA256
28//! type HmacSha256 = Hmac<Sha256>;
29//!
30//! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key")
31//!     .expect("HMAC can take key of any size");
32//! mac.update(b"input message");
33//!
34//! // `result` has type `CtOutput` which is a thin wrapper around array of
35//! // bytes for providing constant time equality check
36//! let result = mac.finalize();
37//! // To get underlying array use `into_bytes`, but be careful, since
38//! // incorrect use of the code value may permit timing attacks which defeats
39//! // the security provided by the `CtOutput`
40//! let code_bytes = result.into_bytes();
41//! let expected = hex!("
42//!     97d2a569059bbcd8ead4444ff99071f4
43//!     c01d005bcefe0d3567e1be628e5fdcd9
44//! ");
45//! assert_eq!(code_bytes[..], expected[..]);
46//! ```
47//!
48//! To verify the message:
49//!
50//! ```rust
51//! # use sha2::Sha256;
52//! # use hmac::{Hmac, KeyInit, Mac};
53//! # use hex_literal::hex;
54//! # type HmacSha256 = Hmac<Sha256>;
55//! let mut mac = HmacSha256::new_from_slice(b"my secret and secure key")
56//!     .expect("HMAC can take key of any size");
57//!
58//! mac.update(b"input message");
59//!
60//! let code_bytes = hex!("
61//!     97d2a569059bbcd8ead4444ff99071f4
62//!     c01d005bcefe0d3567e1be628e5fdcd9
63//! ");
64//! // `verify_slice` will return `Ok(())` if code is correct, `Err(MacError)` otherwise
65//! mac.verify_slice(&code_bytes[..]).unwrap();
66//! ```
67//!
68//! # Block and input sizes
69//! Usually it is assumed that block size is larger than output size. Due to the
70//! generic nature of the implementation, this edge case must be handled as well
71//! to remove potential panic. This is done by truncating hash output to the hash
72//! block size if needed.
73//!
74//! # Crate features
75//! - `std`: enables functionality dependent on `std` (e.g. implementation of
76//!   the [`Error`][std::error::Error] trait for error types)
77//! - `reset`: enables implementation of the [`Reset`][digest::Reset] trait
78//!   (note that it makes HMAC states bigger)
79//!
80//! [`digest`]: https://docs.rs/digest
81//! [`sha2`]: https://docs.rs/sha2
82//! [`RustCrypto/hashes`]: https://github.com/RustCrypto/hashes
83
84#![no_std]
85#![doc(
86    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
87    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
88)]
89#![forbid(unsafe_code)]
90#![cfg_attr(docsrs, feature(doc_cfg))]
91#![warn(missing_docs, rust_2018_idioms)]
92
93#[cfg(feature = "std")]
94extern crate std;
95
96pub use digest::{self, KeyInit, Mac};
97
98use digest::{
99    Digest,
100    core_api::{Block, BlockSizeUser},
101};
102
103mod optim;
104mod simple;
105
106pub use optim::{EagerHash, Hmac, HmacCore};
107pub use simple::SimpleHmac;
108
109const IPAD: u8 = 0x36;
110const OPAD: u8 = 0x5C;
111
112fn get_der_key<D: Digest + BlockSizeUser>(key: &[u8]) -> Block<D> {
113    let mut der_key = Block::<D>::default();
114    // The key that HMAC processes must be the same as the block size of the
115    // underlying hash function. If the provided key is smaller than that,
116    // we just pad it with zeros. If its larger, we hash it and then pad it
117    // with zeros.
118    if key.len() <= der_key.len() {
119        der_key[..key.len()].copy_from_slice(key);
120    } else {
121        let hash = D::digest(key);
122        // All commonly used hash functions have block size bigger
123        // than output hash size, but to be extra rigorous we
124        // handle the potential uncommon cases as well.
125        // The condition is calculated at compile time, so this
126        // branch gets removed from the final binary.
127        if hash.len() <= der_key.len() {
128            der_key[..hash.len()].copy_from_slice(&hash);
129        } else {
130            let n = der_key.len();
131            der_key.copy_from_slice(&hash[..n]);
132        }
133    }
134    der_key
135}