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();
261 fn SecRandomCopyBytes(rnd: *const SecRandom,
262 count: size_t, bytes: *mut u8) -> c_int;
266 /// Create a new `OsRng`.
267 pub fn new() -> io::Result<OsRng> {
268 Ok(OsRng { _dummy: () })
273 fn next_u32(&mut self) -> u32 {
274 next_u32(&mut |v| self.fill_bytes(v))
276 fn next_u64(&mut self) -> u64 {
277 next_u64(&mut |v| self.fill_bytes(v))
279 fn fill_bytes(&mut self, v: &mut [u8]) {
281 SecRandomCopyBytes(kSecRandomDefault, v.len(),
285 panic!("couldn't generate random bytes: {}",
286 io::Error::last_os_error());
292 #[cfg(target_os = "freebsd")]
294 use super::{next_u32, next_u64};
302 // dummy field to ensure that this struct cannot be constructed outside
308 /// Create a new `OsRng`.
309 pub fn new() -> io::Result<OsRng> {
310 Ok(OsRng { _dummy: () })
315 fn next_u32(&mut self) -> u32 {
316 next_u32(&mut |v| self.fill_bytes(v))
318 fn next_u64(&mut self) -> u64 {
319 next_u64(&mut |v| self.fill_bytes(v))
321 fn fill_bytes(&mut self, v: &mut [u8]) {
322 let mib = [libc::CTL_KERN, libc::KERN_ARND];
323 // kern.arandom permits a maximum buffer size of 256 bytes
324 for s in v.chunks_mut(256) {
325 let mut s_len = s.len();
327 libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
328 s.as_mut_ptr() as *mut _, &mut s_len,
331 if ret == -1 || s_len != s.len() {
332 panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
333 ret, s.len(), s_len);
340 #[cfg(target_os = "fuchsia")]
342 use super::{next_u32, next_u64};
347 #[link(name = "magenta")]
349 fn mx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32;
352 fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
355 let status = mx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual);
365 // dummy field to ensure that this struct cannot be constructed outside
371 /// Create a new `OsRng`.
372 pub fn new() -> io::Result<OsRng> {
373 Ok(OsRng { _dummy: () })
378 fn next_u32(&mut self) -> u32 {
379 next_u32(&mut |v| self.fill_bytes(v))
381 fn next_u64(&mut self) -> u64 {
382 next_u64(&mut |v| self.fill_bytes(v))
384 fn fill_bytes(&mut self, v: &mut [u8]) {
386 while !buf.is_empty() {
387 let ret = getrandom(buf);
390 panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})",
395 buf = &mut move_buf[(actual as usize)..];