Add HMAC on SHA-384 for TLS 1.3 support TLS 1.3 has a cipher suite that uses this HMAC variant. We would like to add support for this HMAC scheme for alignment to the specification. Change-Id: I7754f1ce6309d19b622a0fe34efe2e4f7c52ce83 Signed-off-by: Xiangfei Ding <xfding@google.com> Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/87111 Reviewed-by: Adam Langley <agl@google.com> Reviewed-by: Rudolf Polzer <rpolzer@google.com> Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/rust/bssl-crypto/src/hmac.rs b/rust/bssl-crypto/src/hmac.rs index 9a51216..0aca68b 100644 --- a/rust/bssl-crypto/src/hmac.rs +++ b/rust/bssl-crypto/src/hmac.rs
@@ -14,7 +14,7 @@ //! Hash-based message authentication from <https://datatracker.ietf.org/doc/html/rfc2104>. //! -//! HMAC-SHA256 and HMAC-SHA512 are supported. +//! HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 are supported. //! //! MACs can be computed in a single shot: //! @@ -57,7 +57,7 @@ use crate::{ digest, - digest::{Sha256, Sha512}, + digest::{Sha256, Sha384, Sha512}, initialized_struct, sealed, FfiMutSlice, FfiSlice, ForeignTypeRef as _, InvalidSignatureError, }; use core::{ffi::c_uint, marker::PhantomData, ptr}; @@ -129,6 +129,73 @@ } } +/// HMAC-SHA384. +pub struct HmacSha384(Hmac<48, Sha384>); + +impl HmacSha384 { + /// Computes the HMAC-SHA384 of `data` as a one-shot operation. + pub fn mac(key: &[u8], data: &[u8]) -> [u8; 48] { + hmac::<48, Sha384>(key, data) + } + + /// Creates a new HMAC-SHA384 operation from a fixed-size key. + pub fn new(key: &[u8; 48]) -> Self { + Self(Hmac::new(key)) + } + + /// Creates a new HMAC-SHA384 operation from a variable-length key. + pub fn new_from_slice(key: &[u8]) -> Self { + Self(Hmac::new_from_slice(key)) + } + + /// Hashes the provided input into the HMAC operation. + pub fn update(&mut self, data: &[u8]) { + self.0.update(data) + } + + /// Computes the final HMAC value, consuming the object. + pub fn digest(self) -> [u8; 48] { + self.0.digest() + } + + /// Checks that the provided tag value matches the computed HMAC value. + pub fn verify_slice(self, tag: &[u8]) -> Result<(), InvalidSignatureError> { + self.0.verify_slice(tag) + } + + /// Checks that the provided tag value matches the computed HMAC value. + pub fn verify(self, tag: &[u8; 48]) -> Result<(), InvalidSignatureError> { + self.0.verify(tag) + } + + /// Checks that the provided tag value matches the computed HMAC, truncated to the input tag's + /// length. + /// + /// Truncating an HMAC reduces the security of the construction. Callers must ensure `tag`'s + /// length matches the desired HMAC length and security level. + pub fn verify_truncated_left(self, tag: &[u8]) -> Result<(), InvalidSignatureError> { + self.0.verify_truncated_left(tag) + } +} + +#[cfg(feature = "std")] +impl std::io::Write for HmacSha384 { + fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { + self.update(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +impl Clone for HmacSha384 { + fn clone(&self) -> Self { + HmacSha384(self.0.clone()) + } +} + /// HMAC-SHA512. pub struct HmacSha512(Hmac<64, Sha512>); @@ -431,6 +498,67 @@ } #[test] + fn hmac_sha384() { + // We test against some Wycheproof test vectors `hmac_sha384_test.json`. + let key = &[ + 238, 141, 240, 103, 133, 125, 242, 48, 15, 167, 26, 16, 195, 9, 151, 23, 139, 179, 121, + 97, 39, 181, 236, 229, 242, 204, 193, 112, 147, 43, 224, 231, 142, 169, 176, 165, 147, + 108, 9, 21, 126, 103, 28, 231, 236, 159, 197, 16, + ]; + let mut hmac = HmacSha384::new_from_slice(key); + hmac.update(b""); + let hmac_result: [u8; 48] = hmac.digest(); + assert_eq!( + hmac_result, + [ + 166, 85, 24, 77, 175, 51, 70, 255, 198, 98, 157, 73, 60, 132, 66, 100, 78, 73, 150, + 162, 121, 158, 66, 227, 48, 111, 166, 245, 176, 150, 123, 108, 243, 166, 248, 25, + 186, 184, 155, 206, 41, 125, 29, 26, 89, 7, 178, 208 + ] + ); + + let key = &[ + 151, 102, 150, 192, 220, 151, 24, 44, 167, 113, 151, 92, 57, 40, 255, 145, 104, 239, + 137, 205, 116, 12, 210, 41, 40, 88, 253, 145, 96, 104, 167, 2, 188, 29, 247, 198, 205, + 142, 225, 240, 210, 94, 97, 212, 197, 20, 204, 93, + ]; + hmac = HmacSha384::new_from_slice(key); + hmac.update(&[43]); + let hmac_result: [u8; 48] = hmac.digest(); + assert_eq!( + hmac_result, + [ + 54, 62, 137, 115, 254, 220, 247, 137, 32, 19, 223, 174, 11, 112, 101, 214, 29, 128, + 185, 140, 99, 91, 192, 158, 216, 96, 160, 20, 115, 185, 188, 208, 220, 85, 13, 191, + 102, 207, 13, 96, 31, 233, 203, 243, 174, 89, 98, 13 + ] + ); + + let key = &[ + 188, 49, 11, 195, 145, 61, 159, 229, 158, 32, 18, 160, 88, 201, 225, 80, 83, 77, 37, + 97, 30, 54, 32, 108, 240, 124, 202, 239, 225, 83, 243, 142, 176, 234, 173, 153, 65, + 182, 136, 61, 251, 206, 1, 188, 181, 25, 96, 65, + ]; + hmac = HmacSha384::new_from_slice(key); + let msg = &[ + 159, 7, 71, 215, 57, 107, 251, 224, 28, 243, 232, 83, 97, 229, 0, 133, 224, 169, 26, + 116, 144, 185, 148, 3, 29, 129, 133, 27, 114, 80, 101, 153, 63, 69, 218, 208, 214, 13, + 121, 74, 237, 236, 123, 165, 217, 214, 219, 190, 228, + ]; + hmac.update(&msg[..20]); + hmac.update(&msg[20..]); + let hmac_result: [u8; 48] = hmac.digest(); + assert_eq!( + hmac_result, + [ + 58, 134, 73, 143, 120, 195, 251, 126, 179, 183, 179, 216, 47, 103, 125, 45, 254, 1, + 22, 111, 231, 110, 35, 32, 131, 51, 77, 116, 241, 21, 136, 253, 8, 150, 55, 201, + 71, 97, 233, 207, 232, 54, 67, 96, 5, 222, 174, 247 + ] + ); + } + + #[test] fn hmac_sha512() { let expected: [u8; 64] = [ 135, 170, 124, 222, 165, 239, 97, 157, 79, 240, 180, 36, 26, 29, 108, 176, 35, 121,