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 fn getrandom(buf: &mut [u8]) -> libc::c_long {
36 fn syscall(number: libc::c_long, ...) -> libc::c_long;
39 #[cfg(target_arch = "x86_64")]
40 const NR_GETRANDOM: libc::c_long = 318;
41 #[cfg(target_arch = "x86")]
42 const NR_GETRANDOM: libc::c_long = 355;
43 #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
44 const NR_GETRANDOM: libc::c_long = 384;
45 #[cfg(target_arch = "aarch64")]
46 const NR_GETRANDOM: libc::c_long = 278;
49 syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
53 #[cfg(not(all(target_os = "linux",
54 any(target_arch = "x86_64",
57 target_arch = "aarch64",
58 target_arch = "powerpc"))))]
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 fn is_getrandom_available() -> bool {
97 use sync::atomic::{AtomicBool, Ordering};
100 static CHECKER: Once = Once::new();
101 static AVAILABLE: AtomicBool = AtomicBool::new(false);
103 CHECKER.call_once(|| {
104 let mut buf: [u8; 0] = [];
105 let result = getrandom(&mut buf);
106 let available = if result == -1 {
107 let err = io::Error::last_os_error().raw_os_error();
108 err != Some(libc::ENOSYS)
112 AVAILABLE.store(available, Ordering::Relaxed);
115 AVAILABLE.load(Ordering::Relaxed)
118 #[cfg(not(all(target_os = "linux",
119 any(target_arch = "x86_64",
122 target_arch = "aarch64",
123 target_arch = "powerpc"))))]
124 fn is_getrandom_available() -> bool { false }
126 /// A random number generator that retrieves randomness straight from
127 /// the operating system. Platform sources:
129 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
130 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
131 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
132 /// service provider with the `PROV_RSA_FULL` type.
133 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
134 /// - OpenBSD: uses the `getentropy(2)` system call.
136 /// This does not block.
143 OsReaderRng(ReaderRng<File>),
147 /// Create a new `OsRng`.
148 pub fn new() -> io::Result<OsRng> {
149 if is_getrandom_available() {
150 return Ok(OsRng { inner: OsGetrandomRng });
153 let reader = try!(File::open("/dev/urandom"));
154 let reader_rng = ReaderRng::new(reader);
156 Ok(OsRng { inner: OsReaderRng(reader_rng) })
161 fn next_u32(&mut self) -> u32 {
163 OsGetrandomRng => getrandom_next_u32(),
164 OsReaderRng(ref mut rng) => rng.next_u32(),
167 fn next_u64(&mut self) -> u64 {
169 OsGetrandomRng => getrandom_next_u64(),
170 OsReaderRng(ref mut rng) => rng.next_u64(),
173 fn fill_bytes(&mut self, v: &mut [u8]) {
175 OsGetrandomRng => getrandom_fill_bytes(v),
176 OsReaderRng(ref mut rng) => rng.fill_bytes(v)
182 #[cfg(target_os = "openbsd")]
190 /// A random number generator that retrieves randomness straight from
191 /// the operating system. Platform sources:
193 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
194 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
195 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
196 /// service provider with the `PROV_RSA_FULL` type.
197 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
198 /// - OpenBSD: uses the `getentropy(2)` system call.
200 /// This does not block.
202 // dummy field to ensure that this struct cannot be constructed outside
208 /// Create a new `OsRng`.
209 pub fn new() -> io::Result<OsRng> {
210 Ok(OsRng { _dummy: () })
215 fn next_u32(&mut self) -> u32 {
217 self.fill_bytes(&mut v);
218 unsafe { mem::transmute(v) }
220 fn next_u64(&mut self) -> u64 {
222 self.fill_bytes(&mut v);
223 unsafe { mem::transmute(v) }
225 fn fill_bytes(&mut self, v: &mut [u8]) {
226 // getentropy(2) permits a maximum buffer size of 256 bytes
227 for s in v.chunks_mut(256) {
229 libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len())
232 panic!("unexpected getentropy error: {}", errno());
239 #[cfg(target_os = "ios")]
241 #[cfg(stage0)] use prelude::v1::*;
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());
388 use sync::mpsc::channel;
395 let mut r = OsRng::new().unwrap();
400 let mut v = [0; 1000];
401 r.fill_bytes(&mut v);
405 fn test_os_rng_tasks() {
407 let mut txs = vec!();
409 let (tx, rx) = channel();
412 thread::spawn(move|| {
413 // wait until all the threads are ready to go.
416 // deschedule to attempt to interleave things as much
417 // as possible (XXX: is this a good test?)
418 let mut r = OsRng::new().unwrap();
420 let mut v = [0; 1000];
427 r.fill_bytes(&mut v);
433 // start all the threads
435 tx.send(()).unwrap();