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
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,
}
impl Drop for MsgAuthCode {
fn drop(&mut self) {
unsafe {
botan_mac_destroy(self.obj);
}
}
}
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 mut obj = ptr::null_mut();
call_botan! { botan_mac_init(&mut obj, make_cstr(name)?.as_ptr(), 0u32) };
let mut output_length = 0;
call_botan! { botan_mac_output_length(obj, &mut output_length) };
let mut min_keylen = 0;
let mut max_keylen = 0;
let mut mod_keylen = 0;
call_botan! { botan_mac_get_keyspec(obj, &mut min_keylen, &mut max_keylen, &mut mod_keylen) };
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 hmac = botan::MsgAuthCode::new("HMAC(SHA-256)").unwrap();
/// hmac.set_key(&vec![0; 16]).unwrap();
/// ```
pub fn set_key(&self, key: &[u8]) -> Result<()> {
call_botan! { botan_mac_set_key(self.obj, key.as_ptr(), key.len()) };
Ok(())
}
/// Add data to a MAC computation, may be called many times
///
/// # Examples
/// ```
/// let 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(&self, data: &[u8]) -> Result<()> {
call_botan! { botan_mac_update(self.obj, data.as_ptr(), data.len()) };
Ok(())
}
/// Complete a MAC computation, after which the object is reset to
/// MAC a new message with the same key.
///
/// # Examples
/// ```
/// let 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(&self) -> Result<Vec<u8>> {
let mut output = vec![0; self.output_length];
call_botan! { botan_mac_final(self.obj, output.as_mut_ptr()) };
Ok(output)
}
/// Clear the MAC key
///
/// # Examples
/// ```
/// let 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(&self) -> Result<()> {
call_botan! { botan_mac_clear(self.obj) };
Ok(())
}
}