]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/rand.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libstd / sys / unix / rand.rs
CommitLineData
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
11pub use self::imp::OsRng;
12
9cc50fc6 13#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
1a4d82fc 14mod 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 171mod 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")]
217mod 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}