From 1ff6b4d427e85f290b68e3b9f547ca536360f32b Mon Sep 17 00:00:00 2001 From: Maurice Lam Date: Thu, 2 Feb 2023 19:45:12 +0000 Subject: [PATCH 3/3] Add HmacCtx wrapper for BoringSSL --- openssl-sys/src/handwritten/hmac.rs | 2 +- openssl/src/hmac.rs | 111 ++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/openssl-sys/src/handwritten/hmac.rs b/openssl-sys/src/handwritten/hmac.rs index 7cbb7cc9..7c0e0b5a 100644 --- a/openssl-sys/src/handwritten/hmac.rs +++ b/openssl-sys/src/handwritten/hmac.rs @@ -3,7 +3,7 @@ use libc::*; use *; cfg_if! { - if #[cfg(any(ossl110, libressl350))] { + if #[cfg(any(ossl110, libressl350, boringssl))] { extern "C" { pub fn HMAC_CTX_new() -> *mut HMAC_CTX; pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); diff --git a/openssl/src/hmac.rs b/openssl/src/hmac.rs index 601ae01b..90fd2175 100644 --- a/openssl/src/hmac.rs +++ b/openssl/src/hmac.rs @@ -1,10 +1,12 @@ -use crate::cvt_p; +use crate::{cvt, cvt_p}; use crate::error::ErrorStack; use crate::md::MdRef; +use ffi::HMAC_CTX; use foreign_types::ForeignTypeRef; +use libc::{c_uint, c_void}; use openssl_macros::corresponds; -use libc::{c_void, c_uint}; use std::convert::TryFrom; +use std::ptr; /// Computes the HMAC as a one-shot operation. /// @@ -20,7 +22,7 @@ pub fn hmac<'a>( md: &MdRef, key: &[u8], data: &[u8], - out: &'a mut [u8] + out: &'a mut [u8], ) -> Result<&'a [u8], ErrorStack> { let mut out_len = c_uint::try_from(out.len()).unwrap(); unsafe { @@ -31,38 +33,115 @@ pub fn hmac<'a>( data.as_ptr(), data.len(), out.as_mut_ptr(), - &mut out_len - ))?; + &mut out_len, + ))?; } Ok(&out[..out_len as usize]) } +/// Only available in boringssl. For openssl, use `PKey::hmac` instead. +#[cfg(boringssl)] +pub struct HmacCtx { + ctx: *mut HMAC_CTX, +} + +#[cfg(boringssl)] +impl HmacCtx { + #[corresponds(HMAC_CTX_new)] + pub fn new(key: &[u8], md: &MdRef) -> Result { + unsafe { + let ctx = cvt_p(ffi::HMAC_CTX_new())?; + cvt(ffi::HMAC_Init_ex( + ctx, + key.as_ptr() as *const c_void, + key.len(), + md.as_ptr(), + ptr::null_mut(), + ))?; + Ok(Self { ctx }) + } + } + + pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::HMAC_Update(self.ctx, data.as_ptr(), data.len())).map(|_| ()) } + } + + /// Finishes the HMAC process, writing any remaining data to `output`. + /// The number of bytes written to `output` is returned. + /// `update` should not be called after this method. + pub fn finalize(&mut self, md: &mut [u8]) -> Result { + unsafe { + let mut size: c_uint = 0; + cvt(ffi::HMAC_Final( + self.ctx, + md.as_mut_ptr(), + &mut size as *mut c_uint, + )) + .map(|_| size as usize) + } + } +} + +impl Drop for HmacCtx { + #[corresponds(HMAC_CTX_free)] + fn drop(&mut self) { + unsafe { + ffi::HMAC_CTX_free(self.ctx); + } + } +} + #[cfg(test)] mod tests { use super::*; use crate::md::Md; - use crate::memcmp; - const SHA_256_DIGEST_SIZE:usize = 32; + const SHA_256_DIGEST_SIZE: usize = 32; #[test] fn hmac_sha256_test() { - let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7]; + let expected_hmac = [ + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, + 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, + 0x2e, 0x32, 0xcf, 0xf7, + ]; let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE]; - let key:[u8; 20] = [0x0b; 20]; + let key: [u8; 20] = [0x0b; 20]; let data = b"Hi There"; - let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); - expect!(memcmp::eq(&hmac_result, &expected_hmac)); + let hmac_result = + hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); + assert_eq!(&hmac_result, &expected_hmac); } #[test] fn hmac_sha256_test_big_buffer() { - let expected_hmac = [0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7]; + let expected_hmac = [ + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, + 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, + 0x2e, 0x32, 0xcf, 0xf7, + ]; let mut out: [u8; 100] = [0; 100]; - let key:[u8;20] = [0x0b; 20]; + let key: [u8; 20] = [0x0b; 20]; + let data = b"Hi There"; + let hmac_result = + hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); + assert_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE); + assert_eq!(&hmac_result, &expected_hmac); + } + + #[test] + fn hmac_sha256_update_test() { + let expected_hmac = [ + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0xb, + 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x0, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, + 0x2e, 0x32, 0xcf, 0xf7, + ]; + let mut out: [u8; SHA_256_DIGEST_SIZE] = [0; SHA_256_DIGEST_SIZE]; + let key: [u8; 20] = [0x0b; 20]; let data = b"Hi There"; - let hmac_result = hmac(Md::sha256(), &key, data, &mut out).expect("Couldn't calculate sha256 hmac"); - expect_eq!(hmac_result.len(), SHA_256_DIGEST_SIZE); - expect!(memcmp::eq(&hmac_result, &expected_hmac)); + let mut hmac_ctx = HmacCtx::new(&key, Md::sha256()).unwrap(); + hmac_ctx.update(data).unwrap(); + hmac_ctx.finalize(&mut out).unwrap(); + assert_eq!(&out, &expected_hmac); } } -- 2.39.1.519.gcb327c4b5f-goog