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}
;
101 static GETRANDOM_CHECKED
: AtomicBool
= ATOMIC_BOOL_INIT
;
102 static GETRANDOM_AVAILABLE
: AtomicBool
= ATOMIC_BOOL_INIT
;
104 if !GETRANDOM_CHECKED
.load(Ordering
::Relaxed
) {
105 let mut buf
: [u8; 0] = [];
106 let result
= getrandom(&mut buf
);
107 let available
= if result
== -1 {
108 let err
= errno() as libc
::c_int
;
113 GETRANDOM_AVAILABLE
.store(available
, Ordering
::Relaxed
);
114 GETRANDOM_CHECKED
.store(true, Ordering
::Relaxed
);
117 GETRANDOM_AVAILABLE
.load(Ordering
::Relaxed
)
121 #[cfg(not(all(target_os = "linux",
122 any(target_arch
= "x86_64",
125 target_arch
= "aarch64",
126 target_arch
= "powerpc"))))]
127 fn is_getrandom_available() -> bool { false }
129 /// A random number generator that retrieves randomness straight from
130 /// the operating system. Platform sources:
132 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
133 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
134 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
135 /// service provider with the `PROV_RSA_FULL` type.
136 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
138 /// This does not block.
145 OsReaderRng(ReaderRng
<File
>),
149 /// Create a new `OsRng`.
150 pub fn new() -> io
::Result
<OsRng
> {
151 if is_getrandom_available() {
152 return Ok(OsRng { inner: OsGetrandomRng }
);
155 let reader
= try
!(File
::open("/dev/urandom"));
156 let reader_rng
= ReaderRng
::new(reader
);
158 Ok(OsRng { inner: OsReaderRng(reader_rng) }
)
163 fn next_u32(&mut self) -> u32 {
165 OsGetrandomRng
=> getrandom_next_u32(),
166 OsReaderRng(ref mut rng
) => rng
.next_u32(),
169 fn next_u64(&mut self) -> u64 {
171 OsGetrandomRng
=> getrandom_next_u64(),
172 OsReaderRng(ref mut rng
) => rng
.next_u64(),
175 fn fill_bytes(&mut self, v
: &mut [u8]) {
177 OsGetrandomRng
=> getrandom_fill_bytes(v
),
178 OsReaderRng(ref mut rng
) => rng
.fill_bytes(v
)
184 #[cfg(target_os = "ios")]
191 use libc
::{c_int, size_t}
;
193 /// A random number generator that retrieves randomness straight from
194 /// the operating system. Platform sources:
196 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
197 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
198 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
199 /// service provider with the `PROV_RSA_FULL` type.
200 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
202 /// This does not block.
204 // dummy field to ensure that this struct cannot be constructed outside
212 #[allow(non_upper_case_globals)]
213 const kSecRandomDefault
: *const SecRandom
= 0 as *const SecRandom
;
215 #[link(name = "Security", kind = "framework")]
217 fn SecRandomCopyBytes(rnd
: *const SecRandom
,
218 count
: size_t
, bytes
: *mut u8) -> c_int
;
222 /// Create a new `OsRng`.
223 pub fn new() -> io
::Result
<OsRng
> {
224 Ok(OsRng { _dummy: () }
)
229 fn next_u32(&mut self) -> u32 {
231 self.fill_bytes(&mut v
);
232 unsafe { mem::transmute(v) }
234 fn next_u64(&mut self) -> u64 {
236 self.fill_bytes(&mut v
);
237 unsafe { mem::transmute(v) }
239 fn fill_bytes(&mut self, v
: &mut [u8]) {
241 SecRandomCopyBytes(kSecRandomDefault
, v
.len() as size_t
,
245 panic
!("couldn't generate random bytes: {}",
246 io
::Error
::last_os_error());
259 use libc
::types
::os
::arch
::extra
::{LONG_PTR}
;
260 use libc
::{DWORD, BYTE, LPCSTR, BOOL}
;
262 type HCRYPTPROV
= LONG_PTR
;
264 /// A random number generator that retrieves randomness straight from
265 /// the operating system. Platform sources:
267 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
268 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
269 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
270 /// service provider with the `PROV_RSA_FULL` type.
271 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
273 /// This does not block.
275 hcryptprov
: HCRYPTPROV
278 const PROV_RSA_FULL
: DWORD
= 1;
279 const CRYPT_SILENT
: DWORD
= 64;
280 const CRYPT_VERIFYCONTEXT
: DWORD
= 0xF0000000;
282 #[allow(non_snake_case)]
284 fn CryptAcquireContextA(phProv
: *mut HCRYPTPROV
,
285 pszContainer
: LPCSTR
,
288 dwFlags
: DWORD
) -> BOOL
;
289 fn CryptGenRandom(hProv
: HCRYPTPROV
,
291 pbBuffer
: *mut BYTE
) -> BOOL
;
292 fn CryptReleaseContext(hProv
: HCRYPTPROV
, dwFlags
: DWORD
) -> BOOL
;
296 /// Create a new `OsRng`.
297 pub fn new() -> io
::Result
<OsRng
> {
300 CryptAcquireContextA(&mut hcp
, 0 as LPCSTR
, 0 as LPCSTR
,
302 CRYPT_VERIFYCONTEXT
| CRYPT_SILENT
)
306 Err(io
::Error
::last_os_error())
308 Ok(OsRng { hcryptprov: hcp }
)
314 fn next_u32(&mut self) -> u32 {
316 self.fill_bytes(&mut v
);
317 unsafe { mem::transmute(v) }
319 fn next_u64(&mut self) -> u64 {
321 self.fill_bytes(&mut v
);
322 unsafe { mem::transmute(v) }
324 fn fill_bytes(&mut self, v
: &mut [u8]) {
326 CryptGenRandom(self.hcryptprov
, v
.len() as DWORD
,
330 panic
!("couldn't generate random bytes: {}",
331 io
::Error
::last_os_error());
336 impl Drop
for OsRng
{
339 CryptReleaseContext(self.hcryptprov
, 0)
342 panic
!("couldn't release context: {}",
343 io
::Error
::last_os_error());
353 use sync
::mpsc
::channel
;
360 let mut r
= OsRng
::new().unwrap();
365 let mut v
= [0; 1000];
366 r
.fill_bytes(&mut v
);
370 fn test_os_rng_tasks() {
372 let mut txs
= vec
!();
374 let (tx
, rx
) = channel();
377 thread
::spawn(move|| {
378 // wait until all the tasks are ready to go.
381 // deschedule to attempt to interleave things as much
382 // as possible (XXX: is this a good test?)
383 let mut r
= OsRng
::new().unwrap();
385 let mut v
= [0; 1000];
392 r
.fill_bytes(&mut v
);
398 // start all the tasks
400 tx
.send(()).unwrap();