Coverage Report

Created: 2025-10-13 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ring-0.17.14/src/hmac.rs
Line
Count
Source
1
// Copyright 2015-2016 Brian Smith.
2
//
3
// Permission to use, copy, modify, and/or distribute this software for any
4
// purpose with or without fee is hereby granted, provided that the above
5
// copyright notice and this permission notice appear in all copies.
6
//
7
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15
//! HMAC is specified in [RFC 2104].
16
//!
17
//! After a `Key` is constructed, it can be used for multiple signing or
18
//! verification operations. Separating the construction of the key from the
19
//! rest of the HMAC operation allows the per-key precomputation to be done
20
//! only once, instead of it being done in every HMAC operation.
21
//!
22
//! Frequently all the data to be signed in a message is available in a single
23
//! contiguous piece. In that case, the module-level `sign` function can be
24
//! used. Otherwise, if the input is in multiple parts, `Context` should be
25
//! used.
26
//!
27
//! # Examples:
28
//!
29
//! ## Signing a value and verifying it wasn't tampered with
30
//!
31
//! ```
32
//! use ring::{hmac, rand};
33
//!
34
//! let rng = rand::SystemRandom::new();
35
//! let key = hmac::Key::generate(hmac::HMAC_SHA256, &rng)?;
36
//!
37
//! let msg = "hello, world";
38
//!
39
//! let tag = hmac::sign(&key, msg.as_bytes());
40
//!
41
//! // [We give access to the message to an untrusted party, and they give it
42
//! // back to us. We need to verify they didn't tamper with it.]
43
//!
44
//! hmac::verify(&key, msg.as_bytes(), tag.as_ref())?;
45
//!
46
//! # Ok::<(), ring::error::Unspecified>(())
47
//! ```
48
//!
49
//! ## Using the one-shot API:
50
//!
51
//! ```
52
//! use ring::{digest, hmac, rand};
53
//! use ring::rand::SecureRandom;
54
//!
55
//! let msg = "hello, world";
56
//!
57
//! // The sender generates a secure key value and signs the message with it.
58
//! // Note that in a real protocol, a key agreement protocol would be used to
59
//! // derive `key_value`.
60
//! let rng = rand::SystemRandom::new();
61
//! let key_value: [u8; digest::SHA256_OUTPUT_LEN] = rand::generate(&rng)?.expose();
62
//!
63
//! let s_key = hmac::Key::new(hmac::HMAC_SHA256, key_value.as_ref());
64
//! let tag = hmac::sign(&s_key, msg.as_bytes());
65
//!
66
//! // The receiver (somehow!) knows the key value, and uses it to verify the
67
//! // integrity of the message.
68
//! let v_key = hmac::Key::new(hmac::HMAC_SHA256, key_value.as_ref());
69
//! hmac::verify(&v_key, msg.as_bytes(), tag.as_ref())?;
70
//!
71
//! # Ok::<(), ring::error::Unspecified>(())
72
//! ```
73
//!
74
//! ## Using the multi-part API:
75
//! ```
76
//! use ring::{digest, hmac, rand};
77
//! use ring::rand::SecureRandom;
78
//!
79
//! let parts = ["hello", ", ", "world"];
80
//!
81
//! // The sender generates a secure key value and signs the message with it.
82
//! // Note that in a real protocol, a key agreement protocol would be used to
83
//! // derive `key_value`.
84
//! let rng = rand::SystemRandom::new();
85
//! let mut key_value: [u8; digest::SHA384_OUTPUT_LEN] = rand::generate(&rng)?.expose();
86
//!
87
//! let s_key = hmac::Key::new(hmac::HMAC_SHA384, key_value.as_ref());
88
//! let mut s_ctx = hmac::Context::with_key(&s_key);
89
//! for part in &parts {
90
//!     s_ctx.update(part.as_bytes());
91
//! }
92
//! let tag = s_ctx.sign();
93
//!
94
//! // The receiver (somehow!) knows the key value, and uses it to verify the
95
//! // integrity of the message.
96
//! let v_key = hmac::Key::new(hmac::HMAC_SHA384, key_value.as_ref());
97
//! let mut msg = Vec::<u8>::new();
98
//! for part in &parts {
99
//!     msg.extend(part.as_bytes());
100
//! }
101
//! hmac::verify(&v_key, &msg.as_ref(), tag.as_ref())?;
102
//!
103
//! # Ok::<(), ring::error::Unspecified>(())
104
//! ```
105
//!
106
//! [RFC 2104]: https://tools.ietf.org/html/rfc2104
107
108
use crate::{
109
    bb, cpu,
110
    digest::{self, Digest, FinishError},
111
    error, hkdf, rand,
112
};
113
114
pub(crate) use crate::digest::InputTooLongError;
115
116
/// An HMAC algorithm.
117
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
118
pub struct Algorithm(&'static digest::Algorithm);
119
120
impl Algorithm {
121
    /// The digest algorithm this HMAC algorithm is based on.
122
    #[inline]
123
0
    pub fn digest_algorithm(&self) -> &'static digest::Algorithm {
124
0
        self.0
125
0
    }
126
}
127
128
/// HMAC using SHA-1. Obsolete.
129
pub static HMAC_SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm(&digest::SHA1_FOR_LEGACY_USE_ONLY);
130
131
/// HMAC using SHA-256.
132
pub static HMAC_SHA256: Algorithm = Algorithm(&digest::SHA256);
133
134
/// HMAC using SHA-384.
135
pub static HMAC_SHA384: Algorithm = Algorithm(&digest::SHA384);
136
137
/// HMAC using SHA-512.
138
pub static HMAC_SHA512: Algorithm = Algorithm(&digest::SHA512);
139
140
/// An HMAC tag.
141
///
142
/// For a given tag `t`, use `t.as_ref()` to get the tag value as a byte slice.
143
#[derive(Clone, Copy, Debug)]
144
pub struct Tag(Digest);
145
146
impl AsRef<[u8]> for Tag {
147
    #[inline]
148
0
    fn as_ref(&self) -> &[u8] {
149
0
        self.0.as_ref()
150
0
    }
151
}
152
153
/// A key to use for HMAC signing.
154
#[derive(Clone)]
155
pub struct Key {
156
    inner: digest::BlockContext,
157
    outer: digest::BlockContext,
158
}
159
160
impl core::fmt::Debug for Key {
161
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
162
0
        f.debug_struct("Key")
163
0
            .field("algorithm", self.algorithm().digest_algorithm())
164
0
            .finish()
165
0
    }
166
}
167
168
impl Key {
169
    /// Generate an HMAC signing key using the given digest algorithm with a
170
    /// random value generated from `rng`.
171
    ///
172
    /// The key will be `digest_alg.output_len` bytes long, based on the
173
    /// recommendation in [RFC 2104 Section 3].
174
    ///
175
    /// [RFC 2104 Section 3]: https://tools.ietf.org/html/rfc2104#section-3
176
0
    pub fn generate(
177
0
        algorithm: Algorithm,
178
0
        rng: &dyn rand::SecureRandom,
179
0
    ) -> Result<Self, error::Unspecified> {
180
0
        Self::construct(algorithm, |buf| rng.fill(buf), cpu::features())
181
0
    }
182
183
0
    fn construct<F>(
184
0
        algorithm: Algorithm,
185
0
        fill: F,
186
0
        cpu: cpu::Features,
187
0
    ) -> Result<Self, error::Unspecified>
188
0
    where
189
0
        F: FnOnce(&mut [u8]) -> Result<(), error::Unspecified>,
190
    {
191
0
        let mut key_bytes = [0; digest::MAX_OUTPUT_LEN];
192
0
        let key_bytes = &mut key_bytes[..algorithm.0.output_len()];
193
0
        fill(key_bytes)?;
194
0
        Self::try_new(algorithm, key_bytes, cpu).map_err(error::erase::<InputTooLongError>)
195
0
    }
Unexecuted instantiation: <ring::hmac::Key>::construct::<<ring::hmac::Key>::generate::{closure#0}>
Unexecuted instantiation: <ring::hmac::Key>::construct::<<ring::hmac::Key as core::convert::From<ring::hkdf::Okm<ring::hmac::Algorithm>>>::from::{closure#0}>
196
197
    /// Construct an HMAC signing key using the given digest algorithm and key
198
    /// value.
199
    ///
200
    /// `key_value` should be a value generated using a secure random number
201
    /// generator (e.g. the `key_value` output by
202
    /// `SealingKey::generate_serializable()`) or derived from a random key by
203
    /// a key derivation function (e.g. `ring::hkdf`). In particular,
204
    /// `key_value` shouldn't be a password.
205
    ///
206
    /// As specified in RFC 2104, if `key_value` is shorter than the digest
207
    /// algorithm's block length (as returned by `digest::Algorithm::block_len()`,
208
    /// not the digest length returned by `digest::Algorithm::output_len()`) then
209
    /// it will be padded with zeros. Similarly, if it is longer than the block
210
    /// length then it will be compressed using the digest algorithm.
211
    ///
212
    /// You should not use keys larger than the `digest_alg.block_len` because
213
    /// the truncation described above reduces their strength to only
214
    /// `digest_alg.output_len * 8` bits. Support for such keys is likely to be
215
    /// removed in a future version of *ring*.
216
0
    pub fn new(algorithm: Algorithm, key_value: &[u8]) -> Self {
217
0
        Self::try_new(algorithm, key_value, cpu::features())
218
0
            .map_err(error::erase::<InputTooLongError>)
219
0
            .unwrap()
220
0
    }
221
222
0
    pub(crate) fn try_new(
223
0
        algorithm: Algorithm,
224
0
        key_value: &[u8],
225
0
        cpu_features: cpu::Features,
226
0
    ) -> Result<Self, InputTooLongError> {
227
0
        let digest_alg = algorithm.0;
228
0
        let mut key = Self {
229
0
            inner: digest::BlockContext::new(digest_alg),
230
0
            outer: digest::BlockContext::new(digest_alg),
231
0
        };
232
233
0
        let block_len = digest_alg.block_len();
234
235
        let key_hash;
236
0
        let key_value = if key_value.len() <= block_len {
237
0
            key_value
238
        } else {
239
0
            key_hash = Digest::compute_from(digest_alg, key_value, cpu_features)?;
240
0
            key_hash.as_ref()
241
        };
242
243
        const IPAD: u8 = 0x36;
244
245
0
        let mut padded_key = [IPAD; digest::MAX_BLOCK_LEN];
246
0
        let padded_key = &mut padded_key[..block_len];
247
248
        // If the key is shorter than one block then we're supposed to act like
249
        // it is padded with zero bytes up to the block length. `x ^ 0 == x` so
250
        // we can just leave the trailing bytes of `padded_key` untouched.
251
0
        bb::xor_assign_at_start(&mut padded_key[..], key_value);
252
253
0
        let leftover = key.inner.update(padded_key, cpu_features);
254
0
        debug_assert_eq!(leftover.len(), 0);
255
256
        const OPAD: u8 = 0x5C;
257
258
        // Remove the `IPAD` masking, leaving the unmasked padded key, then
259
        // mask with `OPAD`, all in one step.
260
0
        bb::xor_assign(&mut padded_key[..], IPAD ^ OPAD);
261
0
        let leftover = key.outer.update(padded_key, cpu_features);
262
0
        debug_assert_eq!(leftover.len(), 0);
263
264
0
        Ok(key)
265
0
    }
266
267
    /// The digest algorithm for the key.
268
    #[inline]
269
0
    pub fn algorithm(&self) -> Algorithm {
270
0
        Algorithm(self.inner.algorithm)
271
0
    }
272
273
0
    pub(crate) fn sign(&self, data: &[u8], cpu: cpu::Features) -> Result<Tag, InputTooLongError> {
274
0
        let mut ctx = Context::with_key(self);
275
0
        ctx.update(data);
276
0
        ctx.try_sign(cpu)
277
0
    }
278
279
0
    fn verify(&self, data: &[u8], tag: &[u8], cpu: cpu::Features) -> Result<(), VerifyError> {
280
0
        let computed = self
281
0
            .sign(data, cpu)
282
0
            .map_err(VerifyError::InputTooLongError)?;
283
0
        bb::verify_slices_are_equal(computed.as_ref(), tag)
284
0
            .map_err(|_: error::Unspecified| VerifyError::Mismatch)
285
0
    }
286
}
287
288
impl hkdf::KeyType for Algorithm {
289
0
    fn len(&self) -> usize {
290
0
        self.digest_algorithm().output_len()
291
0
    }
292
}
293
294
impl From<hkdf::Okm<'_, Algorithm>> for Key {
295
0
    fn from(okm: hkdf::Okm<Algorithm>) -> Self {
296
0
        Self::construct(*okm.len(), |buf| okm.fill(buf), cpu::features()).unwrap()
297
0
    }
298
}
299
300
/// A context for multi-step (Init-Update-Finish) HMAC signing.
301
///
302
/// Use `sign` for single-step HMAC signing.
303
#[derive(Clone)]
304
pub struct Context {
305
    inner: digest::Context,
306
    outer: digest::BlockContext,
307
}
308
309
impl core::fmt::Debug for Context {
310
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
311
0
        f.debug_struct("Context")
312
0
            .field("algorithm", self.inner.algorithm())
313
0
            .finish()
314
0
    }
315
}
316
317
impl Context {
318
    /// Constructs a new HMAC signing context using the given digest algorithm
319
    /// and key.
320
0
    pub fn with_key(signing_key: &Key) -> Self {
321
0
        Self {
322
0
            inner: digest::Context::clone_from(&signing_key.inner),
323
0
            outer: signing_key.outer.clone(),
324
0
        }
325
0
    }
326
327
    /// Updates the HMAC with all the data in `data`. `update` may be called
328
    /// zero or more times until `finish` is called.
329
0
    pub fn update(&mut self, data: &[u8]) {
330
0
        self.inner.update(data);
331
0
    }
332
333
    /// Finalizes the HMAC calculation and returns the HMAC value. `sign`
334
    /// consumes the context so it cannot be (mis-)used after `sign` has been
335
    /// called.
336
    ///
337
    /// It is generally not safe to implement HMAC verification by comparing
338
    /// the return value of `sign` to a tag. Use `verify` for verification
339
    /// instead.
340
0
    pub fn sign(self) -> Tag {
341
0
        self.try_sign(cpu::features())
342
0
            .map_err(error::erase::<InputTooLongError>)
343
0
            .unwrap()
344
0
    }
345
346
0
    pub(crate) fn try_sign(self, cpu_features: cpu::Features) -> Result<Tag, InputTooLongError> {
347
        // Consequently, `num_pending` is valid.
348
0
        debug_assert_eq!(self.inner.algorithm(), self.outer.algorithm);
349
0
        debug_assert!(self.inner.algorithm().output_len() < self.outer.algorithm.block_len());
350
351
0
        let inner = self.inner.try_finish(cpu_features)?;
352
0
        let inner = inner.as_ref();
353
0
        let num_pending = inner.len();
354
0
        let buffer = &mut [0u8; digest::MAX_BLOCK_LEN];
355
        const _BUFFER_IS_LARGE_ENOUGH_TO_HOLD_INNER: () =
356
            assert!(digest::MAX_OUTPUT_LEN < digest::MAX_BLOCK_LEN);
357
0
        buffer[..num_pending].copy_from_slice(inner);
358
359
0
        self.outer
360
0
            .try_finish(buffer, num_pending, cpu_features)
361
0
            .map(Tag)
362
0
            .map_err(|err| match err {
363
0
                FinishError::InputTooLong(i) => {
364
                    // Unreachable, as we gave the inner context exactly the
365
                    // same input we gave the outer context, and
366
                    // `inner.try_finish` already succeeded. However, it is
367
                    // quite difficult to prove this, and we already return
368
                    // `InputTooLongError`, so just forward it along.
369
0
                    i
370
                }
371
                FinishError::PendingNotAPartialBlock(_) => {
372
                    // Follows from the assertions above.
373
0
                    unreachable!()
374
                }
375
0
            })
376
0
    }
377
}
378
379
/// Calculates the HMAC of `data` using the key `key` in one step.
380
///
381
/// Use `Context` to calculate HMACs where the input is in multiple parts.
382
///
383
/// It is generally not safe to implement HMAC verification by comparing the
384
/// return value of `sign` to a tag. Use `verify` for verification instead.
385
0
pub fn sign(key: &Key, data: &[u8]) -> Tag {
386
0
    key.sign(data, cpu::features())
387
0
        .map_err(error::erase::<InputTooLongError>)
388
0
        .unwrap()
389
0
}
390
391
/// Calculates the HMAC of `data` using the signing key `key`, and verifies
392
/// whether the resultant value equals `tag`, in one step.
393
///
394
/// This is logically equivalent to, but more efficient than, constructing a
395
/// `Key` with the same value as `key` and then using `verify`.
396
///
397
/// The verification will be done in constant time to prevent timing attacks.
398
0
pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), error::Unspecified> {
399
0
    key.verify(data, tag, cpu::features())
400
0
        .map_err(|_: VerifyError| error::Unspecified)
401
0
}
402
403
enum VerifyError {
404
    // Theoretically somebody could have calculated a valid tag with a gigantic
405
    // input that we do not support. If we were to support every theoretically
406
    // valid input length, for *every* digest algorithm, then we could argue
407
    // that hitting the input length limit implies a mismatch since nobody
408
    // could have calculated such a tag with the given input.
409
    #[allow(dead_code)]
410
    InputTooLongError(InputTooLongError),
411
412
    Mismatch,
413
}
414
415
#[cfg(test)]
416
mod tests {
417
    use crate::{hmac, rand};
418
419
    // Make sure that `Key::generate` and `verify_with_own_key` aren't
420
    // completely wacky.
421
    #[test]
422
    pub fn hmac_signing_key_coverage() {
423
        let rng = rand::SystemRandom::new();
424
425
        const HELLO_WORLD_GOOD: &[u8] = b"hello, world";
426
        const HELLO_WORLD_BAD: &[u8] = b"hello, worle";
427
428
        for algorithm in &[
429
            hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
430
            hmac::HMAC_SHA256,
431
            hmac::HMAC_SHA384,
432
            hmac::HMAC_SHA512,
433
        ] {
434
            let key = hmac::Key::generate(*algorithm, &rng).unwrap();
435
            let tag = hmac::sign(&key, HELLO_WORLD_GOOD);
436
            assert!(hmac::verify(&key, HELLO_WORLD_GOOD, tag.as_ref()).is_ok());
437
            assert!(hmac::verify(&key, HELLO_WORLD_BAD, tag.as_ref()).is_err())
438
        }
439
    }
440
}