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")))]
19 use self::OsRngInner::*;
26 use rand::reader::ReaderRng;
29 #[cfg(all(target_os = "linux",
30 any(target_arch = "x86_64",
33 target_arch = "aarch64",
34 target_arch = "powerpc")))]
35 fn getrandom(buf: &mut [u8]) -> libc::c_long {
37 fn syscall(number: libc::c_long, ...) -> libc::c_long;
40 #[cfg(target_arch = "x86_64")]
41 const NR_GETRANDOM: libc::c_long = 318;
42 #[cfg(target_arch = "x86")]
43 const NR_GETRANDOM: libc::c_long = 355;
44 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
45 const NR_GETRANDOM: libc::c_long = 384;
46 #[cfg(target_arch = "powerpc")]
47 const NR_GETRANDOM: libc::c_long = 384;
50 syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
54 #[cfg(not(all(target_os = "linux",
55 any(target_arch = "x86_64",
58 target_arch = "aarch64",
59 target_arch = "powerpc"))))]
60 fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
62 fn getrandom_fill_bytes(v: &mut [u8]) {
66 let result = getrandom(&mut v[read..]);
68 let err = errno() as libc::c_int;
69 if err == libc::EINTR {
72 panic!("unexpected getrandom error: {}", err);
75 read += result as usize;
80 fn getrandom_next_u32() -> u32 {
81 let mut buf: [u8; 4] = [0; 4];
82 getrandom_fill_bytes(&mut buf);
83 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
86 fn getrandom_next_u64() -> u64 {
87 let mut buf: [u8; 8] = [0; 8];
88 getrandom_fill_bytes(&mut buf);
89 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
92 #[cfg(all(target_os = "linux",
93 any(target_arch = "x86_64",
96 target_arch = "aarch64",
97 target_arch = "powerpc")))]
98 fn is_getrandom_available() -> bool {
99 use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
100 use sync::{Once, ONCE_INIT};
102 static CHECKER: Once = ONCE_INIT;
103 static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
105 CHECKER.call_once(|| {
106 let mut buf: [u8; 0] = [];
107 let result = getrandom(&mut buf);
108 let available = if result == -1 {
109 let err = io::Error::last_os_error().raw_os_error();
110 err != Some(libc::ENOSYS)
114 AVAILABLE.store(available, Ordering::Relaxed);
117 AVAILABLE.load(Ordering::Relaxed)
120 #[cfg(not(all(target_os = "linux",
121 any(target_arch = "x86_64",
124 target_arch = "aarch64",
125 target_arch = "powerpc"))))]
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.
137 /// This does not block.
144 OsReaderRng(ReaderRng<File>),
148 /// Create a new `OsRng`.
149 pub fn new() -> io::Result<OsRng> {
150 if is_getrandom_available() {
151 return Ok(OsRng { inner: OsGetrandomRng });
154 let reader = try!(File::open("/dev/urandom"));
155 let reader_rng = ReaderRng::new(reader);
157 Ok(OsRng { inner: OsReaderRng(reader_rng) })
162 fn next_u32(&mut self) -> u32 {
164 OsGetrandomRng => getrandom_next_u32(),
165 OsReaderRng(ref mut rng) => rng.next_u32(),
168 fn next_u64(&mut self) -> u64 {
170 OsGetrandomRng => getrandom_next_u64(),
171 OsReaderRng(ref mut rng) => rng.next_u64(),
174 fn fill_bytes(&mut self, v: &mut [u8]) {
176 OsGetrandomRng => getrandom_fill_bytes(v),
177 OsReaderRng(ref mut rng) => rng.fill_bytes(v)
183 #[cfg(target_os = "ios")]
190 use libc::{c_int, size_t};
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.
201 /// This does not block.
203 // dummy field to ensure that this struct cannot be constructed outside
211 #[allow(non_upper_case_globals)]
212 const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;
214 #[link(name = "Security", kind = "framework")]
216 fn SecRandomCopyBytes(rnd: *const SecRandom,
217 count: size_t, bytes: *mut u8) -> c_int;
221 /// Create a new `OsRng`.
222 pub fn new() -> io::Result<OsRng> {
223 Ok(OsRng { _dummy: () })
228 fn next_u32(&mut self) -> u32 {
230 self.fill_bytes(&mut v);
231 unsafe { mem::transmute(v) }
233 fn next_u64(&mut self) -> u64 {
235 self.fill_bytes(&mut v);
236 unsafe { mem::transmute(v) }
238 fn fill_bytes(&mut self, v: &mut [u8]) {
240 SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
244 panic!("couldn't generate random bytes: {}",
245 io::Error::last_os_error());
258 use libc::types::os::arch::extra::{LONG_PTR};
259 use libc::{DWORD, BYTE, LPCSTR, BOOL};
261 type HCRYPTPROV = LONG_PTR;
263 /// A random number generator that retrieves randomness straight from
264 /// the operating system. Platform sources:
266 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
267 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
268 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
269 /// service provider with the `PROV_RSA_FULL` type.
270 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
272 /// This does not block.
274 hcryptprov: HCRYPTPROV
277 const PROV_RSA_FULL: DWORD = 1;
278 const CRYPT_SILENT: DWORD = 64;
279 const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
281 #[allow(non_snake_case)]
283 fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
284 pszContainer: LPCSTR,
287 dwFlags: DWORD) -> BOOL;
288 fn CryptGenRandom(hProv: HCRYPTPROV,
290 pbBuffer: *mut BYTE) -> BOOL;
291 fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
295 /// Create a new `OsRng`.
296 pub fn new() -> io::Result<OsRng> {
299 CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
301 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
305 Err(io::Error::last_os_error())
307 Ok(OsRng { hcryptprov: hcp })
313 fn next_u32(&mut self) -> u32 {
315 self.fill_bytes(&mut v);
316 unsafe { mem::transmute(v) }
318 fn next_u64(&mut self) -> u64 {
320 self.fill_bytes(&mut v);
321 unsafe { mem::transmute(v) }
323 fn fill_bytes(&mut self, v: &mut [u8]) {
325 CryptGenRandom(self.hcryptprov, v.len() as DWORD,
329 panic!("couldn't generate random bytes: {}",
330 io::Error::last_os_error());
335 impl Drop for OsRng {
338 CryptReleaseContext(self.hcryptprov, 0)
341 panic!("couldn't release context: {}",
342 io::Error::last_os_error());
352 use sync::mpsc::channel;
359 let mut r = OsRng::new().unwrap();
364 let mut v = [0; 1000];
365 r.fill_bytes(&mut v);
369 fn test_os_rng_tasks() {
371 let mut txs = vec!();
373 let (tx, rx) = channel();
376 thread::spawn(move|| {
377 // wait until all the tasks are ready to go.
380 // deschedule to attempt to interleave things as much
381 // as possible (XXX: is this a good test?)
382 let mut r = OsRng::new().unwrap();
384 let mut v = [0; 1000];
391 r.fill_bytes(&mut v);
397 // start all the tasks
399 tx.send(()).unwrap();