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 threads 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 threads
399 tx
.send(()).unwrap();