]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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. | |
4 | // | |
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. | |
10 | ||
1a4d82fc JJ |
11 | pub use self::imp::OsRng; |
12 | ||
9cc50fc6 | 13 | #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))] |
1a4d82fc | 14 | mod imp { |
1a4d82fc JJ |
15 | use self::OsRngInner::*; |
16 | ||
9346a6ac AL |
17 | use fs::File; |
18 | use io; | |
c34b1796 AL |
19 | use libc; |
20 | use mem; | |
1a4d82fc JJ |
21 | use rand::Rng; |
22 | use rand::reader::ReaderRng; | |
c34b1796 | 23 | use sys::os::errno; |
1a4d82fc JJ |
24 | |
25 | #[cfg(all(target_os = "linux", | |
26 | any(target_arch = "x86_64", | |
27 | target_arch = "x86", | |
28 | target_arch = "arm", | |
85aaf69f | 29 | target_arch = "aarch64", |
9cc50fc6 | 30 | target_arch = "powerpc", |
7453a54e | 31 | target_arch = "powerpc64")))] |
1a4d82fc | 32 | fn getrandom(buf: &mut [u8]) -> libc::c_long { |
1a4d82fc JJ |
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; | |
9cc50fc6 | 37 | #[cfg(target_arch = "arm")] |
85aaf69f | 38 | const NR_GETRANDOM: libc::c_long = 384; |
7453a54e | 39 | #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] |
9cc50fc6 SL |
40 | const NR_GETRANDOM: libc::c_long = 359; |
41 | #[cfg(target_arch = "aarch64")] | |
c1a9b12d | 42 | const NR_GETRANDOM: libc::c_long = 278; |
1a4d82fc JJ |
43 | |
44 | unsafe { | |
9cc50fc6 | 45 | libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0) |
1a4d82fc JJ |
46 | } |
47 | } | |
48 | ||
49 | #[cfg(not(all(target_os = "linux", | |
50 | any(target_arch = "x86_64", | |
51 | target_arch = "x86", | |
52 | target_arch = "arm", | |
85aaf69f | 53 | target_arch = "aarch64", |
9cc50fc6 | 54 | target_arch = "powerpc", |
7453a54e | 55 | target_arch = "powerpc64"))))] |
1a4d82fc JJ |
56 | fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } |
57 | ||
58 | fn getrandom_fill_bytes(v: &mut [u8]) { | |
59 | let mut read = 0; | |
9cc50fc6 | 60 | while read < v.len() { |
85aaf69f | 61 | let result = getrandom(&mut v[read..]); |
1a4d82fc JJ |
62 | if result == -1 { |
63 | let err = errno() as libc::c_int; | |
64 | if err == libc::EINTR { | |
65 | continue; | |
66 | } else { | |
67 | panic!("unexpected getrandom error: {}", err); | |
68 | } | |
69 | } else { | |
85aaf69f | 70 | read += result as usize; |
1a4d82fc JJ |
71 | } |
72 | } | |
73 | } | |
74 | ||
75 | fn getrandom_next_u32() -> u32 { | |
c34b1796 | 76 | let mut buf: [u8; 4] = [0; 4]; |
1a4d82fc JJ |
77 | getrandom_fill_bytes(&mut buf); |
78 | unsafe { mem::transmute::<[u8; 4], u32>(buf) } | |
79 | } | |
80 | ||
81 | fn getrandom_next_u64() -> u64 { | |
c34b1796 | 82 | let mut buf: [u8; 8] = [0; 8]; |
1a4d82fc JJ |
83 | getrandom_fill_bytes(&mut buf); |
84 | unsafe { mem::transmute::<[u8; 8], u64>(buf) } | |
85 | } | |
86 | ||
87 | #[cfg(all(target_os = "linux", | |
88 | any(target_arch = "x86_64", | |
89 | target_arch = "x86", | |
90 | target_arch = "arm", | |
85aaf69f | 91 | target_arch = "aarch64", |
9cc50fc6 | 92 | target_arch = "powerpc", |
7453a54e | 93 | target_arch = "powerpc64")))] |
1a4d82fc | 94 | fn is_getrandom_available() -> bool { |
62682a34 SL |
95 | use sync::atomic::{AtomicBool, Ordering}; |
96 | use sync::Once; | |
1a4d82fc | 97 | |
62682a34 SL |
98 | static CHECKER: Once = Once::new(); |
99 | static AVAILABLE: AtomicBool = AtomicBool::new(false); | |
1a4d82fc | 100 | |
d9579d0f | 101 | CHECKER.call_once(|| { |
1a4d82fc JJ |
102 | let mut buf: [u8; 0] = []; |
103 | let result = getrandom(&mut buf); | |
104 | let available = if result == -1 { | |
d9579d0f AL |
105 | let err = io::Error::last_os_error().raw_os_error(); |
106 | err != Some(libc::ENOSYS) | |
1a4d82fc JJ |
107 | } else { |
108 | true | |
109 | }; | |
d9579d0f AL |
110 | AVAILABLE.store(available, Ordering::Relaxed); |
111 | }); | |
112 | ||
113 | AVAILABLE.load(Ordering::Relaxed) | |
1a4d82fc JJ |
114 | } |
115 | ||
116 | #[cfg(not(all(target_os = "linux", | |
117 | any(target_arch = "x86_64", | |
118 | target_arch = "x86", | |
119 | target_arch = "arm", | |
85aaf69f | 120 | target_arch = "aarch64", |
9cc50fc6 | 121 | target_arch = "powerpc", |
7453a54e | 122 | target_arch = "powerpc64"))))] |
1a4d82fc JJ |
123 | fn is_getrandom_available() -> bool { false } |
124 | ||
1a4d82fc JJ |
125 | pub struct OsRng { |
126 | inner: OsRngInner, | |
127 | } | |
128 | ||
129 | enum OsRngInner { | |
130 | OsGetrandomRng, | |
131 | OsReaderRng(ReaderRng<File>), | |
132 | } | |
133 | ||
134 | impl OsRng { | |
135 | /// Create a new `OsRng`. | |
9346a6ac | 136 | pub fn new() -> io::Result<OsRng> { |
1a4d82fc JJ |
137 | if is_getrandom_available() { |
138 | return Ok(OsRng { inner: OsGetrandomRng }); | |
139 | } | |
140 | ||
54a0048b | 141 | let reader = File::open("/dev/urandom")?; |
1a4d82fc JJ |
142 | let reader_rng = ReaderRng::new(reader); |
143 | ||
144 | Ok(OsRng { inner: OsReaderRng(reader_rng) }) | |
145 | } | |
146 | } | |
147 | ||
148 | impl Rng for OsRng { | |
149 | fn next_u32(&mut self) -> u32 { | |
150 | match self.inner { | |
151 | OsGetrandomRng => getrandom_next_u32(), | |
152 | OsReaderRng(ref mut rng) => rng.next_u32(), | |
153 | } | |
154 | } | |
155 | fn next_u64(&mut self) -> u64 { | |
156 | match self.inner { | |
157 | OsGetrandomRng => getrandom_next_u64(), | |
158 | OsReaderRng(ref mut rng) => rng.next_u64(), | |
159 | } | |
160 | } | |
161 | fn fill_bytes(&mut self, v: &mut [u8]) { | |
162 | match self.inner { | |
163 | OsGetrandomRng => getrandom_fill_bytes(v), | |
164 | OsReaderRng(ref mut rng) => rng.fill_bytes(v) | |
165 | } | |
166 | } | |
167 | } | |
168 | } | |
169 | ||
9cc50fc6 | 170 | #[cfg(target_os = "openbsd")] |
1a4d82fc | 171 | mod imp { |
9cc50fc6 SL |
172 | use io; |
173 | use libc; | |
174 | use mem; | |
175 | use sys::os::errno; | |
176 | use rand::Rng; | |
177 | ||
9cc50fc6 SL |
178 | pub struct OsRng { |
179 | // dummy field to ensure that this struct cannot be constructed outside | |
180 | // of this module | |
181 | _dummy: (), | |
182 | } | |
183 | ||
184 | impl OsRng { | |
185 | /// Create a new `OsRng`. | |
186 | pub fn new() -> io::Result<OsRng> { | |
187 | Ok(OsRng { _dummy: () }) | |
188 | } | |
189 | } | |
190 | ||
191 | impl Rng for OsRng { | |
192 | fn next_u32(&mut self) -> u32 { | |
193 | let mut v = [0; 4]; | |
194 | self.fill_bytes(&mut v); | |
195 | unsafe { mem::transmute(v) } | |
196 | } | |
197 | fn next_u64(&mut self) -> u64 { | |
198 | let mut v = [0; 8]; | |
199 | self.fill_bytes(&mut v); | |
200 | unsafe { mem::transmute(v) } | |
201 | } | |
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) { | |
205 | let ret = unsafe { | |
206 | libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len()) | |
207 | }; | |
208 | if ret == -1 { | |
209 | panic!("unexpected getentropy error: {}", errno()); | |
210 | } | |
211 | } | |
212 | } | |
213 | } | |
214 | } | |
1a4d82fc | 215 | |
9cc50fc6 SL |
216 | #[cfg(target_os = "ios")] |
217 | mod imp { | |
c34b1796 | 218 | use io; |
1a4d82fc | 219 | use mem; |
e9174d1e | 220 | use ptr; |
1a4d82fc | 221 | use rand::Rng; |
e9174d1e | 222 | use libc::{c_int, size_t}; |
1a4d82fc | 223 | |
1a4d82fc | 224 | pub struct OsRng { |
9346a6ac AL |
225 | // dummy field to ensure that this struct cannot be constructed outside |
226 | // of this module | |
1a4d82fc JJ |
227 | _dummy: (), |
228 | } | |
229 | ||
e9174d1e | 230 | enum SecRandom {} |
1a4d82fc | 231 | |
1a4d82fc | 232 | #[allow(non_upper_case_globals)] |
e9174d1e | 233 | const kSecRandomDefault: *const SecRandom = ptr::null(); |
1a4d82fc JJ |
234 | |
235 | #[link(name = "Security", kind = "framework")] | |
7453a54e SL |
236 | #[cfg(not(cargobuild))] |
237 | extern {} | |
238 | ||
239 | extern { | |
1a4d82fc JJ |
240 | fn SecRandomCopyBytes(rnd: *const SecRandom, |
241 | count: size_t, bytes: *mut u8) -> c_int; | |
242 | } | |
243 | ||
244 | impl OsRng { | |
245 | /// Create a new `OsRng`. | |
9346a6ac | 246 | pub fn new() -> io::Result<OsRng> { |
1a4d82fc JJ |
247 | Ok(OsRng { _dummy: () }) |
248 | } | |
249 | } | |
250 | ||
251 | impl Rng for OsRng { | |
252 | fn next_u32(&mut self) -> u32 { | |
c34b1796 | 253 | let mut v = [0; 4]; |
1a4d82fc JJ |
254 | self.fill_bytes(&mut v); |
255 | unsafe { mem::transmute(v) } | |
256 | } | |
257 | fn next_u64(&mut self) -> u64 { | |
c34b1796 | 258 | let mut v = [0; 8]; |
1a4d82fc JJ |
259 | self.fill_bytes(&mut v); |
260 | unsafe { mem::transmute(v) } | |
261 | } | |
262 | fn fill_bytes(&mut self, v: &mut [u8]) { | |
263 | let ret = unsafe { | |
9346a6ac AL |
264 | SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, |
265 | v.as_mut_ptr()) | |
1a4d82fc JJ |
266 | }; |
267 | if ret == -1 { | |
9346a6ac AL |
268 | panic!("couldn't generate random bytes: {}", |
269 | io::Error::last_os_error()); | |
1a4d82fc JJ |
270 | } |
271 | } | |
272 | } | |
273 | } |