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
use mbedtls_sys::types::raw_types::{c_int, c_uchar, c_void};
use mbedtls_sys::types::size_t;
pub use mbedtls_sys::HMAC_DRBG_RESEED_INTERVAL as RESEED_INTERVAL;
use mbedtls_sys::{
hmac_drbg_random, hmac_drbg_reseed, hmac_drbg_seed, hmac_drbg_seed_buf,
hmac_drbg_set_prediction_resistance, hmac_drbg_update, HMAC_DRBG_PR_OFF, HMAC_DRBG_PR_ON,
};
use super::{EntropyCallback, RngCallback};
use error::IntoResult;
define!(struct HmacDrbg<'entropy>(hmac_drbg_context) {
fn init=hmac_drbg_init;
fn drop=hmac_drbg_free;
});
#[cfg(feature = "threading")]
unsafe impl<'entropy> Sync for HmacDrbg<'entropy> {}
impl<'entropy> HmacDrbg<'entropy> {
pub fn new<F: EntropyCallback>(
md_info: ::hash::MdInfo,
source: &'entropy mut F,
additional_entropy: Option<&[u8]>,
) -> ::Result<HmacDrbg<'entropy>> {
let mut ret = Self::init();
unsafe {
try!(
hmac_drbg_seed(
&mut ret.inner,
md_info.into(),
Some(F::call),
source.data_ptr(),
additional_entropy
.map(<[_]>::as_ptr)
.unwrap_or(::core::ptr::null()),
additional_entropy.map(<[_]>::len).unwrap_or(0)
).into_result()
)
};
Ok(ret)
}
pub fn from_buf(md_info: ::hash::MdInfo, entropy: &[u8]) -> ::Result<HmacDrbg<'entropy>> {
let mut ret = Self::init();
unsafe {
try!(
hmac_drbg_seed_buf(
&mut ret.inner,
md_info.into(),
entropy.as_ptr(),
entropy.len()
).into_result()
)
};
Ok(ret)
}
pub fn prediction_resistance(&self) -> bool {
if self.inner.prediction_resistance == HMAC_DRBG_PR_OFF {
false
} else {
true
}
}
pub fn set_prediction_resistance(&mut self, pr: bool) {
unsafe {
hmac_drbg_set_prediction_resistance(
&mut self.inner,
if pr {
HMAC_DRBG_PR_ON
} else {
HMAC_DRBG_PR_OFF
},
)
}
}
getter!(entropy_len() -> size_t = .entropy_len);
setter!(set_entropy_len(len: size_t) = hmac_drbg_set_entropy_len);
getter!(reseed_interval() -> c_int = .reseed_interval);
setter!(set_reseed_interval(i: c_int) = hmac_drbg_set_reseed_interval);
pub fn reseed(&mut self, additional_entropy: Option<&[u8]>) -> ::Result<()> {
unsafe {
try!(
hmac_drbg_reseed(
&mut self.inner,
additional_entropy
.map(<[_]>::as_ptr)
.unwrap_or(::core::ptr::null()),
additional_entropy.map(<[_]>::len).unwrap_or(0)
).into_result()
)
};
Ok(())
}
pub fn update(&mut self, entropy: &[u8]) {
unsafe { hmac_drbg_update(&mut self.inner, entropy.as_ptr(), entropy.len()) };
}
}
impl<'entropy> RngCallback for HmacDrbg<'entropy> {
#[inline(always)]
unsafe extern "C" fn call(user_data: *mut c_void, data: *mut c_uchar, len: size_t) -> c_int {
hmac_drbg_random(user_data, data, len)
}
fn data_ptr(&mut self) -> *mut c_void {
&mut self.inner as *mut _ as *mut _
}
}