1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use crate::utils::*;
use botan_sys::*;
#[derive(Debug)]
/// Message authentication code
pub struct MsgAuthCode {
obj: botan_mac_t,
output_length: usize,
min_keylen: usize,
max_keylen: usize,
mod_keylen: usize,
}
unsafe impl Sync for MsgAuthCode {}
unsafe impl Send for MsgAuthCode {}
botan_impl_drop!(MsgAuthCode, botan_mac_destroy);
impl MsgAuthCode {
/// Create a new message authentication code
///
/// # Examples
/// ```
/// let hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// ```
/// ```
/// let poly1305 = botan::MsgAuthCode::new("Poly1305").unwrap();
/// ```
pub fn new(name: &str) -> Result<MsgAuthCode> {
let obj = botan_init!(botan_mac_init, make_cstr(name)?.as_ptr(), 0u32)?;
let output_length = botan_usize!(botan_mac_output_length, obj)?;
let (min_keylen, max_keylen, mod_keylen) = botan_usize3!(botan_mac_get_keyspec, obj)?;
Ok(MsgAuthCode {
obj,
output_length,
min_keylen,
max_keylen,
mod_keylen,
})
}
/// Return the name of this algorithm which may or may not exactly
/// match what was provided to new()
///
/// # Examples
///
/// ```
/// let mac = botan::MsgAuthCode::new("HMAC(SHA-384)").unwrap();
/// assert_eq!(mac.algo_name().unwrap(), "HMAC(SHA-384)");
/// ```
pub fn algo_name(&self) -> Result<String> {
call_botan_ffi_returning_string(32, &|out_buf, out_len| unsafe {
botan_mac_name(self.obj, out_buf as *mut c_char, out_len)
})
}
/// Return information about the key lengths supported by this object
pub fn key_spec(&self) -> Result<KeySpec> {
KeySpec::new(self.min_keylen, self.max_keylen, self.mod_keylen)
}
/// Return the output length of the authentication code, in bytes
/// # Examples
/// ```
/// let hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// assert_eq!(hmac.output_length().unwrap(), 32);
/// ```
pub fn output_length(&self) -> Result<usize> {
Ok(self.output_length)
}
/// Set the key for the authentication code object
/// # Examples
/// ```
/// let mut hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// hmac.set_key(&vec![0; 16]).unwrap();
/// ```
pub fn set_key(&mut self, key: &[u8]) -> Result<()> {
botan_call!(botan_mac_set_key, self.obj, key.as_ptr(), key.len())
}
#[cfg(botan_ffi_20230403)]
/// Set the nonce for the authentication code object
///
/// Only a few MACs support this; currently only GMAC
///
/// # Examples
/// ```
/// let mut gmac = botan::MsgAuthCode::new("GMAC(AES-128)").unwrap();
/// gmac.set_key(&vec![0; 16]).unwrap();
/// gmac.set_nonce(&vec![0; 12]);
/// ```
pub fn set_nonce(&mut self, nonce: &[u8]) -> Result<()> {
botan_call!(botan_mac_set_nonce, self.obj, nonce.as_ptr(), nonce.len())
}
/// Add data to a MAC computation, may be called many times
///
/// # Examples
/// ```
/// let mut hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// assert!(hmac.update(&[23]).is_err()); // key not set yet
/// hmac.set_key(&vec![0; 16]).unwrap();
/// hmac.update(&[1,2,3]).unwrap();
/// hmac.update(&[4,5,6]).unwrap();
/// ```
pub fn update(&mut self, data: &[u8]) -> Result<()> {
botan_call!(botan_mac_update, self.obj, data.as_ptr(), data.len())
}
/// Complete a MAC computation, after which the object is reset to
/// MAC a new message with the same key.
///
/// # Examples
/// ```
/// let mut hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// assert!(hmac.update(&[23]).is_err()); // key not set yet
/// hmac.set_key(&vec![0; 16]).unwrap();
/// hmac.update(&[1,2,3]).unwrap();
/// hmac.update(&[4,5,6]).unwrap();
/// let mac = hmac.finish().unwrap();
/// ```
pub fn finish(&mut self) -> Result<Vec<u8>> {
let mut output = vec![0; self.output_length];
botan_call!(botan_mac_final, self.obj, output.as_mut_ptr())?;
Ok(output)
}
/// Clear the MAC key
///
/// # Examples
/// ```
/// let mut hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// hmac.set_key(&vec![0; 16]).unwrap();
/// hmac.update(&[1,2,3]).unwrap();
/// hmac.clear().unwrap();
/// assert!(hmac.update(&[23]).is_err()); // key not set anymore
/// ```
pub fn clear(&mut self) -> Result<()> {
botan_call!(botan_mac_clear, self.obj)
}
}