1use crate::cvt;
2use crate::cvt_p;
3use crate::error::ErrorStack;
4use crate::mac::Mac;
5use foreign_types::ForeignType;
6use openssl_macros::corresponds;
7use std::ffi::CStr;
8use std::ptr;
9
10foreign_type_and_impl_send_sync! {
11 type CType = ffi::EVP_MAC_CTX;
12 fn drop = ffi::EVP_MAC_CTX_free;
13 fn clone = ffi::EVP_MAC_CTX_dup;
14
15 pub struct MacCtx;
17 pub struct MacCtxRef;
19}
20
21impl MacCtx {
22 #[corresponds(EVP_MAC_CTX_new)]
24 pub fn new(mac: Mac) -> Result<Self, ErrorStack> {
25 ffi::init();
26
27 unsafe {
28 let ptr = cvt_p(ffi::EVP_MAC_CTX_new(mac.as_ptr()))?;
29 Ok(MacCtx::from_ptr(ptr))
30 }
31 }
32
33 pub fn init_ex(&mut self, key: Option<&[u8]>, md: &CStr) -> Result<(), ErrorStack> {
35 let key_field_name = CStr::from_bytes_with_nul(b"key\0").unwrap();
36 let digest_field_name = CStr::from_bytes_with_nul(b"digest\0").unwrap();
37
38 let key_len = key.map(|v| v.len()).unwrap_or_default();
39 let key = key.map(|v| v.as_ptr()).unwrap_or(ptr::null());
40
41 unsafe {
42 let param_key =
43 ffi::OSSL_PARAM_construct_octet_string(key_field_name.as_ptr(), key as _, key_len);
44 let param_digest = ffi::OSSL_PARAM_construct_utf8_string(
45 digest_field_name.as_ptr(),
46 md.as_ptr() as _,
47 md.to_bytes().len(),
48 );
49 let param_end = ffi::OSSL_PARAM_construct_end();
50
51 let params = [param_key, param_digest, param_end];
52
53 cvt(ffi::EVP_MAC_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
54 }
55 Ok(())
56 }
57
58 #[corresponds(EVP_MAC_CTX_get_mac_size)]
60 pub fn mac_size(&self) -> usize {
61 unsafe { ffi::EVP_MAC_CTX_get_mac_size(self.as_ptr()) }
62 }
63
64 #[corresponds(EVP_MAC_CTX_get_block_size)]
68 pub fn block_size(&self) -> usize {
69 unsafe { ffi::EVP_MAC_CTX_get_block_size(self.as_ptr()) }
70 }
71
72 #[corresponds(EVP_MAC_update)]
74 #[inline]
75 pub fn mac_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
76 unsafe {
77 cvt(ffi::EVP_MAC_update(
78 self.as_ptr(),
79 data.as_ptr() as *const _,
80 data.len(),
81 ))?;
82 }
83
84 Ok(())
85 }
86
87 #[corresponds(EVP_MAC_final)]
92 #[inline]
93 pub fn mac_final(&mut self, out: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
94 let mut len = out.as_ref().map_or(0, |b| b.len());
95
96 unsafe {
97 cvt(ffi::EVP_MAC_final(
98 self.as_ptr(),
99 out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
100 &mut len,
101 len,
102 ))?;
103 }
104
105 Ok(len)
106 }
107
108 pub fn mac_final_to_vec(&mut self, out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
110 let base = out.len();
111 out.resize(base + self.mac_size(), 0);
112 let len = self.mac_final(Some(&mut out[base..]))?;
113 out.truncate(base + len);
114 Ok(len)
115 }
116}