mod hmac_drbg;
pub use hmac_drbg::HmacDrbg;
pub trait RngCore {
fn fill_bytes(&mut self, dest: &mut [u8]);
#[inline]
fn next_u32(&mut self) -> u32 {
let mut b = [0u8; 4];
self.fill_bytes(&mut b);
u32::from_le_bytes(b)
}
#[inline]
fn next_u64(&mut self) -> u64 {
let mut b = [0u8; 8];
self.fill_bytes(&mut b);
u64::from_le_bytes(b)
}
}
pub trait CryptoRng {}
#[cfg(all(feature = "std", unix))]
#[derive(Debug, Clone, Copy, Default)]
pub struct OsRng;
#[cfg(all(feature = "std", unix))]
impl RngCore for OsRng {
fn fill_bytes(&mut self, dest: &mut [u8]) {
use std::io::Read;
std::fs::File::open("/dev/urandom")
.and_then(|mut f| f.read_exact(dest))
.expect("failed to read entropy from /dev/urandom");
}
}
#[cfg(all(feature = "std", unix))]
impl CryptoRng for OsRng {}
#[cfg(all(feature = "std", windows))]
mod os_windows {
#![allow(unsafe_code)]
use super::{CryptoRng, RngCore};
#[link(name = "bcryptprimitives", kind = "raw-dylib")]
unsafe extern "system" {
fn ProcessPrng(data: *mut u8, len: usize) -> i32;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct OsRng;
impl RngCore for OsRng {
fn fill_bytes(&mut self, dest: &mut [u8]) {
if dest.is_empty() {
return;
}
let ok = unsafe { ProcessPrng(dest.as_mut_ptr(), dest.len()) };
assert!(ok != 0, "ProcessPrng failed to produce entropy");
}
}
impl CryptoRng for OsRng {}
}
#[cfg(all(feature = "std", windows))]
pub use os_windows::OsRng;
#[cfg(all(test, feature = "std", any(unix, windows)))]
mod tests {
use super::*;
#[test]
fn os_rng_fills_and_varies() {
let mut rng = OsRng;
let mut a = [0u8; 32];
let mut b = [0u8; 32];
rng.fill_bytes(&mut a);
rng.fill_bytes(&mut b);
assert_ne!(a, [0u8; 32]);
assert_ne!(a, b);
}
}