Coverage Report

Created: 2026-02-14 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.15.4/src/hmac.rs
Line
Count
Source
1
// Copyright 2015-2022 Brian Smith.
2
// SPDX-License-Identifier: ISC
3
// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6
//! HMAC is specified in [RFC 2104].
7
//!
8
//! After a `Key` is constructed, it can be used for multiple signing or
9
//! verification operations. Separating the construction of the key from the
10
//! rest of the HMAC operation allows the per-key precomputation to be done
11
//! only once, instead of it being done in every HMAC operation.
12
//!
13
//! Frequently all the data to be signed in a message is available in a single
14
//! contiguous piece. In that case, the module-level `sign` function can be
15
//! used. Otherwise, if the input is in multiple parts, `Context` should be
16
//! used.
17
//!
18
//! # Examples:
19
//!
20
//! ## Signing a value and verifying it wasn't tampered with
21
//!
22
//! ```
23
//! use aws_lc_rs::{hmac, rand};
24
//!
25
//! let rng = rand::SystemRandom::new();
26
//! let key = hmac::Key::generate(hmac::HMAC_SHA256, &rng)?;
27
//!
28
//! let msg = "hello, world";
29
//!
30
//! let tag = hmac::sign(&key, msg.as_bytes());
31
//!
32
//! // [We give access to the message to an untrusted party, and they give it
33
//! // back to us. We need to verify they didn't tamper with it.]
34
//!
35
//! hmac::verify(&key, msg.as_bytes(), tag.as_ref())?;
36
//!
37
//! # Ok::<(), aws_lc_rs::error::Unspecified>(())
38
//! ```
39
//!
40
//! ## Using the one-shot API:
41
//!
42
//! ```
43
//! use aws_lc_rs::rand::SecureRandom;
44
//! use aws_lc_rs::{digest, hmac, rand};
45
//!
46
//! let msg = "hello, world";
47
//!
48
//! // The sender generates a secure key value and signs the message with it.
49
//! // Note that in a real protocol, a key agreement protocol would be used to
50
//! // derive `key_value`.
51
//! let rng = rand::SystemRandom::new();
52
//! let key_value: [u8; digest::SHA256_OUTPUT_LEN] = rand::generate(&rng)?.expose();
53
//!
54
//! let s_key = hmac::Key::new(hmac::HMAC_SHA256, key_value.as_ref());
55
//! let tag = hmac::sign(&s_key, msg.as_bytes());
56
//!
57
//! // The receiver (somehow!) knows the key value, and uses it to verify the
58
//! // integrity of the message.
59
//! let v_key = hmac::Key::new(hmac::HMAC_SHA256, key_value.as_ref());
60
//! hmac::verify(&v_key, msg.as_bytes(), tag.as_ref())?;
61
//!
62
//! # Ok::<(), aws_lc_rs::error::Unspecified>(())
63
//! ```
64
//!
65
//! ## Using the multi-part API:
66
//! ```
67
//! use aws_lc_rs::rand::SecureRandom;
68
//! use aws_lc_rs::{digest, hmac, rand};
69
//!
70
//! let parts = ["hello", ", ", "world"];
71
//!
72
//! // The sender generates a secure key value and signs the message with it.
73
//! // Note that in a real protocol, a key agreement protocol would be used to
74
//! // derive `key_value`.
75
//! let rng = rand::SystemRandom::new();
76
//! let mut key_value: [u8; digest::SHA384_OUTPUT_LEN] = rand::generate(&rng)?.expose();
77
//!
78
//! let s_key = hmac::Key::new(hmac::HMAC_SHA384, key_value.as_ref());
79
//! let mut s_ctx = hmac::Context::with_key(&s_key);
80
//! for part in &parts {
81
//!     s_ctx.update(part.as_bytes());
82
//! }
83
//! let tag = s_ctx.sign();
84
//!
85
//! // The receiver (somehow!) knows the key value, and uses it to verify the
86
//! // integrity of the message.
87
//! let v_key = hmac::Key::new(hmac::HMAC_SHA384, key_value.as_ref());
88
//! let mut msg = Vec::<u8>::new();
89
//! for part in &parts {
90
//!     msg.extend(part.as_bytes());
91
//! }
92
//! hmac::verify(&v_key, &msg.as_ref(), tag.as_ref())?;
93
//!
94
//! # Ok::<(), aws_lc_rs::error::Unspecified>(())
95
//! ```
96
//! [RFC 2104]: https://tools.ietf.org/html/rfc2104
97
98
use crate::aws_lc::{
99
    HMAC_CTX_cleanup, HMAC_CTX_copy_ex, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex, HMAC_Update,
100
    HMAC_CTX,
101
};
102
use crate::error::Unspecified;
103
use crate::fips::indicator_check;
104
use crate::{constant_time, digest, hkdf};
105
use core::ffi::c_uint;
106
use core::mem::MaybeUninit;
107
use core::ptr::null_mut;
108
109
/// A deprecated alias for `Tag`.
110
#[deprecated]
111
pub type Signature = Tag;
112
/// Renamed to `Context`.
113
#[deprecated]
114
pub type SigningContext = Context;
115
/// Renamed to `Key`.
116
#[deprecated]
117
pub type SigningKey = Key;
118
/// Merged into `Key`.
119
#[deprecated]
120
pub type VerificationKey = Key;
121
122
/// An HMAC algorithm.
123
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
124
pub struct Algorithm(&'static digest::Algorithm);
125
126
impl Algorithm {
127
    /// The digest algorithm this HMAC algorithm is based on.
128
    #[inline]
129
    #[must_use]
130
0
    pub fn digest_algorithm(&self) -> &'static digest::Algorithm {
131
0
        self.0
132
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Algorithm>::digest_algorithm
Unexecuted instantiation: <aws_lc_rs::hmac::Algorithm>::digest_algorithm
133
}
134
135
/// HMAC using SHA-1. Obsolete.
136
pub const HMAC_SHA1_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm(&digest::SHA1_FOR_LEGACY_USE_ONLY);
137
138
/// HMAC using SHA-224.
139
pub const HMAC_SHA224: Algorithm = Algorithm(&digest::SHA224);
140
141
/// HMAC using SHA-256.
142
pub const HMAC_SHA256: Algorithm = Algorithm(&digest::SHA256);
143
144
/// HMAC using SHA-384.
145
pub const HMAC_SHA384: Algorithm = Algorithm(&digest::SHA384);
146
147
/// HMAC using SHA-512.
148
pub const HMAC_SHA512: Algorithm = Algorithm(&digest::SHA512);
149
150
/// An HMAC tag.
151
///
152
/// For a given tag `t`, use `t.as_ref()` to get the tag value as a byte slice.
153
#[derive(Clone, Copy, Debug)]
154
pub struct Tag {
155
    msg: [u8; digest::MAX_OUTPUT_LEN],
156
    msg_len: usize,
157
}
158
159
impl AsRef<[u8]> for Tag {
160
    #[inline]
161
0
    fn as_ref(&self) -> &[u8] {
162
0
        &self.msg[..self.msg_len]
163
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Tag as core::convert::AsRef<[u8]>>::as_ref
Unexecuted instantiation: <aws_lc_rs::hmac::Tag as core::convert::AsRef<[u8]>>::as_ref
164
}
165
166
struct LcHmacCtx(HMAC_CTX);
167
168
impl LcHmacCtx {
169
0
    fn as_mut_ptr(&mut self) -> *mut HMAC_CTX {
170
0
        &mut self.0
171
0
    }
172
0
    fn as_ptr(&self) -> *const HMAC_CTX {
173
0
        &self.0
174
0
    }
175
176
0
    fn try_clone(&self) -> Result<Self, Unspecified> {
177
        unsafe {
178
0
            let mut hmac_ctx = MaybeUninit::<HMAC_CTX>::uninit();
179
0
            HMAC_CTX_init(hmac_ctx.as_mut_ptr());
180
0
            let mut hmac_ctx = hmac_ctx.assume_init();
181
0
            if 1 != HMAC_CTX_copy_ex(&mut hmac_ctx, self.as_ptr()) {
182
0
                return Err(Unspecified);
183
0
            }
184
0
            Ok(LcHmacCtx(hmac_ctx))
185
        }
186
0
    }
187
}
188
unsafe impl Send for LcHmacCtx {}
189
190
impl Drop for LcHmacCtx {
191
0
    fn drop(&mut self) {
192
0
        unsafe { HMAC_CTX_cleanup(self.as_mut_ptr()) }
193
0
    }
194
}
195
196
impl Clone for LcHmacCtx {
197
0
    fn clone(&self) -> Self {
198
0
        self.try_clone().expect("Unable to clone LcHmacCtx")
199
0
    }
200
}
201
202
/// A key to use for HMAC signing.
203
//
204
// # FIPS
205
// Use this type with one of the following algorithms:
206
// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY`
207
// * `HMAC_SHA224`
208
// * `HMAC_SHA256`
209
// * `HMAC_SHA384`
210
// * `HMAC_SHA512`
211
#[derive(Clone)]
212
pub struct Key {
213
    pub(crate) algorithm: Algorithm,
214
    ctx: LcHmacCtx,
215
}
216
217
unsafe impl Send for Key {}
218
// All uses of *mut HMAC_CTX require the creation of a Context, which will clone the Key.
219
unsafe impl Sync for Key {}
220
221
#[allow(clippy::missing_fields_in_debug)]
222
impl core::fmt::Debug for Key {
223
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
224
0
        f.debug_struct("Key")
225
0
            .field("algorithm", &self.algorithm.digest_algorithm())
226
0
            .finish()
227
0
    }
228
}
229
230
impl Key {
231
    /// Generate an HMAC signing key using the given digest algorithm with a
232
    /// random value generated from `rng`.
233
    ///
234
    /// The key will be `digest_alg.output_len` bytes long, based on the
235
    /// recommendation in [RFC 2104 Section 3].
236
    ///
237
    /// [RFC 2104 Section 3]: https://tools.ietf.org/html/rfc2104#section-3
238
    ///
239
    //
240
    // # FIPS
241
    // Use this function with one of the following algorithms:
242
    // * `HMAC_SHA1_FOR_LEGACY_USE_ONLY`
243
    // * `HMAC_SHA224`
244
    // * `HMAC_SHA256`
245
    // * `HMAC_SHA384`
246
    // * `HMAC_SHA512`
247
    //
248
    /// # Errors
249
    /// `error::Unspecified` is the `rng` fails.
250
0
    pub fn generate(
251
0
        algorithm: Algorithm,
252
0
        rng: &dyn crate::rand::SecureRandom,
253
0
    ) -> Result<Self, Unspecified> {
254
0
        Self::construct(algorithm, |buf| rng.fill(buf))
255
0
    }
256
257
0
    fn construct<F>(algorithm: Algorithm, fill: F) -> Result<Self, Unspecified>
258
0
    where
259
0
        F: FnOnce(&mut [u8]) -> Result<(), Unspecified>,
260
    {
261
0
        let mut key_bytes = [0; digest::MAX_OUTPUT_LEN];
262
0
        let key_bytes = &mut key_bytes[..algorithm.0.output_len];
263
0
        fill(key_bytes)?;
264
0
        Ok(Self::new(algorithm, key_bytes))
265
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Key>::construct::<<aws_lc_rs::hmac::Key>::generate::{closure#0}>
Unexecuted instantiation: <aws_lc_rs::hmac::Key>::construct::<<aws_lc_rs::hmac::Key as core::convert::From<aws_lc_rs::hkdf::Okm<aws_lc_rs::hmac::Algorithm>>>::from::{closure#0}>
266
267
    /// Construct an HMAC signing key using the given digest algorithm and key
268
    /// value.
269
    ///
270
    /// `key_value` should be a value generated using a secure random number
271
    /// generator (e.g. the `key_value` output by
272
    /// `SealingKey::generate_serializable()`) or derived from a random key by
273
    /// a key derivation function (e.g. `aws_lc_rs::hkdf`). In particular,
274
    /// `key_value` shouldn't be a password.
275
    ///
276
    /// As specified in RFC 2104, if `key_value` is shorter than the digest
277
    /// algorithm's block length (as returned by `digest::Algorithm::block_len`,
278
    /// not the digest length returned by `digest::Algorithm::output_len`) then
279
    /// it will be padded with zeros. Similarly, if it is longer than the block
280
    /// length then it will be compressed using the digest algorithm.
281
    ///
282
    /// You should not use keys larger than the `digest_alg.block_len` because
283
    /// the truncation described above reduces their strength to only
284
    /// `digest_alg.output_len * 8` bits.
285
    ///
286
    /// # Panics
287
    /// Panics if the HMAC context cannot be constructed
288
    #[inline]
289
    #[must_use]
290
0
    pub fn new(algorithm: Algorithm, key_value: &[u8]) -> Self {
291
0
        Key::try_new(algorithm, key_value).expect("Unable to create HmacContext")
292
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Key>::new
Unexecuted instantiation: <aws_lc_rs::hmac::Key>::new
293
294
0
    fn try_new(algorithm: Algorithm, key_value: &[u8]) -> Result<Self, Unspecified> {
295
        unsafe {
296
0
            let mut ctx = MaybeUninit::<HMAC_CTX>::uninit();
297
0
            HMAC_CTX_init(ctx.as_mut_ptr());
298
0
            let evp_md_type = digest::match_digest_type(&algorithm.digest_algorithm().id);
299
0
            if 1 != HMAC_Init_ex(
300
0
                ctx.as_mut_ptr(),
301
0
                key_value.as_ptr().cast(),
302
0
                key_value.len(),
303
0
                evp_md_type.as_const_ptr(),
304
0
                null_mut(),
305
0
            ) {
306
0
                return Err(Unspecified);
307
0
            }
308
0
            let result = Self {
309
0
                algorithm,
310
0
                ctx: LcHmacCtx(ctx.assume_init()),
311
0
            };
312
0
            Ok(result)
313
        }
314
0
    }
315
316
0
    unsafe fn get_hmac_ctx_ptr(&mut self) -> *mut HMAC_CTX {
317
0
        self.ctx.as_mut_ptr()
318
0
    }
319
320
    /// The digest algorithm for the key.
321
    #[inline]
322
    #[must_use]
323
0
    pub fn algorithm(&self) -> Algorithm {
324
0
        Algorithm(self.algorithm.digest_algorithm())
325
0
    }
326
}
327
328
impl hkdf::KeyType for Algorithm {
329
    #[inline]
330
0
    fn len(&self) -> usize {
331
0
        self.digest_algorithm().output_len
332
0
    }
333
}
334
335
impl From<hkdf::Okm<'_, Algorithm>> for Key {
336
0
    fn from(okm: hkdf::Okm<Algorithm>) -> Self {
337
0
        Self::construct(*okm.len(), |buf| okm.fill(buf)).unwrap()
338
0
    }
339
}
340
341
/// A context for multi-step (Init-Update-Finish) HMAC signing.
342
///
343
/// Use `sign` for single-step HMAC signing.
344
pub struct Context {
345
    key: Key,
346
}
347
348
impl Clone for Context {
349
0
    fn clone(&self) -> Self {
350
0
        Self {
351
0
            key: self.key.clone(),
352
0
        }
353
0
    }
354
}
355
356
unsafe impl Send for Context {}
357
358
impl core::fmt::Debug for Context {
359
0
    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
360
0
        f.debug_struct("Context")
361
0
            .field("algorithm", &self.key.algorithm.digest_algorithm())
362
0
            .finish()
363
0
    }
364
}
365
366
impl Context {
367
    /// Constructs a new HMAC signing context using the given digest algorithm
368
    /// and key.
369
    #[inline]
370
    #[must_use]
371
0
    pub fn with_key(signing_key: &Key) -> Self {
372
0
        Self {
373
0
            key: signing_key.clone(),
374
0
        }
375
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::with_key
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::with_key
376
377
    /// Updates the HMAC with all the data in `data`. `update` may be called
378
    /// zero or more times until `finish` is called.
379
    ///
380
    /// # Panics
381
    /// Panics if the HMAC cannot be updated
382
    #[inline]
383
0
    pub fn update(&mut self, data: &[u8]) {
384
0
        Self::try_update(self, data).expect("HMAC_Update failed");
385
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::update
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::update
386
387
    #[inline]
388
0
    fn try_update(&mut self, data: &[u8]) -> Result<(), Unspecified> {
389
        unsafe {
390
0
            if 1 != HMAC_Update(self.key.get_hmac_ctx_ptr(), data.as_ptr(), data.len()) {
391
0
                return Err(Unspecified);
392
0
            }
393
        }
394
0
        Ok(())
395
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::try_update
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::try_update
396
397
    /// Finalizes the HMAC calculation and returns the HMAC value. `sign`
398
    /// consumes the context so it cannot be (mis-)used after `sign` has been
399
    /// called.
400
    ///
401
    /// It is generally not safe to implement HMAC verification by comparing
402
    /// the return value of `sign` to a tag. Use `verify` for verification
403
    /// instead.
404
    ///
405
    // # FIPS
406
    // Use this method with one of the following algorithms:
407
    // * `HMAC_SHA1_FOR_LEGACY_USE_ONLY`
408
    // * `HMAC_SHA224`
409
    // * `HMAC_SHA256`
410
    // * `HMAC_SHA384`
411
    // * `HMAC_SHA512`
412
    //
413
    /// # Panics
414
    /// Panics if the HMAC calculation cannot be finalized
415
    #[inline]
416
    #[must_use]
417
0
    pub fn sign(self) -> Tag {
418
0
        Self::try_sign(self).expect("HMAC_Final failed")
419
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::sign
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::sign
420
    #[inline]
421
0
    fn try_sign(mut self) -> Result<Tag, Unspecified> {
422
0
        let mut output = [0u8; digest::MAX_OUTPUT_LEN];
423
0
        let mut out_len = MaybeUninit::<c_uint>::uninit();
424
        unsafe {
425
0
            if 1 != indicator_check!(HMAC_Final(
426
0
                self.key.get_hmac_ctx_ptr(),
427
0
                output.as_mut_ptr(),
428
0
                out_len.as_mut_ptr(),
429
0
            )) {
430
0
                return Err(Unspecified);
431
0
            }
432
0
            Ok(Tag {
433
0
                msg: output,
434
0
                msg_len: out_len.assume_init() as usize,
435
0
            })
436
        }
437
0
    }
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::try_sign
Unexecuted instantiation: <aws_lc_rs::hmac::Context>::try_sign
438
}
439
440
/// Calculates the HMAC of `data` using the key `key` in one step.
441
///
442
/// Use `Context` to calculate HMACs where the input is in multiple parts.
443
///
444
/// It is generally not safe to implement HMAC verification by comparing the
445
/// return value of `sign` to a tag. Use `verify` for verification instead.
446
//
447
// # FIPS
448
// Use this function with one of the following algorithms:
449
// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY`
450
// * `HMAC_SHA224`
451
// * `HMAC_SHA256`
452
// * `HMAC_SHA384`
453
// * `HMAC_SHA512`
454
#[inline]
455
#[must_use]
456
0
pub fn sign(key: &Key, data: &[u8]) -> Tag {
457
0
    let mut ctx = Context::with_key(key);
458
0
    ctx.update(data);
459
0
    ctx.sign()
460
0
}
Unexecuted instantiation: aws_lc_rs::hmac::sign
Unexecuted instantiation: aws_lc_rs::hmac::sign
461
462
/// Calculates the HMAC of `data` using the signing key `key`, and verifies
463
/// whether the resultant value equals `tag`, in one step.
464
///
465
/// This is logically equivalent to, but more efficient than, constructing a
466
/// `Key` with the same value as `key` and then using `verify`.
467
///
468
/// The verification will be done in constant time to prevent timing attacks.
469
///
470
/// # Errors
471
/// `error::Unspecified` if the inputs are not verified.
472
//
473
// # FIPS
474
// Use this function with one of the following algorithms:
475
// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY`
476
// * `HMAC_SHA224`
477
// * `HMAC_SHA256`
478
// * `HMAC_SHA384`
479
// * `HMAC_SHA512`
480
#[inline]
481
0
pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), Unspecified> {
482
0
    constant_time::verify_slices_are_equal(sign(key, data).as_ref(), tag)
483
0
}
Unexecuted instantiation: aws_lc_rs::hmac::verify
Unexecuted instantiation: aws_lc_rs::hmac::verify
484
485
#[cfg(test)]
486
mod tests {
487
    use crate::{hmac, rand};
488
489
    #[cfg(feature = "fips")]
490
    mod fips;
491
492
    // Make sure that `Key::generate` and `verify_with_own_key` aren't
493
    // completely wacky.
494
    #[test]
495
    pub fn hmac_signing_key_coverage() {
496
        const HELLO_WORLD_GOOD: &[u8] = b"hello, world";
497
        const HELLO_WORLD_BAD: &[u8] = b"hello, worle";
498
499
        let rng = rand::SystemRandom::new();
500
501
        for algorithm in &[
502
            hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
503
            hmac::HMAC_SHA224,
504
            hmac::HMAC_SHA256,
505
            hmac::HMAC_SHA384,
506
            hmac::HMAC_SHA512,
507
        ] {
508
            let key = hmac::Key::generate(*algorithm, &rng).unwrap();
509
            let tag = hmac::sign(&key, HELLO_WORLD_GOOD);
510
            println!("{key:?}");
511
            assert!(hmac::verify(&key, HELLO_WORLD_GOOD, tag.as_ref()).is_ok());
512
            assert!(hmac::verify(&key, HELLO_WORLD_BAD, tag.as_ref()).is_err());
513
        }
514
    }
515
516
    #[test]
517
    fn hmac_coverage() {
518
        // Something would have gone horribly wrong for this to not pass, but we test this so our
519
        // coverage reports will look better.
520
        assert_ne!(hmac::HMAC_SHA256, hmac::HMAC_SHA384);
521
522
        for &alg in &[
523
            hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
524
            hmac::HMAC_SHA224,
525
            hmac::HMAC_SHA256,
526
            hmac::HMAC_SHA384,
527
            hmac::HMAC_SHA512,
528
        ] {
529
            // Clone after updating context with message, then check if the final Tag is the same.
530
            let key = hmac::Key::new(alg, &[0; 32]);
531
            let mut ctx = hmac::Context::with_key(&key);
532
            ctx.update(b"hello, world");
533
            let ctx_clone = ctx.clone();
534
535
            let orig_tag = ctx.sign();
536
            let clone_tag = ctx_clone.sign();
537
            assert_eq!(orig_tag.as_ref(), clone_tag.as_ref());
538
            assert_eq!(orig_tag.clone().as_ref(), clone_tag.as_ref());
539
        }
540
    }
541
}