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
use crate::utils::*;
use botan_sys::*;
#[derive(Debug)]
/// A hash function object
pub struct HashFunction {
obj: botan_hash_t,
output_length: usize,
}
impl Clone for HashFunction {
fn clone(&self) -> HashFunction {
self.duplicate().expect("copying hash object state failed")
}
}
unsafe impl Sync for HashFunction {}
unsafe impl Send for HashFunction {}
botan_impl_drop!(HashFunction, botan_hash_destroy);
impl HashFunction {
/// Create a new hash function
///
/// # Errors
/// Will fail if the named hash is not known
/// # Examples
/// ```
/// assert!(botan::HashFunction::new("SHA-256").is_ok());
/// assert!(botan::HashFunction::new("Hash9000").is_err());
/// ```
pub fn new(name: &str) -> Result<HashFunction> {
let obj = botan_init!(botan_hash_init, make_cstr(name)?.as_ptr(), 0u32)?;
let output_length = botan_usize!(botan_hash_output_length, obj)?;
Ok(HashFunction { obj, output_length })
}
/// Return the name of this algorithm which may or may not exactly
/// match what was provided to new()
///
/// # Examples
///
/// ```
/// let hash = botan::HashFunction::new("SHA-384").unwrap();
/// assert_eq!(hash.algo_name().unwrap(), "SHA-384");
/// ```
pub fn algo_name(&self) -> Result<String> {
call_botan_ffi_returning_string(32, &|out_buf, out_len| unsafe {
botan_hash_name(self.obj, out_buf as *mut c_char, out_len)
})
}
/// Return the output length of the hash function, in bytes
///
/// # Examples
/// ```
/// let hash = botan::HashFunction::new("SHA-256").unwrap();
/// assert_eq!(hash.output_length().unwrap(), 32);
/// ```
pub fn output_length(&self) -> Result<usize> {
Ok(self.output_length)
}
/// Return the block length of the hash function, in bytes
///
/// # Examples
/// ```
/// let hash = botan::HashFunction::new("SHA-256").unwrap();
/// assert_eq!(hash.block_size().unwrap(), 64);
/// ```
pub fn block_size(&self) -> Result<usize> {
botan_usize!(botan_hash_block_size, self.obj)
}
/// Add data to a hash computation, may be called many times
///
/// # Examples
/// ```
/// let mut hash = botan::HashFunction::new("SHA-256").unwrap();
/// hash.update(&[1,2,3]).unwrap();
/// hash.update(&[4,5,6]).unwrap();
/// ```
pub fn update(&mut self, data: &[u8]) -> Result<()> {
botan_call!(botan_hash_update, self.obj, data.as_ptr(), data.len())?;
Ok(())
}
/// Finalize the computation, returning the hash of the message
///
/// # Examples
/// ```
/// let mut hash = botan::HashFunction::new("SHA-256").unwrap();
/// hash.update(&[1,2,3]).unwrap();
/// hash.update(&[4,5,6]).unwrap();
/// let digest = hash.finish().unwrap();
/// ```
pub fn finish(&mut self) -> Result<Vec<u8>> {
let mut output = vec![0; self.output_length];
botan_call!(botan_hash_final, self.obj, output.as_mut_ptr())?;
Ok(output)
}
/// Clear the internal state of the hash function. It acts as if it
/// was newly created, and is ready to compute a new digest.
/// Basically the same as calling final, but without returning a
/// result.
pub fn clear(&mut self) -> Result<()> {
botan_call!(botan_hash_clear, self.obj)?;
Ok(())
}
/// Copy hash object state to a new object, allowing prefixes of
/// messages to be hashed. This function is also called by clone.
///
/// # Errors
/// Should not fail but might due to unexpected error
/// # Examples
/// ```
/// let mut hash = botan::HashFunction::new("SHA-256").unwrap();
/// hash.update(&[1,2,3]);
/// let mut hash2 = hash.duplicate().unwrap();
/// hash2.update(&[4,5,6]);
/// let result1 = hash.finish().unwrap(); // hash of 1,2,3
/// let result2 = hash2.finish().unwrap(); // hash of 1,2,3,4,5,6
/// ```
pub fn duplicate(&self) -> Result<HashFunction> {
let obj = botan_init!(botan_hash_copy_state, self.obj)?;
Ok(HashFunction {
obj,
output_length: self.output_length,
})
}
}