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
use botan_sys::*;
use utils::*;
#[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")
}
}
impl Drop for HashFunction {
fn drop(&mut self) {
unsafe { botan_hash_destroy(self.obj); }
}
}
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 mut obj = ptr::null_mut();
call_botan! { botan_hash_init(&mut obj, make_cstr(name)?.as_ptr(), 0u32) };
let mut output_length = 0;
call_botan! { botan_hash_output_length(obj, &mut output_length) };
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> {
let mut block_length = 0;
call_botan! { botan_hash_block_size(self.obj, &mut block_length) };
Ok(block_length)
}
/// Add data to a hash computation, may be called many times
///
/// # Examples
/// ```
/// let hash = botan::HashFunction::new("SHA-256").unwrap();
/// hash.update(&[1,2,3]).unwrap();
/// hash.update(&[4,5,6]).unwrap();
/// ```
pub fn update(&self, data: &[u8]) -> Result<()> {
call_botan! { botan_hash_update(self.obj, data.as_ptr(), data.len()) };
Ok(())
}
/// Finalize the computation, returning the hash of the message
///
/// # Examples
/// ```
/// let 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(&self) -> Result<Vec<u8>> {
let mut output = vec![0; self.output_length];
call_botan! { 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(&self) -> Result<()> {
call_botan! { 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 hash = botan::HashFunction::new("SHA-256").unwrap();
/// hash.update(&[1,2,3]);
/// let 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 mut obj = ptr::null_mut();
call_botan! { botan_hash_copy_state(&mut obj, self.obj) };
Ok(HashFunction { obj: obj, output_length: self.output_length })
}
}