/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 | | } |