crate::ix!();
pub struct RNGInnerState {
state: [u8; 32],
counter: u64,
strongly_seeded: bool,
}
impl Default for RNGInnerState {
fn default() -> Self {
Self {
state: [0; 32],
counter: 0,
strongly_seeded: false,
}
}
}
#[derive(Default)]
pub struct RNGStateEvents {
hasher: Sha256,
}
pub struct RNGState {
inner: Mutex<RNGInnerState>,
events: Mutex<RNGStateEvents>,
}
impl Default for RNGState {
fn default() -> Self {
init_hardware_rand();
Self {
inner: Mutex::new(RNGInnerState::default()),
events: Mutex::new(RNGStateEvents::default()),
}
}
}
impl RNGState {
pub fn add_event(&mut self, event_info: u32) {
let mut events = self.events.lock();
events.hasher.write_ptr(
&event_info as *const _ as *const u8,
size_of_val(&event_info)
);
let perfcounter: u32
= (get_performance_counter() & 0xffffffff).try_into().unwrap();
events.hasher.write_ptr(
&perfcounter as *const _ as *const u8,
size_of_val(&perfcounter)
);
}
pub fn seed_events(&mut self, hasher: &mut Sha512) {
let mut events = self.events.lock();
let mut events_hash: [u8; 32] = [0; 32];
events.hasher.finalize(&mut events_hash);
events.hasher.write_ptr(events_hash.as_mut_ptr(), 32);
events.hasher.reset();
events.hasher.write_ptr(events_hash.as_mut_ptr(), 32);
}
pub fn mix_extract(&mut self,
out: &mut [u8],
num: usize,
mut hasher: Sha512,
strong_seed: bool) -> bool {
assert!{num <= 32};
type BufType = [u8; 64];
const_assert!{
size_of::<BufType>() == SHA512_OUTPUT_SIZE,
};
let mut buf: BufType = [0; 64];
let mut ret: bool = false;
{
let mut inner = self.inner.lock();
inner.strongly_seeded |= strong_seed;
ret = inner.strongly_seeded;
hasher.write(
inner.state.as_ptr(),
32
);
hasher.write(
&mut inner.counter as *mut u64 as *mut u8,
size_of_val(&inner.counter)
);
inner.counter += 1;
hasher.finalize(&mut buf);
unsafe {
libc::memcpy(
inner.state.as_mut_ptr() as *mut c_void,
buf.as_ptr().add(32) as *const c_void,
32
);
}
}
if num != 0 {
assert!{out.len() != 0};
unsafe {
libc::memcpy(
out.as_mut_ptr() as *mut c_void,
buf.as_ptr() as *const c_void,
num
);
}
}
hasher.reset();
memory_cleanse(buf.as_mut_ptr() as *mut c_void, 64);
ret
}
}
lazy_static!{
pub static ref G_RNG: Arc<Mutex<Box<RNGState,SecureAllocator>>>
= Arc::new(
Mutex::new(
Box::new_in(RNGState::default(), SECURE_ALLOCATOR.clone())
)
);
}
#[cfg(test)]
mod state_spec {
use super::*;
#[traced_test]
fn mix_extract_updates_state_and_respects_strong_seed_flag() {
let mut rng = RNGState::default();
let mut h = Sha512::default();
let mut out = [0u8; 16];
let out_len = out.len();
let strong = rng.mix_extract(&mut out, out_len, h.clone(), false);
assert!(!strong);
assert_eq!(out.len(), 16);
let strong2 = rng.mix_extract(&mut out, out_len, h.clone(), true);
assert!(strong2);
let strong3 = rng.mix_extract(&mut out, out_len, h, false);
assert!(strong3);
}
}