diff options
| author | bors <bors@rust-lang.org> | 2016-02-19 10:58:53 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-02-19 10:58:53 +0000 |
| commit | d5e2e5fbbc4b856af4a5146b1b5887f58a8256ad (patch) | |
| tree | c4dbb8bedacfa45974f9ccece93a26cd5c493ed7 /src/libstd/sys | |
| parent | 15611f75ca49bd6c40ecbe84caa44cb74a9781f4 (diff) | |
| parent | 34dfc3991db26a363657f0bd56db1669032468b3 (diff) | |
| download | rust-d5e2e5fbbc4b856af4a5146b1b5887f58a8256ad.tar.gz rust-d5e2e5fbbc4b856af4a5146b1b5887f58a8256ad.zip | |
Auto merge of #31738 - seanmonstar:sys-rand, r=alexcrichton
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/unix/rand.rs | 273 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/rand.rs | 72 |
4 files changed, 347 insertions, 0 deletions
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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<File>), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result<OsRng> { + 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<OsRng> { + 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<OsRng> { + 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<OsRng> { + 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()); + } + } +} |
