1 // Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Interfaces to the operating system provided random number
14 pub use self::imp::OsRng;
16 #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
18 use self::OsRngInner::*;
25 use rand::reader::ReaderRng;
28 #[cfg(all(target_os = "linux",
29 any(target_arch = "x86_64",
32 target_arch = "aarch64",
33 target_arch = "powerpc",
34 target_arch = "powerpc64")))]
35 fn getrandom(buf: &mut [u8]) -> libc::c_long {
36 #[cfg(target_arch = "x86_64")]
37 const NR_GETRANDOM: libc::c_long = 318;
38 #[cfg(target_arch = "x86")]
39 const NR_GETRANDOM: libc::c_long = 355;
40 #[cfg(target_arch = "arm")]
41 const NR_GETRANDOM: libc::c_long = 384;
42 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
43 const NR_GETRANDOM: libc::c_long = 359;
44 #[cfg(target_arch = "aarch64")]
45 const NR_GETRANDOM: libc::c_long = 278;
48 libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
52 #[cfg(not(all(target_os = "linux",
53 any(target_arch = "x86_64",
56 target_arch = "aarch64",
57 target_arch = "powerpc",
58 target_arch = "powerpc64"))))]
59 fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
61 fn getrandom_fill_bytes(v: &mut [u8]) {
63 while read < v.len() {
64 let result = getrandom(&mut v[read..]);
66 let err = errno() as libc::c_int;
67 if err == libc::EINTR {
70 panic!("unexpected getrandom error: {}", err);
73 read += result as usize;
78 fn getrandom_next_u32() -> u32 {
79 let mut buf: [u8; 4] = [0; 4];
80 getrandom_fill_bytes(&mut buf);
81 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
84 fn getrandom_next_u64() -> u64 {
85 let mut buf: [u8; 8] = [0; 8];
86 getrandom_fill_bytes(&mut buf);
87 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
90 #[cfg(all(target_os = "linux",
91 any(target_arch = "x86_64",
94 target_arch = "aarch64",
95 target_arch = "powerpc",
96 target_arch = "powerpc64")))]
97 fn is_getrandom_available() -> bool {
98 use sync::atomic::{AtomicBool, Ordering};
101 static CHECKER: Once = Once::new();
102 static AVAILABLE: AtomicBool = AtomicBool::new(false);
104 CHECKER.call_once(|| {
105 let mut buf: [u8; 0] = [];
106 let result = getrandom(&mut buf);
107 let available = if result == -1 {
108 let err = io::Error::last_os_error().raw_os_error();
109 err != Some(libc::ENOSYS)
113 AVAILABLE.store(available, Ordering::Relaxed);
116 AVAILABLE.load(Ordering::Relaxed)
119 #[cfg(not(all(target_os = "linux",
120 any(target_arch = "x86_64",
123 target_arch = "aarch64",
124 target_arch = "powerpc",
125 target_arch = "powerpc64"))))]
126 fn is_getrandom_available() -> bool { false }
128 /// A random number generator that retrieves randomness straight from
129 /// the operating system. Platform sources:
131 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
132 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
133 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
134 /// service provider with the `PROV_RSA_FULL` type.
135 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
136 /// - OpenBSD: uses the `getentropy(2)` system call.
138 /// This does not block.
145 OsReaderRng(ReaderRng<File>),
149 /// Create a new `OsRng`.
150 pub fn new() -> io::Result<OsRng> {
151 if is_getrandom_available() {
152 return Ok(OsRng { inner: OsGetrandomRng });
155 let reader = try!(File::open("/dev/urandom"));
156 let reader_rng = ReaderRng::new(reader);
158 Ok(OsRng { inner: OsReaderRng(reader_rng) })
163 fn next_u32(&mut self) -> u32 {
165 OsGetrandomRng => getrandom_next_u32(),
166 OsReaderRng(ref mut rng) => rng.next_u32(),
169 fn next_u64(&mut self) -> u64 {
171 OsGetrandomRng => getrandom_next_u64(),
172 OsReaderRng(ref mut rng) => rng.next_u64(),
175 fn fill_bytes(&mut self, v: &mut [u8]) {
177 OsGetrandomRng => getrandom_fill_bytes(v),
178 OsReaderRng(ref mut rng) => rng.fill_bytes(v)
184 #[cfg(target_os = "openbsd")]
192 /// A random number generator that retrieves randomness straight from
193 /// the operating system. Platform sources:
195 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
196 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
197 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
198 /// service provider with the `PROV_RSA_FULL` type.
199 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
200 /// - OpenBSD: uses the `getentropy(2)` system call.
202 /// This does not block.
204 // dummy field to ensure that this struct cannot be constructed outside
210 /// Create a new `OsRng`.
211 pub fn new() -> io::Result<OsRng> {
212 Ok(OsRng { _dummy: () })
217 fn next_u32(&mut self) -> u32 {
219 self.fill_bytes(&mut v);
220 unsafe { mem::transmute(v) }
222 fn next_u64(&mut self) -> u64 {
224 self.fill_bytes(&mut v);
225 unsafe { mem::transmute(v) }
227 fn fill_bytes(&mut self, v: &mut [u8]) {
228 // getentropy(2) permits a maximum buffer size of 256 bytes
229 for s in v.chunks_mut(256) {
231 libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
234 panic!("unexpected getentropy error: {}", errno());
241 #[cfg(target_os = "ios")]
247 use libc::{c_int, size_t};
249 /// A random number generator that retrieves randomness straight from
250 /// the operating system. Platform sources:
252 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
253 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
254 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
255 /// service provider with the `PROV_RSA_FULL` type.
256 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
257 /// - OpenBSD: uses the `getentropy(2)` system call.
259 /// This does not block.
261 // dummy field to ensure that this struct cannot be constructed outside
268 #[allow(non_upper_case_globals)]
269 const kSecRandomDefault: *const SecRandom = ptr::null();
271 #[link(name = "Security", kind = "framework")]
273 fn SecRandomCopyBytes(rnd: *const SecRandom,
274 count: size_t, bytes: *mut u8) -> c_int;
278 /// Create a new `OsRng`.
279 pub fn new() -> io::Result<OsRng> {
280 Ok(OsRng { _dummy: () })
285 fn next_u32(&mut self) -> u32 {
287 self.fill_bytes(&mut v);
288 unsafe { mem::transmute(v) }
290 fn next_u64(&mut self) -> u64 {
292 self.fill_bytes(&mut v);
293 unsafe { mem::transmute(v) }
295 fn fill_bytes(&mut self, v: &mut [u8]) {
297 SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
301 panic!("couldn't generate random bytes: {}",
302 io::Error::last_os_error());
315 /// A random number generator that retrieves randomness straight from
316 /// the operating system. Platform sources:
318 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
319 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
320 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
321 /// service provider with the `PROV_RSA_FULL` type.
322 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
323 /// - OpenBSD: uses the `getentropy(2)` system call.
325 /// This does not block.
327 hcryptprov: c::HCRYPTPROV
331 /// Create a new `OsRng`.
332 pub fn new() -> io::Result<OsRng> {
335 c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
337 c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
341 Err(io::Error::last_os_error())
343 Ok(OsRng { hcryptprov: hcp })
349 fn next_u32(&mut self) -> u32 {
351 self.fill_bytes(&mut v);
352 unsafe { mem::transmute(v) }
354 fn next_u64(&mut self) -> u64 {
356 self.fill_bytes(&mut v);
357 unsafe { mem::transmute(v) }
359 fn fill_bytes(&mut self, v: &mut [u8]) {
361 c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
365 panic!("couldn't generate random bytes: {}",
366 io::Error::last_os_error());
371 impl Drop for OsRng {
374 c::CryptReleaseContext(self.hcryptprov, 0)
377 panic!("couldn't release context: {}",
378 io::Error::last_os_error());
386 use sync::mpsc::channel;
393 let mut r = OsRng::new().unwrap();
398 let mut v = [0; 1000];
399 r.fill_bytes(&mut v);
403 fn test_os_rng_tasks() {
405 let mut txs = vec!();
407 let (tx, rx) = channel();
410 thread::spawn(move|| {
411 // wait until all the threads are ready to go.
414 // deschedule to attempt to interleave things as much
415 // as possible (XXX: is this a good test?)
416 let mut r = OsRng::new().unwrap();
418 let mut v = [0; 1000];
425 r.fill_bytes(&mut v);
431 // start all the threads
433 tx.send(()).unwrap();