diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 21e60420c186adb48a19058884006bcd763f2455..3f14fcd239f1d0ceb2d6d36f32da74a3a845c345 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -62,6 +62,7 @@ use io; use mem; use rc::Rc; +use sys; #[cfg(target_pointer_width = "32")] use core_rand::IsaacRng as IsaacWordRng; @@ -71,9 +72,7 @@ pub use core_rand::{Rand, Rng, SeedableRng}; pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng}; pub use core_rand::reseeding; -pub use rand::os::OsRng; -pub mod os; pub mod reader; /// The standard RNG. This is designed to be efficient on the current @@ -185,3 +184,95 @@ fn fill_bytes(&mut self, bytes: &mut [u8]) { self.rng.borrow_mut().fill_bytes(bytes) } } + +/// A random number generator that retrieves randomness straight from +/// the operating system. Platform sources: +/// +/// - Unix-like systems (Linux, Android, Mac OSX): read directly from +/// `/dev/urandom`, or from `getrandom(2)` system call if available. +/// - Windows: calls `CryptGenRandom`, using the default cryptographic +/// service provider with the `PROV_RSA_FULL` type. +/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. +/// - OpenBSD: uses the `getentropy(2)` system call. +/// +/// This does not block. +pub struct OsRng(sys::rand::OsRng); + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + sys::rand::OsRng::new().map(OsRng) + } +} + +impl Rng for OsRng { + #[inline] + fn next_u32(&mut self) -> u32 { + self.0.next_u32() + } + + #[inline] + fn next_u64(&mut self) -> u64 { + self.0.next_u64() + } + + #[inline] + fn fill_bytes(&mut self, bytes: &mut [u8]) { + self.0.fill_bytes(bytes) + } +} + + +#[cfg(test)] +mod tests { + use sync::mpsc::channel; + use rand::Rng; + use super::OsRng; + use thread; + + #[test] + fn test_os_rng() { + let mut r = OsRng::new().unwrap(); + + r.next_u32(); + r.next_u64(); + + let mut v = [0; 1000]; + r.fill_bytes(&mut v); + } + + #[test] + fn test_os_rng_tasks() { + + let mut txs = vec!(); + for _ in 0..20 { + let (tx, rx) = channel(); + txs.push(tx); + + thread::spawn(move|| { + // wait until all the threads are ready to go. + rx.recv().unwrap(); + + // deschedule to attempt to interleave things as much + // as possible (XXX: is this a good test?) + let mut r = OsRng::new().unwrap(); + thread::yield_now(); + let mut v = [0; 1000]; + + for _ in 0..100 { + r.next_u32(); + thread::yield_now(); + r.next_u64(); + thread::yield_now(); + r.fill_bytes(&mut v); + thread::yield_now(); + } + }); + } + + // start all the threads + for tx in &txs { + tx.send(()).unwrap(); + } + } +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9cae36fb7260b45763a4ee5b4d42cf9f28aee244..c332d6035ee8d8d789ccf681bbae8c754cdd55a8 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -42,6 +42,7 @@ pub mod os_str; pub mod pipe; pub mod process; +pub mod rand; pub mod rwlock; pub mod stack_overflow; pub mod thread; diff --git a/src/libstd/rand/os.rs b/src/libstd/sys/unix/rand.rs similarity index 60% rename from src/libstd/rand/os.rs rename to src/libstd/sys/unix/rand.rs index 8a422246514bcc833c3734cc08b24c705a77fcbe..fa504ade084fc3f3b4d043f318d09df9342625e6 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/sys/unix/rand.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Interfaces to the operating system provided random number -//! generators. - pub use self::imp::OsRng; #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] @@ -125,17 +122,6 @@ fn is_getrandom_available() -> bool { target_arch = "powerpc64"))))] fn is_getrandom_available() -> bool { false } - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. - /// - OpenBSD: uses the `getentropy(2)` system call. - /// - /// This does not block. pub struct OsRng { inner: OsRngInner, } @@ -189,17 +175,6 @@ mod imp { use sys::os::errno; use rand::Rng; - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. - /// - OpenBSD: uses the `getentropy(2)` system call. - /// - /// This does not block. pub struct OsRng { // dummy field to ensure that this struct cannot be constructed outside // of this module @@ -246,17 +221,6 @@ mod imp { use rand::Rng; use libc::{c_int, size_t}; - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. - /// - OpenBSD: uses the `getentropy(2)` system call. - /// - /// This does not block. pub struct OsRng { // dummy field to ensure that this struct cannot be constructed outside // of this module @@ -307,133 +271,3 @@ fn fill_bytes(&mut self, v: &mut [u8]) { } } } - -#[cfg(windows)] -mod imp { - use io; - use mem; - use rand::Rng; - use sys::c; - - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed. - /// - OpenBSD: uses the `getentropy(2)` system call. - /// - /// This does not block. - pub struct OsRng { - hcryptprov: c::HCRYPTPROV - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result { - let mut hcp = 0; - let ret = unsafe { - c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR, - c::PROV_RSA_FULL, - c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT) - }; - - if ret == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(OsRng { hcryptprov: hcp }) - } - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let ret = unsafe { - c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD, - v.as_mut_ptr()) - }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - } - } - - impl Drop for OsRng { - fn drop(&mut self) { - let ret = unsafe { - c::CryptReleaseContext(self.hcryptprov, 0) - }; - if ret == 0 { - panic!("couldn't release context: {}", - io::Error::last_os_error()); - } - } - } -} - -#[cfg(test)] -mod tests { - use sync::mpsc::channel; - use rand::Rng; - use super::OsRng; - use thread; - - #[test] - fn test_os_rng() { - let mut r = OsRng::new().unwrap(); - - r.next_u32(); - r.next_u64(); - - let mut v = [0; 1000]; - r.fill_bytes(&mut v); - } - - #[test] - fn test_os_rng_tasks() { - - let mut txs = vec!(); - for _ in 0..20 { - let (tx, rx) = channel(); - txs.push(tx); - - thread::spawn(move|| { - // wait until all the threads are ready to go. - rx.recv().unwrap(); - - // deschedule to attempt to interleave things as much - // as possible (XXX: is this a good test?) - let mut r = OsRng::new().unwrap(); - thread::yield_now(); - let mut v = [0; 1000]; - - for _ in 0..100 { - r.next_u32(); - thread::yield_now(); - r.next_u64(); - thread::yield_now(); - r.fill_bytes(&mut v); - thread::yield_now(); - } - }); - } - - // start all the threads - for tx in &txs { - tx.send(()).unwrap(); - } - } -} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9ecef5ee92c714c6e1cbb3b9ca7be9a1046fbf40..765e6e09427641cc127e38fc30a02409be033bed 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -33,6 +33,7 @@ pub mod os_str; pub mod pipe; pub mod process; +pub mod rand; pub mod rwlock; pub mod stack_overflow; pub mod thread; diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs new file mode 100644 index 0000000000000000000000000000000000000000..fdd260b6e28844959fed6fd2860fde4a4194c410 --- /dev/null +++ b/src/libstd/sys/windows/rand.rs @@ -0,0 +1,72 @@ +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use io; +use mem; +use rand::Rng; +use sys::c; + +pub struct OsRng { + hcryptprov: c::HCRYPTPROV +} + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + let mut hcp = 0; + let ret = unsafe { + c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR, + c::PROV_RSA_FULL, + c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT) + }; + + if ret == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(OsRng { hcryptprov: hcp }) + } + } +} + +impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let mut v = [0; 4]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn next_u64(&mut self) -> u64 { + let mut v = [0; 8]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let ret = unsafe { + c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD, + v.as_mut_ptr()) + }; + if ret == 0 { + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); + } + } +} + +impl Drop for OsRng { + fn drop(&mut self) { + let ret = unsafe { + c::CryptReleaseContext(self.hcryptprov, 0) + }; + if ret == 0 { + panic!("couldn't release context: {}", + io::Error::last_os_error()); + } + } +}