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 pub use self::imp::OsRng;
15 fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
16 let mut buf: [u8; 4] = [0; 4];
18 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
21 fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
22 let mut buf: [u8; 8] = [0; 8];
24 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
28 not(target_os = "ios"),
29 not(target_os = "openbsd"),
30 not(target_os = "freebsd"),
31 not(target_os = "fuchsia")))]
33 use self::OsRngInner::*;
34 use super::{next_u32, next_u64};
40 use rand::reader::ReaderRng;
43 #[cfg(all(target_os = "linux",
44 any(target_arch = "x86_64",
47 target_arch = "aarch64",
48 target_arch = "powerpc",
49 target_arch = "powerpc64",
50 target_arch = "s390x")))]
51 fn getrandom(buf: &mut [u8]) -> libc::c_long {
52 #[cfg(target_arch = "x86_64")]
53 const NR_GETRANDOM: libc::c_long = 318;
54 #[cfg(target_arch = "x86")]
55 const NR_GETRANDOM: libc::c_long = 355;
56 #[cfg(target_arch = "arm")]
57 const NR_GETRANDOM: libc::c_long = 384;
58 #[cfg(target_arch = "s390x")]
59 const NR_GETRANDOM: libc::c_long = 349;
60 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
61 const NR_GETRANDOM: libc::c_long = 359;
62 #[cfg(target_arch = "aarch64")]
63 const NR_GETRANDOM: libc::c_long = 278;
65 const GRND_NONBLOCK: libc::c_uint = 0x0001;
68 libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)
72 #[cfg(not(all(target_os = "linux",
73 any(target_arch = "x86_64",
76 target_arch = "aarch64",
77 target_arch = "powerpc",
78 target_arch = "powerpc64",
79 target_arch = "s390x"))))]
80 fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
82 fn getrandom_fill_bytes(v: &mut [u8]) {
84 while read < v.len() {
85 let result = getrandom(&mut v[read..]);
87 let err = errno() as libc::c_int;
88 if err == libc::EINTR {
90 } else if err == libc::EAGAIN {
91 // if getrandom() returns EAGAIN it would have blocked
92 // because the non-blocking pool (urandom) has not
93 // initialized in the kernel yet due to a lack of entropy
94 // the fallback we do here is to avoid blocking applications
95 // which could depend on this call without ever knowing
96 // they do and don't have a work around. The PRNG of
97 // /dev/urandom will still be used but not over a completely
99 let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom");
100 let mut reader_rng = ReaderRng::new(reader);
101 reader_rng.fill_bytes(&mut v[read..]);
104 panic!("unexpected getrandom error: {}", err);
107 read += result as usize;
112 #[cfg(all(target_os = "linux",
113 any(target_arch = "x86_64",
116 target_arch = "aarch64",
117 target_arch = "powerpc",
118 target_arch = "powerpc64",
119 target_arch = "s390x")))]
120 fn is_getrandom_available() -> bool {
121 use sync::atomic::{AtomicBool, Ordering};
124 static CHECKER: Once = Once::new();
125 static AVAILABLE: AtomicBool = AtomicBool::new(false);
127 CHECKER.call_once(|| {
128 let mut buf: [u8; 0] = [];
129 let result = getrandom(&mut buf);
130 let available = if result == -1 {
131 let err = io::Error::last_os_error().raw_os_error();
132 err != Some(libc::ENOSYS)
136 AVAILABLE.store(available, Ordering::Relaxed);
139 AVAILABLE.load(Ordering::Relaxed)
142 #[cfg(not(all(target_os = "linux",
143 any(target_arch = "x86_64",
146 target_arch = "aarch64",
147 target_arch = "powerpc",
148 target_arch = "powerpc64",
149 target_arch = "s390x"))))]
150 fn is_getrandom_available() -> bool { false }
158 OsReaderRng(ReaderRng<File>),
162 /// Create a new `OsRng`.
163 pub fn new() -> io::Result<OsRng> {
164 if is_getrandom_available() {
165 return Ok(OsRng { inner: OsGetrandomRng });
168 let reader = File::open("/dev/urandom")?;
169 let reader_rng = ReaderRng::new(reader);
171 Ok(OsRng { inner: OsReaderRng(reader_rng) })
176 fn next_u32(&mut self) -> u32 {
178 OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
179 OsReaderRng(ref mut rng) => rng.next_u32(),
182 fn next_u64(&mut self) -> u64 {
184 OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
185 OsReaderRng(ref mut rng) => rng.next_u64(),
188 fn fill_bytes(&mut self, v: &mut [u8]) {
190 OsGetrandomRng => getrandom_fill_bytes(v),
191 OsReaderRng(ref mut rng) => rng.fill_bytes(v)
197 #[cfg(target_os = "openbsd")]
199 use super::{next_u32, next_u64};
207 // dummy field to ensure that this struct cannot be constructed outside
213 /// Create a new `OsRng`.
214 pub fn new() -> io::Result<OsRng> {
215 Ok(OsRng { _dummy: () })
220 fn next_u32(&mut self) -> u32 {
221 next_u32(&mut |v| self.fill_bytes(v))
223 fn next_u64(&mut self) -> u64 {
224 next_u64(&mut |v| self.fill_bytes(v))
226 fn fill_bytes(&mut self, v: &mut [u8]) {
227 // getentropy(2) permits a maximum buffer size of 256 bytes
228 for s in v.chunks_mut(256) {
230 libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
233 panic!("unexpected getentropy error: {}", errno());
240 #[cfg(target_os = "ios")]
242 use super::{next_u32, next_u64};
247 use libc::{c_int, size_t};
250 // dummy field to ensure that this struct cannot be constructed outside
257 #[allow(non_upper_case_globals)]
258 const kSecRandomDefault: *const SecRandom = ptr::null();
260 #[link(name = "Security", kind = "framework")]
261 #[cfg(not(cargobuild))]
265 fn SecRandomCopyBytes(rnd: *const SecRandom,
266 count: size_t, bytes: *mut u8) -> c_int;
270 /// Create a new `OsRng`.
271 pub fn new() -> io::Result<OsRng> {
272 Ok(OsRng { _dummy: () })
277 fn next_u32(&mut self) -> u32 {
278 next_u32(&mut |v| self.fill_bytes(v))
280 fn next_u64(&mut self) -> u64 {
281 next_u64(&mut |v| self.fill_bytes(v))
283 fn fill_bytes(&mut self, v: &mut [u8]) {
285 SecRandomCopyBytes(kSecRandomDefault, v.len(),
289 panic!("couldn't generate random bytes: {}",
290 io::Error::last_os_error());
296 #[cfg(target_os = "freebsd")]
298 use super::{next_u32, next_u64};
306 // dummy field to ensure that this struct cannot be constructed outside
312 /// Create a new `OsRng`.
313 pub fn new() -> io::Result<OsRng> {
314 Ok(OsRng { _dummy: () })
319 fn next_u32(&mut self) -> u32 {
320 next_u32(&mut |v| self.fill_bytes(v))
322 fn next_u64(&mut self) -> u64 {
323 next_u64(&mut |v| self.fill_bytes(v))
325 fn fill_bytes(&mut self, v: &mut [u8]) {
326 let mib = [libc::CTL_KERN, libc::KERN_ARND];
327 // kern.arandom permits a maximum buffer size of 256 bytes
328 for s in v.chunks_mut(256) {
329 let mut s_len = s.len();
331 libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
332 s.as_mut_ptr() as *mut _, &mut s_len,
335 if ret == -1 || s_len != s.len() {
336 panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
337 ret, s.len(), s_len);
344 #[cfg(target_os = "fuchsia")]
346 use super::{next_u32, next_u64};
351 #[link(name = "magenta")]
353 fn mx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32;
356 fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
359 let status = mx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual);
369 // dummy field to ensure that this struct cannot be constructed outside
375 /// Create a new `OsRng`.
376 pub fn new() -> io::Result<OsRng> {
377 Ok(OsRng { _dummy: () })
382 fn next_u32(&mut self) -> u32 {
383 next_u32(&mut |v| self.fill_bytes(v))
385 fn next_u64(&mut self) -> u64 {
386 next_u64(&mut |v| self.fill_bytes(v))
388 fn fill_bytes(&mut self, v: &mut [u8]) {
390 while !buf.is_empty() {
391 let ret = getrandom(buf);
394 panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})",
399 buf = &mut move_buf[(actual as usize)..];