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")))]
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
{
36 fn syscall(number
: libc
::c_long
, ...) -> libc
::c_long
;
39 #[cfg(target_arch = "x86_64")]
40 const NR_GETRANDOM
: libc
::c_long
= 318;
41 #[cfg(target_arch = "x86")]
42 const NR_GETRANDOM
: libc
::c_long
= 355;
43 #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
44 const NR_GETRANDOM
: libc
::c_long
= 384;
45 #[cfg(any(target_arch = "aarch64"))]
46 const NR_GETRANDOM
: libc
::c_long
= 278;
49 syscall(NR_GETRANDOM
, buf
.as_mut_ptr(), buf
.len(), 0)
53 #[cfg(not(all(target_os = "linux",
54 any(target_arch
= "x86_64",
57 target_arch
= "aarch64",
58 target_arch
= "powerpc"))))]
59 fn getrandom(_buf
: &mut [u8]) -> libc
::c_long { -1 }
61 fn getrandom_fill_bytes(v
: &mut [u8]) {
65 let result
= getrandom(&mut v
[read
..]);
67 let err
= errno() as libc
::c_int
;
68 if err
== libc
::EINTR
{
71 panic
!("unexpected getrandom error: {}", err
);
74 read
+= result
as usize;
79 fn getrandom_next_u32() -> u32 {
80 let mut buf
: [u8; 4] = [0; 4];
81 getrandom_fill_bytes(&mut buf
);
82 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
85 fn getrandom_next_u64() -> u64 {
86 let mut buf
: [u8; 8] = [0; 8];
87 getrandom_fill_bytes(&mut buf
);
88 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
91 #[cfg(all(target_os = "linux",
92 any(target_arch
= "x86_64",
95 target_arch
= "aarch64",
96 target_arch
= "powerpc")))]
97 fn is_getrandom_available() -> bool
{
98 use sync
::atomic
::{AtomicBool, Ordering}
;
101 static CHECKER
: Once
= Once
::new();
102 static AVAILABLE
: AtomicBool
= AtomicBool
::new(false);
104 CHECKER
.call_once(|| {
105 let mut buf
: [u8; 0] = [];
106 let result
= getrandom(&mut buf
);
107 let available
= if result
== -1 {
108 let err
= io
::Error
::last_os_error().raw_os_error();
109 err
!= Some(libc
::ENOSYS
)
113 AVAILABLE
.store(available
, Ordering
::Relaxed
);
116 AVAILABLE
.load(Ordering
::Relaxed
)
119 #[cfg(not(all(target_os = "linux",
120 any(target_arch
= "x86_64",
123 target_arch
= "aarch64",
124 target_arch
= "powerpc"))))]
125 fn is_getrandom_available() -> bool { false }
127 /// A random number generator that retrieves randomness straight from
128 /// the operating system. Platform sources:
130 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
131 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
132 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
133 /// service provider with the `PROV_RSA_FULL` type.
134 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
136 /// This does not block.
143 OsReaderRng(ReaderRng
<File
>),
147 /// Create a new `OsRng`.
148 pub fn new() -> io
::Result
<OsRng
> {
149 if is_getrandom_available() {
150 return Ok(OsRng { inner: OsGetrandomRng }
);
153 let reader
= try
!(File
::open("/dev/urandom"));
154 let reader_rng
= ReaderRng
::new(reader
);
156 Ok(OsRng { inner: OsReaderRng(reader_rng) }
)
161 fn next_u32(&mut self) -> u32 {
163 OsGetrandomRng
=> getrandom_next_u32(),
164 OsReaderRng(ref mut rng
) => rng
.next_u32(),
167 fn next_u64(&mut self) -> u64 {
169 OsGetrandomRng
=> getrandom_next_u64(),
170 OsReaderRng(ref mut rng
) => rng
.next_u64(),
173 fn fill_bytes(&mut self, v
: &mut [u8]) {
175 OsGetrandomRng
=> getrandom_fill_bytes(v
),
176 OsReaderRng(ref mut rng
) => rng
.fill_bytes(v
)
182 #[cfg(target_os = "ios")]
184 #[cfg(stage0)] use prelude::v1::*;
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
210 #[allow(non_upper_case_globals)]
211 const kSecRandomDefault
: *const SecRandom
= ptr
::null();
213 #[link(name = "Security", kind = "framework")]
215 fn SecRandomCopyBytes(rnd
: *const SecRandom
,
216 count
: size_t
, bytes
: *mut u8) -> c_int
;
220 /// Create a new `OsRng`.
221 pub fn new() -> io
::Result
<OsRng
> {
222 Ok(OsRng { _dummy: () }
)
227 fn next_u32(&mut self) -> u32 {
229 self.fill_bytes(&mut v
);
230 unsafe { mem::transmute(v) }
232 fn next_u64(&mut self) -> u64 {
234 self.fill_bytes(&mut v
);
235 unsafe { mem::transmute(v) }
237 fn fill_bytes(&mut self, v
: &mut [u8]) {
239 SecRandomCopyBytes(kSecRandomDefault
, v
.len() as size_t
,
243 panic
!("couldn't generate random bytes: {}",
244 io
::Error
::last_os_error());
257 /// A random number generator that retrieves randomness straight from
258 /// the operating system. Platform sources:
260 /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
261 /// `/dev/urandom`, or from `getrandom(2)` system call if available.
262 /// - Windows: calls `CryptGenRandom`, using the default cryptographic
263 /// service provider with the `PROV_RSA_FULL` type.
264 /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
266 /// This does not block.
268 hcryptprov
: c
::HCRYPTPROV
272 /// Create a new `OsRng`.
273 pub fn new() -> io
::Result
<OsRng
> {
276 c
::CryptAcquireContextA(&mut hcp
, 0 as c
::LPCSTR
, 0 as c
::LPCSTR
,
278 c
::CRYPT_VERIFYCONTEXT
| c
::CRYPT_SILENT
)
282 Err(io
::Error
::last_os_error())
284 Ok(OsRng { hcryptprov: hcp }
)
290 fn next_u32(&mut self) -> u32 {
292 self.fill_bytes(&mut v
);
293 unsafe { mem::transmute(v) }
295 fn next_u64(&mut self) -> u64 {
297 self.fill_bytes(&mut v
);
298 unsafe { mem::transmute(v) }
300 fn fill_bytes(&mut self, v
: &mut [u8]) {
302 c
::CryptGenRandom(self.hcryptprov
, v
.len() as c
::DWORD
,
306 panic
!("couldn't generate random bytes: {}",
307 io
::Error
::last_os_error());
312 impl Drop
for OsRng
{
315 c
::CryptReleaseContext(self.hcryptprov
, 0)
318 panic
!("couldn't release context: {}",
319 io
::Error
::last_os_error());
329 use sync
::mpsc
::channel
;
336 let mut r
= OsRng
::new().unwrap();
341 let mut v
= [0; 1000];
342 r
.fill_bytes(&mut v
);
346 fn test_os_rng_tasks() {
348 let mut txs
= vec
!();
350 let (tx
, rx
) = channel();
353 thread
::spawn(move|| {
354 // wait until all the threads are ready to go.
357 // deschedule to attempt to interleave things as much
358 // as possible (XXX: is this a good test?)
359 let mut r
= OsRng
::new().unwrap();
361 let mut v
= [0; 1000];
368 r
.fill_bytes(&mut v
);
374 // start all the threads
376 tx
.send(()).unwrap();