1use crate::{
59 digest,
60 digest::{Sha256, Sha384, Sha512},
61 initialized_struct, sealed, FfiMutSlice, FfiSlice, ForeignTypeRef as _, InvalidSignatureError,
62};
63use core::{ffi::c_uint, marker::PhantomData, ptr};
64
65pub struct HmacSha256(Hmac<32, Sha256>);
67
68impl HmacSha256 {
69 pub fn mac(key: &[u8], data: &[u8]) -> [u8; 32] {
71 hmac::<32, Sha256>(key, data)
72 }
73
74 pub fn new(key: &[u8; 32]) -> Self {
76 Self(Hmac::new(key))
77 }
78
79 pub fn new_from_slice(key: &[u8]) -> Self {
81 Self(Hmac::new_from_slice(key))
82 }
83
84 pub fn update(&mut self, data: &[u8]) {
86 self.0.update(data)
87 }
88
89 pub fn digest(self) -> [u8; 32] {
91 self.0.digest()
92 }
93
94 pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
96 self.0.verify_slice(tag)
97 }
98
99 pub fn verify(self, tag: &[u8; 32]) -> Result<(), InvalidSignatureError> {
101 self.0.verify(tag)
102 }
103
104 pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
110 self.0.verify_truncated_left(tag)
111 }
112}
113
114#[cfg(feature = "std")]
115impl std::io::Write for HmacSha256 {
116 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
117 self.update(buf);
118 Ok(buf.len())
119 }
120
121 fn flush(&mut self) -> std::io::Result<()> {
122 Ok(())
123 }
124}
125
126impl Clone for HmacSha256 {
127 fn clone(&self) -> Self {
128 HmacSha256(self.0.clone())
129 }
130}
131
132pub struct HmacSha384(Hmac<48, Sha384>);
134
135impl HmacSha384 {
136 pub fn mac(key: &[u8], data: &[u8]) -> [u8; 48] {
138 hmac::<48, Sha384>(key, data)
139 }
140
141 pub fn new(key: &[u8; 48]) -> Self {
143 Self(Hmac::new(key))
144 }
145
146 pub fn new_from_slice(key: &[u8]) -> Self {
148 Self(Hmac::new_from_slice(key))
149 }
150
151 pub fn update(&mut self, data: &[u8]) {
153 self.0.update(data)
154 }
155
156 pub fn digest(self) -> [u8; 48] {
158 self.0.digest()
159 }
160
161 pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
163 self.0.verify_slice(tag)
164 }
165
166 pub fn verify(self, tag: &[u8; 48]) -> Result<(), InvalidSignatureError> {
168 self.0.verify(tag)
169 }
170
171 pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
177 self.0.verify_truncated_left(tag)
178 }
179}
180
181#[cfg(feature = "std")]
182impl std::io::Write for HmacSha384 {
183 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
184 self.update(buf);
185 Ok(buf.len())
186 }
187
188 fn flush(&mut self) -> std::io::Result<()> {
189 Ok(())
190 }
191}
192
193impl Clone for HmacSha384 {
194 fn clone(&self) -> Self {
195 HmacSha384(self.0.clone())
196 }
197}
198
199pub struct HmacSha512(Hmac<64, Sha512>);
201
202impl HmacSha512 {
203 pub fn mac(key: &[u8], data: &[u8]) -> [u8; 64] {
205 hmac::<64, Sha512>(key, data)
206 }
207
208 pub fn new(key: &[u8; 64]) -> Self {
210 Self(Hmac::new(key))
211 }
212
213 pub fn new_from_slice(key: &[u8]) -> Self {
215 Self(Hmac::new_from_slice(key))
216 }
217
218 pub fn update(&mut self, data: &[u8]) {
220 self.0.update(data)
221 }
222
223 pub fn digest(self) -> [u8; 64] {
225 self.0.digest()
226 }
227
228 pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
230 self.0.verify_slice(tag)
231 }
232
233 pub fn verify(self, tag: &[u8; 64]) -> Result<(), InvalidSignatureError> {
235 self.0.verify(tag)
236 }
237
238 pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
244 self.0.verify_truncated_left(tag)
245 }
246}
247
248#[cfg(feature = "std")]
249impl std::io::Write for HmacSha512 {
250 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
251 self.update(buf);
252 Ok(buf.len())
253 }
254
255 fn flush(&mut self) -> std::io::Result<()> {
256 Ok(())
257 }
258}
259
260impl Clone for HmacSha512 {
261 fn clone(&self) -> Self {
262 HmacSha512(self.0.clone())
263 }
264}
265
266#[inline]
272fn hmac<const N: usize, MD: digest::Algorithm>(key: &[u8], data: &[u8]) -> [u8; N] {
273 let mut out = [0_u8; N];
274 let mut size: c_uint = 0;
275
276 let result = unsafe {
280 bssl_sys::HMAC(
281 MD::get_md(sealed::SealedType).as_ptr(),
282 key.as_ffi_void_ptr(),
283 key.len(),
284 data.as_ffi_ptr(),
285 data.len(),
286 out.as_mut_ffi_ptr(),
287 &mut size as *mut c_uint,
288 )
289 };
290 assert_eq!(size as usize, N);
291 assert!(!result.is_null(), "Result of bssl_sys::HMAC was null");
292
293 out
294}
295
296struct Hmac<const N: usize, MD: digest::Algorithm> {
303 ctx: bssl_sys::HMAC_CTX,
308 _marker: PhantomData<MD>,
309}
310
311impl<const N: usize, MD: digest::Algorithm> Hmac<N, MD> {
312 fn new(key: &[u8; N]) -> Self {
314 Self::new_from_slice(key)
315 }
316
317 fn new_from_slice(key: &[u8]) -> Self {
319 let mut ret = Self {
320 ctx: unsafe { initialized_struct(|ctx| bssl_sys::HMAC_CTX_init(ctx)) },
323 _marker: Default::default(),
324 };
325
326 let result = unsafe {
333 bssl_sys::HMAC_Init_ex(
334 &mut ret.ctx,
335 key.as_ffi_void_ptr(),
336 key.len(),
337 MD::get_md(sealed::SealedType).as_ptr(),
338 ptr::null_mut(),
339 )
340 };
341 assert!(result > 0, "Allocation failure in bssl_sys::HMAC_Init_ex");
342 ret
343 }
344
345 fn update(&mut self, data: &[u8]) {
347 let result = unsafe { bssl_sys::HMAC_Update(&mut self.ctx, data.as_ffi_ptr(), data.len()) };
350 assert_eq!(result, 1, "failure in bssl_sys::HMAC_Update");
352 }
353
354 fn digest(mut self) -> [u8; N] {
356 let mut buf = [0_u8; N];
357 let mut size: c_uint = 0;
358 let result =
365 unsafe { bssl_sys::HMAC_Final(&mut self.ctx, buf.as_mut_ffi_ptr(), &mut size) };
366 assert!(result > 0, "Allocation failure in bssl_sys::HMAC_Final");
367 assert_eq!(size as usize, N);
368 buf
369 }
370
371 fn verify(self, tag: &[u8; N]) -> Result<(), InvalidSignatureError> {
373 self.verify_slice(tag)
374 }
375
376 fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
381 if tag.len() == N {
382 self.verify_truncated_left(tag)
383 } else {
384 Err(InvalidSignatureError)
385 }
386 }
387
388 fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> {
396 let len = tag.len();
397 if len == 0 || len > N {
398 return Err(InvalidSignatureError);
399 }
400 let calculated = self.digest();
401
402 let result = unsafe {
406 bssl_sys::CRYPTO_memcmp(calculated.as_ffi_void_ptr(), tag.as_ffi_void_ptr(), len)
407 };
408 if result == 0 {
409 Ok(())
410 } else {
411 Err(InvalidSignatureError)
412 }
413 }
414
415 fn clone(&self) -> Self {
416 let mut ret = Self {
417 ctx: unsafe { initialized_struct(|ctx| bssl_sys::HMAC_CTX_init(ctx)) },
420 _marker: Default::default(),
421 };
422 let result = unsafe { bssl_sys::HMAC_CTX_copy(&mut ret.ctx, &self.ctx) };
425 assert_eq!(result, 1);
426 ret
427 }
428}
429
430impl<const N: usize, MD: digest::Algorithm> Drop for Hmac<N, MD> {
431 fn drop(&mut self) {
432 unsafe { bssl_sys::HMAC_CTX_cleanup(&mut self.ctx) }
433 }
434}
435
436#[cfg(test)]
437mod tests {
438 use super::*;
439 use alloc::boxed::Box;
440
441 #[test]
442 fn hmac_sha256() {
443 let expected: [u8; 32] = [
444 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb,
445 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c,
446 0x2e, 0x32, 0xcf, 0xf7,
447 ];
448 let key: [u8; 20] = [0x0b; 20];
449 let data = b"Hi There";
450
451 let mut hmac = HmacSha256::new_from_slice(&key);
452 hmac.update(data);
453 assert_eq!(hmac.digest(), expected);
454
455 let mut hmac = HmacSha256::new_from_slice(&key);
456 hmac.update(&data[..1]);
457 hmac.update(&data[1..]);
458 assert_eq!(hmac.digest(), expected);
459
460 let mut hmac = HmacSha256::new_from_slice(&key);
461 hmac.update(data);
462 assert!(hmac.verify(&expected).is_ok());
463
464 let mut hmac = HmacSha256::new_from_slice(&key);
465 hmac.update(data);
466 assert!(hmac.verify_truncated_left(&expected[..4]).is_ok());
467
468 let mut hmac = HmacSha256::new_from_slice(&key);
469 hmac.update(data);
470 assert!(hmac.verify_truncated_left(&expected[4..8]).is_err());
471
472 let mut hmac = HmacSha256::new_from_slice(&key);
473 hmac.update(&data[..1]);
474 let mut hmac2 = hmac.clone();
475 let mut hmac3 = Box::new(hmac2.clone());
476 hmac.update(&data[1..]);
477 hmac2.update(&data[1..]);
478 hmac3.update(&data[1..]);
479 assert_eq!(hmac.digest(), expected);
480 assert_eq!(hmac2.digest(), expected);
481 assert_eq!(hmac3.digest(), expected);
482 }
483
484 #[test]
485 fn hmac_sha256_fixed_size_key() {
486 let expected_hmac = [
487 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6, 0x99, 0x3, 0xa0, 0xf1, 0xcf, 0x2b,
488 0xbd, 0xc5, 0xba, 0xa, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c, 0x7a, 0x3b, 0x16, 0x96,
489 0xa0, 0xb6, 0x8c, 0xf7,
490 ];
491 let key: [u8; 32] = [0x0b; 32];
492 let data = b"Hi There";
493
494 let mut hmac = HmacSha256::new(&key);
495 hmac.update(data);
496 let hmac_result: [u8; 32] = hmac.digest();
497 assert_eq!(&hmac_result, &expected_hmac);
498 }
499
500 #[test]
501 fn hmac_sha384() {
502 let key = &[
504 238, 141, 240, 103, 133, 125, 242, 48, 15, 167, 26, 16, 195, 9, 151, 23, 139, 179, 121,
505 97, 39, 181, 236, 229, 242, 204, 193, 112, 147, 43, 224, 231, 142, 169, 176, 165, 147,
506 108, 9, 21, 126, 103, 28, 231, 236, 159, 197, 16,
507 ];
508 let mut hmac = HmacSha384::new_from_slice(key);
509 hmac.update(b"");
510 let hmac_result: [u8; 48] = hmac.digest();
511 assert_eq!(
512 hmac_result,
513 [
514 166, 85, 24, 77, 175, 51, 70, 255, 198, 98, 157, 73, 60, 132, 66, 100, 78, 73, 150,
515 162, 121, 158, 66, 227, 48, 111, 166, 245, 176, 150, 123, 108, 243, 166, 248, 25,
516 186, 184, 155, 206, 41, 125, 29, 26, 89, 7, 178, 208
517 ]
518 );
519
520 let key = &[
521 151, 102, 150, 192, 220, 151, 24, 44, 167, 113, 151, 92, 57, 40, 255, 145, 104, 239,
522 137, 205, 116, 12, 210, 41, 40, 88, 253, 145, 96, 104, 167, 2, 188, 29, 247, 198, 205,
523 142, 225, 240, 210, 94, 97, 212, 197, 20, 204, 93,
524 ];
525 hmac = HmacSha384::new_from_slice(key);
526 hmac.update(&[43]);
527 let hmac_result: [u8; 48] = hmac.digest();
528 assert_eq!(
529 hmac_result,
530 [
531 54, 62, 137, 115, 254, 220, 247, 137, 32, 19, 223, 174, 11, 112, 101, 214, 29, 128,
532 185, 140, 99, 91, 192, 158, 216, 96, 160, 20, 115, 185, 188, 208, 220, 85, 13, 191,
533 102, 207, 13, 96, 31, 233, 203, 243, 174, 89, 98, 13
534 ]
535 );
536
537 let key = &[
538 188, 49, 11, 195, 145, 61, 159, 229, 158, 32, 18, 160, 88, 201, 225, 80, 83, 77, 37,
539 97, 30, 54, 32, 108, 240, 124, 202, 239, 225, 83, 243, 142, 176, 234, 173, 153, 65,
540 182, 136, 61, 251, 206, 1, 188, 181, 25, 96, 65,
541 ];
542 hmac = HmacSha384::new_from_slice(key);
543 let msg = &[
544 159, 7, 71, 215, 57, 107, 251, 224, 28, 243, 232, 83, 97, 229, 0, 133, 224, 169, 26,
545 116, 144, 185, 148, 3, 29, 129, 133, 27, 114, 80, 101, 153, 63, 69, 218, 208, 214, 13,
546 121, 74, 237, 236, 123, 165, 217, 214, 219, 190, 228,
547 ];
548 hmac.update(&msg[..20]);
549 hmac.update(&msg[20..]);
550 let hmac_result: [u8; 48] = hmac.digest();
551 assert_eq!(
552 hmac_result,
553 [
554 58, 134, 73, 143, 120, 195, 251, 126, 179, 183, 179, 216, 47, 103, 125, 45, 254, 1,
555 22, 111, 231, 110, 35, 32, 131, 51, 77, 116, 241, 21, 136, 253, 8, 150, 55, 201,
556 71, 97, 233, 207, 232, 54, 67, 96, 5, 222, 174, 247
557 ]
558 );
559 }
560
561 #[test]
562 fn hmac_sha512() {
563 let expected: [u8; 64] = [
564 135, 170, 124, 222, 165, 239, 97, 157, 79, 240, 180, 36, 26, 29, 108, 176, 35, 121,
565 244, 226, 206, 78, 194, 120, 122, 208, 179, 5, 69, 225, 124, 222, 218, 168, 51, 183,
566 214, 184, 167, 2, 3, 139, 39, 78, 174, 163, 244, 228, 190, 157, 145, 78, 235, 97, 241,
567 112, 46, 105, 108, 32, 58, 18, 104, 84,
568 ];
569 let key: [u8; 20] = [0x0b; 20];
570 let data = b"Hi There";
571
572 let mut hmac = HmacSha512::new_from_slice(&key);
573 hmac.update(data);
574 assert_eq!(hmac.digest(), expected);
575
576 let mut hmac = HmacSha512::new_from_slice(&key);
577 hmac.update(&data[..1]);
578 hmac.update(&data[1..]);
579 assert_eq!(hmac.digest(), expected);
580
581 let mut hmac = HmacSha512::new_from_slice(&key);
582 hmac.update(data);
583 assert!(hmac.verify(&expected).is_ok());
584
585 let mut hmac = HmacSha512::new_from_slice(&key);
586 hmac.update(data);
587 assert!(hmac.verify_truncated_left(&expected[..4]).is_ok());
588
589 let mut hmac = HmacSha512::new_from_slice(&key);
590 hmac.update(data);
591 assert!(hmac.verify_truncated_left(&expected[4..8]).is_err());
592
593 let mut hmac = HmacSha512::new_from_slice(&key);
594 hmac.update(&data[..1]);
595 let mut hmac2 = hmac.clone();
596 let mut hmac3 = Box::new(hmac.clone());
597 hmac.update(&data[1..]);
598 hmac2.update(&data[1..]);
599 hmac3.update(&data[1..]);
600 assert_eq!(hmac.digest(), expected);
601 assert_eq!(hmac2.digest(), expected);
602 assert_eq!(hmac3.digest(), expected);
603 }
604}