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 {
35 #[cfg(target_arch = "x86_64")]
36 const NR_GETRANDOM: libc::c_long = 318;
37 #[cfg(target_arch = "x86")]
38 const NR_GETRANDOM: libc::c_long = 355;
39 #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
40 const NR_GETRANDOM: libc::c_long = 384;
41 #[cfg(target_arch = "aarch64")]
42 const NR_GETRANDOM: libc::c_long = 278;
45 libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
49 #[cfg(not(all(target_os = "linux",
50 any(target_arch = "x86_64",
53 target_arch = "aarch64",
54 target_arch = "powerpc"))))]
55 fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
57 fn getrandom_fill_bytes(v: &mut [u8]) {
59 while read < v.len() {
60 let result = getrandom(&mut v[read..]);
62 let err = errno() as libc::c_int;
63 if err == libc::EINTR {
66 panic!("unexpected getrandom error: {}", err);
69 read += result as usize;
74 fn getrandom_next_u32() -> u32 {
75 let mut buf: [u8; 4] = [0; 4];
76 getrandom_fill_bytes(&mut buf);
77 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
80 fn getrandom_next_u64() -> u64 {
81 let mut buf: [u8; 8] = [0; 8];
82 getrandom_fill_bytes(&mut buf);
83 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
86 #[cfg(all(target_os = "linux",
87 any(target_arch = "x86_64",
90 target_arch = "aarch64",
91 target_arch = "powerpc")))]
92 fn is_getrandom_available() -> bool {
93 use sync::atomic::{AtomicBool, Ordering};
96 static CHECKER: Once = Once::new();
97 static AVAILABLE: AtomicBool = AtomicBool::new(false);
99 CHECKER.call_once(|| {
100 let mut buf: [u8; 0] = [];
101 let result = getrandom(&mut buf);
102 let available = if result == -1 {
103 let err = io::Error::last_os_error().raw_os_error();
104 err != Some(libc::ENOSYS)
108 AVAILABLE.store(available, Ordering::Relaxed);
111 AVAILABLE.load(Ordering::Relaxed)
114 #[cfg(not(all(target_os = "linux",
115 any(target_arch = "x86_64",
118 target_arch = "aarch64",
119 target_arch = "powerpc"))))]
120 fn is_getrandom_available() -> bool { false }
122 /// A random number generator that retrieves randomness straight from
123 /// the operating system. Platform sources:
125 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
126 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
127 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
128 /// service provider with the `PROV_RSA_FULL` type.
129 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
130 /// - OpenBSD: uses the `getentropy(2)` system call.
132 /// This does not block.
139 OsReaderRng(ReaderRng<File>),
143 /// Create a new `OsRng`.
144 pub fn new() -> io::Result<OsRng> {
145 if is_getrandom_available() {
146 return Ok(OsRng { inner: OsGetrandomRng });
149 let reader = try!(File::open("/dev/urandom"));
150 let reader_rng = ReaderRng::new(reader);
152 Ok(OsRng { inner: OsReaderRng(reader_rng) })
157 fn next_u32(&mut self) -> u32 {
159 OsGetrandomRng => getrandom_next_u32(),
160 OsReaderRng(ref mut rng) => rng.next_u32(),
163 fn next_u64(&mut self) -> u64 {
165 OsGetrandomRng => getrandom_next_u64(),
166 OsReaderRng(ref mut rng) => rng.next_u64(),
169 fn fill_bytes(&mut self, v: &mut [u8]) {
171 OsGetrandomRng => getrandom_fill_bytes(v),
172 OsReaderRng(ref mut rng) => rng.fill_bytes(v)
178 #[cfg(target_os = "openbsd")]
186 /// A random number generator that retrieves randomness straight from
187 /// the operating system. Platform sources:
189 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
190 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
191 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
192 /// service provider with the `PROV_RSA_FULL` type.
193 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
194 /// - OpenBSD: uses the `getentropy(2)` system call.
196 /// This does not block.
198 // dummy field to ensure that this struct cannot be constructed outside
204 /// Create a new `OsRng`.
205 pub fn new() -> io::Result<OsRng> {
206 Ok(OsRng { _dummy: () })
211 fn next_u32(&mut self) -> u32 {
213 self.fill_bytes(&mut v);
214 unsafe { mem::transmute(v) }
216 fn next_u64(&mut self) -> u64 {
218 self.fill_bytes(&mut v);
219 unsafe { mem::transmute(v) }
221 fn fill_bytes(&mut self, v: &mut [u8]) {
222 // getentropy(2) permits a maximum buffer size of 256 bytes
223 for s in v.chunks_mut(256) {
225 libc::syscall(libc::NR_GETENTROPY, s.as_mut_ptr(), s.len())
228 panic!("unexpected getentropy error: {}", errno());
235 #[cfg(target_os = "ios")]
241 use libc::{c_int, size_t};
243 /// A random number generator that retrieves randomness straight from
244 /// the operating system. Platform sources:
246 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
247 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
248 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
249 /// service provider with the `PROV_RSA_FULL` type.
250 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
251 /// - OpenBSD: uses the `getentropy(2)` system call.
253 /// This does not block.
255 // dummy field to ensure that this struct cannot be constructed outside
262 #[allow(non_upper_case_globals)]
263 const kSecRandomDefault: *const SecRandom = ptr::null();
265 #[link(name = "Security", kind = "framework")]
267 fn SecRandomCopyBytes(rnd: *const SecRandom,
268 count: size_t, bytes: *mut u8) -> c_int;
272 /// Create a new `OsRng`.
273 pub fn new() -> io::Result<OsRng> {
274 Ok(OsRng { _dummy: () })
279 fn next_u32(&mut self) -> u32 {
281 self.fill_bytes(&mut v);
282 unsafe { mem::transmute(v) }
284 fn next_u64(&mut self) -> u64 {
286 self.fill_bytes(&mut v);
287 unsafe { mem::transmute(v) }
289 fn fill_bytes(&mut self, v: &mut [u8]) {
291 SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
295 panic!("couldn't generate random bytes: {}",
296 io::Error::last_os_error());
309 /// A random number generator that retrieves randomness straight from
310 /// the operating system. Platform sources:
312 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
313 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
314 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
315 /// service provider with the `PROV_RSA_FULL` type.
316 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
317 /// - OpenBSD: uses the `getentropy(2)` system call.
319 /// This does not block.
321 hcryptprov: c::HCRYPTPROV
325 /// Create a new `OsRng`.
326 pub fn new() -> io::Result<OsRng> {
329 c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
331 c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
335 Err(io::Error::last_os_error())
337 Ok(OsRng { hcryptprov: hcp })
343 fn next_u32(&mut self) -> u32 {
345 self.fill_bytes(&mut v);
346 unsafe { mem::transmute(v) }
348 fn next_u64(&mut self) -> u64 {
350 self.fill_bytes(&mut v);
351 unsafe { mem::transmute(v) }
353 fn fill_bytes(&mut self, v: &mut [u8]) {
355 c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
359 panic!("couldn't generate random bytes: {}",
360 io::Error::last_os_error());
365 impl Drop for OsRng {
368 c::CryptReleaseContext(self.hcryptprov, 0)
371 panic!("couldn't release context: {}",
372 io::Error::last_os_error());
380 use sync::mpsc::channel;
387 let mut r = OsRng::new().unwrap();
392 let mut v = [0; 1000];
393 r.fill_bytes(&mut v);
397 fn test_os_rng_tasks() {
399 let mut txs = vec!();
401 let (tx, rx) = channel();
404 thread::spawn(move|| {
405 // wait until all the threads are ready to go.
408 // deschedule to attempt to interleave things as much
409 // as possible (XXX: is this a good test?)
410 let mut r = OsRng::new().unwrap();
412 let mut v = [0; 1000];
419 r.fill_bytes(&mut v);
425 // start all the threads
427 tx.send(()).unwrap();