Coverage Report

Created: 2025-02-22 06:51

/rust/registry/src/index.crates.io-6f17d22bba15001f/hmac-0.13.0-pre.4/src/lib.rs
Line
Count
Source (jump to first uncovered line)
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")]
94
extern crate std;
95
96
pub use digest;
97
pub use digest::{KeyInit, Mac};
98
99
use digest::{
100
    core_api::{Block, BlockSizeUser},
101
    Digest,
102
};
103
104
mod optim;
105
mod simple;
106
107
pub use optim::{EagerHash, Hmac, HmacCore};
108
pub use simple::SimpleHmac;
109
110
const IPAD: u8 = 0x36;
111
const OPAD: u8 = 0x5C;
112
113
3.17k
fn get_der_key<D: Digest + BlockSizeUser>(key: &[u8]) -> Block<D> {
114
3.17k
    let mut der_key = Block::<D>::default();
115
3.17k
    // The key that HMAC processes must be the same as the block size of the
116
3.17k
    // underlying hash function. If the provided key is smaller than that,
117
3.17k
    // we just pad it with zeros. If its larger, we hash it and then pad it
118
3.17k
    // with zeros.
119
3.17k
    if key.len() <= der_key.len() {
120
3.17k
        der_key[..key.len()].copy_from_slice(key);
121
3.17k
    } else {
122
0
        let hash = D::digest(key);
123
0
        // All commonly used hash functions have block size bigger
124
0
        // than output hash size, but to be extra rigorous we
125
0
        // handle the potential uncommon cases as well.
126
0
        // The condition is calculated at compile time, so this
127
0
        // branch gets removed from the final binary.
128
0
        if hash.len() <= der_key.len() {
129
0
            der_key[..hash.len()].copy_from_slice(&hash);
130
0
        } else {
131
0
            let n = der_key.len();
132
0
            der_key.copy_from_slice(&hash[..n]);
133
0
        }
134
    }
135
3.17k
    der_key
136
3.17k
}