From 34dfc3991db26a363657f0bd56db1669032468b3 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Wed, 17 Feb 2016 13:56:16 -0800 Subject: std: restructure rand os code into sys modules --- src/libstd/rand/mod.rs | 95 ++++++++- src/libstd/rand/os.rs | 439 ----------------------------------------- src/libstd/sys/unix/mod.rs | 1 + src/libstd/sys/unix/rand.rs | 273 +++++++++++++++++++++++++ src/libstd/sys/windows/mod.rs | 1 + src/libstd/sys/windows/rand.rs | 72 +++++++ 6 files changed, 440 insertions(+), 441 deletions(-) delete mode 100644 src/libstd/rand/os.rs create mode 100644 src/libstd/sys/unix/rand.rs create mode 100644 src/libstd/sys/windows/rand.rs (limited to 'src/libstd') diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 21e60420c18..3f14fcd239f 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -62,6 +62,7 @@ use cell::RefCell; use io; use mem; use rc::Rc; +use sys; #[cfg(target_pointer_width = "32")] use core_rand::IsaacRng as IsaacWordRng; @@ -71,9 +72,7 @@ use core_rand::Isaac64Rng as IsaacWordRng; 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 @@ impl Rng for ThreadRng { 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/rand/os.rs b/src/libstd/rand/os.rs deleted file mode 100644 index 8a422246514..00000000000 --- a/src/libstd/rand/os.rs +++ /dev/null @@ -1,439 +0,0 @@ -// 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. - -//! 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")))] -mod imp { - use self::OsRngInner::*; - - use fs::File; - use io; - use libc; - use mem; - use rand::Rng; - use rand::reader::ReaderRng; - use sys::os::errno; - - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64")))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - #[cfg(target_arch = "x86_64")] - const NR_GETRANDOM: libc::c_long = 318; - #[cfg(target_arch = "x86")] - const NR_GETRANDOM: libc::c_long = 355; - #[cfg(target_arch = "arm")] - const NR_GETRANDOM: libc::c_long = 384; - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - const NR_GETRANDOM: libc::c_long = 359; - #[cfg(target_arch = "aarch64")] - const NR_GETRANDOM: libc::c_long = 278; - - unsafe { - libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0) - } - } - - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64"))))] - fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } - - fn getrandom_fill_bytes(v: &mut [u8]) { - let mut read = 0; - while read < v.len() { - let result = getrandom(&mut v[read..]); - if result == -1 { - let err = errno() as libc::c_int; - if err == libc::EINTR { - continue; - } else { - panic!("unexpected getrandom error: {}", err); - } - } else { - read += result as usize; - } - } - } - - fn getrandom_next_u32() -> u32 { - let mut buf: [u8; 4] = [0; 4]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } - } - - fn getrandom_next_u64() -> u64 { - let mut buf: [u8; 8] = [0; 8]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } - } - - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64")))] - fn is_getrandom_available() -> bool { - use sync::atomic::{AtomicBool, Ordering}; - use sync::Once; - - static CHECKER: Once = Once::new(); - static AVAILABLE: AtomicBool = AtomicBool::new(false); - - CHECKER.call_once(|| { - let mut buf: [u8; 0] = []; - let result = getrandom(&mut buf); - let available = if result == -1 { - let err = io::Error::last_os_error().raw_os_error(); - err != Some(libc::ENOSYS) - } else { - true - }; - AVAILABLE.store(available, Ordering::Relaxed); - }); - - AVAILABLE.load(Ordering::Relaxed) - } - - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - 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, - } - - enum OsRngInner { - OsGetrandomRng, - OsReaderRng(ReaderRng), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result { - if is_getrandom_available() { - return Ok(OsRng { inner: OsGetrandomRng }); - } - - let reader = try!(File::open("/dev/urandom")); - let reader_rng = ReaderRng::new(reader); - - Ok(OsRng { inner: OsReaderRng(reader_rng) }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - match self.inner { - OsGetrandomRng => getrandom_next_u32(), - OsReaderRng(ref mut rng) => rng.next_u32(), - } - } - fn next_u64(&mut self) -> u64 { - match self.inner { - OsGetrandomRng => getrandom_next_u64(), - OsReaderRng(ref mut rng) => rng.next_u64(), - } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - match self.inner { - OsGetrandomRng => getrandom_fill_bytes(v), - OsReaderRng(ref mut rng) => rng.fill_bytes(v) - } - } - } -} - -#[cfg(target_os = "openbsd")] -mod imp { - use io; - use libc; - use mem; - 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 - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result { - Ok(OsRng { _dummy: () }) - } - } - - 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]) { - // getentropy(2) permits a maximum buffer size of 256 bytes - for s in v.chunks_mut(256) { - let ret = unsafe { - libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) - }; - if ret == -1 { - panic!("unexpected getentropy error: {}", errno()); - } - } - } - } -} - -#[cfg(target_os = "ios")] -mod imp { - use io; - use mem; - use ptr; - 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 - _dummy: (), - } - - enum SecRandom {} - - #[allow(non_upper_case_globals)] - const kSecRandomDefault: *const SecRandom = ptr::null(); - - #[link(name = "Security", kind = "framework")] - #[cfg(not(cargobuild))] - extern {} - - extern { - fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, bytes: *mut u8) -> c_int; - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result { - Ok(OsRng { _dummy: () }) - } - } - - 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 { - SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, - v.as_mut_ptr()) - }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - } - } -} - -#[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/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 9cae36fb726..c332d6035ee 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -42,6 +42,7 @@ pub mod os; 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/unix/rand.rs b/src/libstd/sys/unix/rand.rs new file mode 100644 index 00000000000..fa504ade084 --- /dev/null +++ b/src/libstd/sys/unix/rand.rs @@ -0,0 +1,273 @@ +// 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. + +pub use self::imp::OsRng; + +#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] +mod imp { + use self::OsRngInner::*; + + use fs::File; + use io; + use libc; + use mem; + use rand::Rng; + use rand::reader::ReaderRng; + use sys::os::errno; + + #[cfg(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "powerpc64")))] + fn getrandom(buf: &mut [u8]) -> libc::c_long { + #[cfg(target_arch = "x86_64")] + const NR_GETRANDOM: libc::c_long = 318; + #[cfg(target_arch = "x86")] + const NR_GETRANDOM: libc::c_long = 355; + #[cfg(target_arch = "arm")] + const NR_GETRANDOM: libc::c_long = 384; + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] + const NR_GETRANDOM: libc::c_long = 359; + #[cfg(target_arch = "aarch64")] + const NR_GETRANDOM: libc::c_long = 278; + + unsafe { + libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0) + } + } + + #[cfg(not(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "powerpc64"))))] + fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } + + fn getrandom_fill_bytes(v: &mut [u8]) { + let mut read = 0; + while read < v.len() { + let result = getrandom(&mut v[read..]); + if result == -1 { + let err = errno() as libc::c_int; + if err == libc::EINTR { + continue; + } else { + panic!("unexpected getrandom error: {}", err); + } + } else { + read += result as usize; + } + } + } + + fn getrandom_next_u32() -> u32 { + let mut buf: [u8; 4] = [0; 4]; + getrandom_fill_bytes(&mut buf); + unsafe { mem::transmute::<[u8; 4], u32>(buf) } + } + + fn getrandom_next_u64() -> u64 { + let mut buf: [u8; 8] = [0; 8]; + getrandom_fill_bytes(&mut buf); + unsafe { mem::transmute::<[u8; 8], u64>(buf) } + } + + #[cfg(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "powerpc64")))] + fn is_getrandom_available() -> bool { + use sync::atomic::{AtomicBool, Ordering}; + use sync::Once; + + static CHECKER: Once = Once::new(); + static AVAILABLE: AtomicBool = AtomicBool::new(false); + + CHECKER.call_once(|| { + let mut buf: [u8; 0] = []; + let result = getrandom(&mut buf); + let available = if result == -1 { + let err = io::Error::last_os_error().raw_os_error(); + err != Some(libc::ENOSYS) + } else { + true + }; + AVAILABLE.store(available, Ordering::Relaxed); + }); + + AVAILABLE.load(Ordering::Relaxed) + } + + #[cfg(not(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "powerpc", + target_arch = "powerpc64"))))] + fn is_getrandom_available() -> bool { false } + + pub struct OsRng { + inner: OsRngInner, + } + + enum OsRngInner { + OsGetrandomRng, + OsReaderRng(ReaderRng), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + if is_getrandom_available() { + return Ok(OsRng { inner: OsGetrandomRng }); + } + + let reader = try!(File::open("/dev/urandom")); + let reader_rng = ReaderRng::new(reader); + + Ok(OsRng { inner: OsReaderRng(reader_rng) }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + match self.inner { + OsGetrandomRng => getrandom_next_u32(), + OsReaderRng(ref mut rng) => rng.next_u32(), + } + } + fn next_u64(&mut self) -> u64 { + match self.inner { + OsGetrandomRng => getrandom_next_u64(), + OsReaderRng(ref mut rng) => rng.next_u64(), + } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + match self.inner { + OsGetrandomRng => getrandom_fill_bytes(v), + OsReaderRng(ref mut rng) => rng.fill_bytes(v) + } + } + } +} + +#[cfg(target_os = "openbsd")] +mod imp { + use io; + use libc; + use mem; + use sys::os::errno; + use rand::Rng; + + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + Ok(OsRng { _dummy: () }) + } + } + + 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]) { + // getentropy(2) permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let ret = unsafe { + libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) + }; + if ret == -1 { + panic!("unexpected getentropy error: {}", errno()); + } + } + } + } +} + +#[cfg(target_os = "ios")] +mod imp { + use io; + use mem; + use ptr; + use rand::Rng; + use libc::{c_int, size_t}; + + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + enum SecRandom {} + + #[allow(non_upper_case_globals)] + const kSecRandomDefault: *const SecRandom = ptr::null(); + + #[link(name = "Security", kind = "framework")] + #[cfg(not(cargobuild))] + extern {} + + extern { + fn SecRandomCopyBytes(rnd: *const SecRandom, + count: size_t, bytes: *mut u8) -> c_int; + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + Ok(OsRng { _dummy: () }) + } + } + + 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 { + SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, + v.as_mut_ptr()) + }; + if ret == -1 { + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); + } + } + } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9ecef5ee92c..765e6e09427 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -33,6 +33,7 @@ pub mod os; 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 00000000000..fdd260b6e28 --- /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()); + } + } +} -- cgit 1.4.1-3-g733a5