variant_ssl/
hmac.rs

1use crate::error::ErrorStack;
2use crate::md::MdRef;
3use crate::util::ForeignTypeRefExt;
4use crate::{cvt, cvt_p};
5use foreign_types::{ForeignType, ForeignTypeRef};
6use openssl_macros::corresponds;
7use std::ptr;
8
9foreign_type_and_impl_send_sync! {
10    type CType = ffi::HMAC_CTX;
11    fn drop = ffi::HMAC_CTX_free;
12
13    /// A context object used to perform MAC operations.
14    pub struct HMacCtx;
15    /// A reference to a [`HmacCtx`].
16    pub struct HMacCtxRef;
17}
18
19impl HMacCtx {
20    /// Creates a new context.
21    #[corresponds(HMAC_CTX_new)]
22    pub fn new() -> Result<Self, ErrorStack> {
23        ffi::init();
24
25        unsafe {
26            let ptr = cvt_p(ffi::HMAC_CTX_new())?;
27            Ok(HMacCtx::from_ptr(ptr))
28        }
29    }
30}
31
32impl HMacCtxRef {
33    /// Clears an existing HMAC_CTX and associated resources.
34    ///
35    /// This will make it suitable for new computations as if it was newly created with HMAC_CTX_new().
36    #[corresponds(HMAC_CTX_reset)]
37    #[cfg(any(ossl110, libressl350))]
38    #[inline]
39    pub fn reset(&mut self) -> Result<(), ErrorStack> {
40        unsafe {
41            let _ = cvt(ffi::HMAC_CTX_reset(self.as_ptr()))?;
42            Ok(())
43        }
44    }
45
46    /// Clears an existing HMAC_CTX and associated resources.
47    ///
48    /// This will make it suitable for new computations as if it was newly created with HMAC_CTX_new().
49    #[corresponds(HMAC_CTX_reset)]
50    #[cfg(any(boringssl, awslc))]
51    #[inline]
52    pub fn reset(&mut self) -> Result<(), ErrorStack> {
53        unsafe {
54            ffi::HMAC_CTX_reset(self.as_ptr());
55            Ok(())
56        }
57    }
58
59    #[corresponds(HMAC_CTX_copy)]
60    pub fn copy(&mut self, src: &HMacCtxRef) -> Result<(), ErrorStack> {
61        unsafe {
62            cvt(ffi::HMAC_CTX_copy(self.as_ptr(), src.as_ptr()))?;
63            Ok(())
64        }
65    }
66
67    #[corresponds(HMAC_Init_ex)]
68    pub fn init_ex(&mut self, key: Option<&[u8]>, md: &MdRef) -> Result<(), ErrorStack> {
69        let key_len = key.map(|v| v.len()).unwrap_or_default();
70        #[cfg(not(any(boringssl, awslc)))]
71        let key_len = i32::try_from(key_len).unwrap();
72        let key = key.map(|v| v.as_ptr()).unwrap_or(ptr::null());
73        unsafe {
74            cvt(ffi::HMAC_Init_ex(
75                self.as_ptr(),
76                key as _,
77                key_len,
78                md.as_ptr(),
79                ptr::null_mut(),
80            ))?;
81            Ok(())
82        }
83    }
84
85    #[corresponds(HMAC_CTX_get_md)]
86    pub fn md(&self) -> Option<&MdRef> {
87        unsafe {
88            let ptr = ffi::HMAC_CTX_get_md(self.as_ptr());
89            if ptr.is_null() {
90                None
91            } else {
92                Some(MdRef::from_const_ptr(ptr))
93            }
94        }
95    }
96
97    /// Returns the size, in bytes, of the HMAC that will be produced by ctx.
98    ///
99    /// On entry, ctx must have been setup with init_ex
100    #[corresponds(HMAC_size)]
101    #[cfg(any(ossl110, boringssl, awslc))]
102    pub fn size(&self) -> usize {
103        // HMAC_size is a macro in LibreSSL
104        unsafe { ffi::HMAC_size(self.as_ptr()) }
105    }
106
107    /// Returns the size, in bytes, of the HMAC that will be produced by ctx.
108    ///
109    /// On entry, ctx must have been setup with init_ex
110    #[cfg(not(any(ossl110, boringssl, awslc)))]
111    pub fn size(&self) -> usize {
112        self.md().map(|md| md.size()).unwrap_or_default()
113    }
114
115    /// Add data bytes to the MAC input.
116    #[corresponds(HMAC_Update)]
117    #[inline]
118    pub fn hmac_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
119        unsafe {
120            cvt(ffi::HMAC_Update(
121                self.as_ptr(),
122                data.as_ptr() as *const _,
123                data.len(),
124            ))?;
125        }
126
127        Ok(())
128    }
129
130    /// Place the message authentication code in out.
131    #[corresponds(HMAC_Update)]
132    pub fn hmac_final(&mut self, out: &mut [u8]) -> Result<usize, ErrorStack> {
133        let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX);
134
135        unsafe {
136            cvt(ffi::HMAC_Final(self.as_ptr(), out.as_mut_ptr(), &mut len))?;
137        }
138
139        Ok(len as usize)
140    }
141
142    /// Like [`Self::hmac_final`] but appends the signature to a [`Vec`].
143    pub fn hmac_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
144        let base = out.len();
145        out.resize(base + self.size(), 0);
146        let len = self.hmac_final(&mut out[base..])?;
147        out.truncate(base + len);
148        Ok(len)
149    }
150}