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 pub use self::imp
::OsRng
;
13 #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
15 use self::OsRngInner
::*;
22 use rand
::reader
::ReaderRng
;
25 #[cfg(all(target_os = "linux",
26 any(target_arch
= "x86_64",
29 target_arch
= "aarch64",
30 target_arch
= "powerpc",
31 target_arch
= "powerpc64")))]
32 fn getrandom(buf
: &mut [u8]) -> libc
::c_long
{
33 #[cfg(target_arch = "x86_64")]
34 const NR_GETRANDOM
: libc
::c_long
= 318;
35 #[cfg(target_arch = "x86")]
36 const NR_GETRANDOM
: libc
::c_long
= 355;
37 #[cfg(target_arch = "arm")]
38 const NR_GETRANDOM
: libc
::c_long
= 384;
39 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
40 const NR_GETRANDOM
: libc
::c_long
= 359;
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 target_arch
= "powerpc64"))))]
56 fn getrandom(_buf
: &mut [u8]) -> libc
::c_long { -1 }
58 fn getrandom_fill_bytes(v
: &mut [u8]) {
60 while read
< v
.len() {
61 let result
= getrandom(&mut v
[read
..]);
63 let err
= errno() as libc
::c_int
;
64 if err
== libc
::EINTR
{
67 panic
!("unexpected getrandom error: {}", err
);
70 read
+= result
as usize;
75 fn getrandom_next_u32() -> u32 {
76 let mut buf
: [u8; 4] = [0; 4];
77 getrandom_fill_bytes(&mut buf
);
78 unsafe { mem::transmute::<[u8; 4], u32>(buf) }
81 fn getrandom_next_u64() -> u64 {
82 let mut buf
: [u8; 8] = [0; 8];
83 getrandom_fill_bytes(&mut buf
);
84 unsafe { mem::transmute::<[u8; 8], u64>(buf) }
87 #[cfg(all(target_os = "linux",
88 any(target_arch
= "x86_64",
91 target_arch
= "aarch64",
92 target_arch
= "powerpc",
93 target_arch
= "powerpc64")))]
94 fn is_getrandom_available() -> bool
{
95 use sync
::atomic
::{AtomicBool, Ordering}
;
98 static CHECKER
: Once
= Once
::new();
99 static AVAILABLE
: AtomicBool
= AtomicBool
::new(false);
101 CHECKER
.call_once(|| {
102 let mut buf
: [u8; 0] = [];
103 let result
= getrandom(&mut buf
);
104 let available
= if result
== -1 {
105 let err
= io
::Error
::last_os_error().raw_os_error();
106 err
!= Some(libc
::ENOSYS
)
110 AVAILABLE
.store(available
, Ordering
::Relaxed
);
113 AVAILABLE
.load(Ordering
::Relaxed
)
116 #[cfg(not(all(target_os = "linux",
117 any(target_arch
= "x86_64",
120 target_arch
= "aarch64",
121 target_arch
= "powerpc",
122 target_arch
= "powerpc64"))))]
123 fn is_getrandom_available() -> bool { false }
131 OsReaderRng(ReaderRng
<File
>),
135 /// Create a new `OsRng`.
136 pub fn new() -> io
::Result
<OsRng
> {
137 if is_getrandom_available() {
138 return Ok(OsRng { inner: OsGetrandomRng }
);
141 let reader
= File
::open("/dev/urandom")?
;
142 let reader_rng
= ReaderRng
::new(reader
);
144 Ok(OsRng { inner: OsReaderRng(reader_rng) }
)
149 fn next_u32(&mut self) -> u32 {
151 OsGetrandomRng
=> getrandom_next_u32(),
152 OsReaderRng(ref mut rng
) => rng
.next_u32(),
155 fn next_u64(&mut self) -> u64 {
157 OsGetrandomRng
=> getrandom_next_u64(),
158 OsReaderRng(ref mut rng
) => rng
.next_u64(),
161 fn fill_bytes(&mut self, v
: &mut [u8]) {
163 OsGetrandomRng
=> getrandom_fill_bytes(v
),
164 OsReaderRng(ref mut rng
) => rng
.fill_bytes(v
)
170 #[cfg(target_os = "openbsd")]
179 // dummy field to ensure that this struct cannot be constructed outside
185 /// Create a new `OsRng`.
186 pub fn new() -> io
::Result
<OsRng
> {
187 Ok(OsRng { _dummy: () }
)
192 fn next_u32(&mut self) -> u32 {
194 self.fill_bytes(&mut v
);
195 unsafe { mem::transmute(v) }
197 fn next_u64(&mut self) -> u64 {
199 self.fill_bytes(&mut v
);
200 unsafe { mem::transmute(v) }
202 fn fill_bytes(&mut self, v
: &mut [u8]) {
203 // getentropy(2) permits a maximum buffer size of 256 bytes
204 for s
in v
.chunks_mut(256) {
206 libc
::getentropy(s
.as_mut_ptr() as *mut libc
::c_void
, s
.len())
209 panic
!("unexpected getentropy error: {}", errno());
216 #[cfg(target_os = "ios")]
222 use libc
::{c_int, size_t}
;
225 // dummy field to ensure that this struct cannot be constructed outside
232 #[allow(non_upper_case_globals)]
233 const kSecRandomDefault
: *const SecRandom
= ptr
::null();
235 #[link(name = "Security", kind = "framework")]
236 #[cfg(not(cargobuild))]
240 fn SecRandomCopyBytes(rnd
: *const SecRandom
,
241 count
: size_t
, bytes
: *mut u8) -> c_int
;
245 /// Create a new `OsRng`.
246 pub fn new() -> io
::Result
<OsRng
> {
247 Ok(OsRng { _dummy: () }
)
252 fn next_u32(&mut self) -> u32 {
254 self.fill_bytes(&mut v
);
255 unsafe { mem::transmute(v) }
257 fn next_u64(&mut self) -> u64 {
259 self.fill_bytes(&mut v
);
260 unsafe { mem::transmute(v) }
262 fn fill_bytes(&mut self, v
: &mut [u8]) {
264 SecRandomCopyBytes(kSecRandomDefault
, v
.len() as size_t
,
268 panic
!("couldn't generate random bytes: {}",
269 io
::Error
::last_os_error());