1 // Copyright 2019 Developers of the Rand project.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8
9 //! Interface to the operating system's random number generator.
10 //!
11 //! # Supported targets
12 //!
13 //! | Target | Target Triple | Implementation
14 //! | ----------------- | ------------------ | --------------
15 //! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` |
16 //! | Windows | `*‑windows‑*` | [`BCryptGenRandom`][3] |
17 //! | macOS | `*‑apple‑darwin` | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
18 //! | iOS | `*‑apple‑ios` | [`SecRandomCopyBytes`][4]
19 //! | FreeBSD | `*‑freebsd` | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
20 //! | OpenBSD | `*‑openbsd` | [`getentropy`][6]
21 //! | NetBSD | `*‑netbsd` | [`kern.arandom`][7]
22 //! | Dragonfly BSD | `*‑dragonfly` | [`/dev/random`][8]
23 //! | Solaris, illumos | `*‑solaris`, `*‑illumos` | [`getrandom()`][9] if available, otherwise [`/dev/random`][10]
24 //! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`][11]
25 //! | Redox | `*‑redox` | [`rand:`][12]
26 //! | Haiku | `*‑haiku` | `/dev/random` (identical to `/dev/urandom`)
27 //! | SGX | `x86_64‑*‑sgx` | [RDRAND][18]
28 //! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure`
29 //! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`)
30 //! | WASI | `wasm32‑wasi` | [`__wasi_random_get`][17]
31 //! | Web Browser | `wasm32‑*‑unknown` | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16]
32 //! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomBytes`][15], see [WebAssembly support][16]
33 //!
34 //! There is no blanket implementation on `unix` targets that reads from
35 //! `/dev/urandom`. This ensures all supported targets are using the recommended
36 //! interface and respect maximum buffer sizes.
37 //!
38 //! Pull Requests that add support for new targets to `getrandom` are always welcome.
39 //!
40 //! ## Unsupported targets
41 //!
42 //! By default, `getrandom` will not compile on unsupported targets, but certain
43 //! features allow a user to select a "fallback" implementation if no supported
44 //! implementation exists.
45 //!
46 //! All of the below mechanisms only affect unsupported
47 //! targets. Supported targets will _always_ use their supported implementations.
48 //! This prevents a crate from overriding a secure source of randomness
49 //! (either accidentally or intentionally).
50 //!
51 //! ### RDRAND on x86
52 //!
53 //! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
54 //! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
55 //! targets. This feature has no effect on other CPU architectures.
56 //!
57 //! ### WebAssembly support
58 //!
59 //! This crate fully supports the
60 //! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
61 //! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
62 //! targets. However, the `wasm32-unknown-unknown` target is not automatically
63 //! supported since, from the target name alone, we cannot deduce which
64 //! JavaScript interface is in use (or if JavaScript is available at all).
65 //!
66 //! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
67 //! that you are building for an environment containing JavaScript, and will
68 //! call the appropriate methods. Both web browser (main window and Web Workers)
69 //! and Node.js environments are supported, invoking the methods
70 //! [described above](#supported-targets) using the
71 //! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
72 //!
73 //! This feature has no effect on targets other than `wasm32-unknown-unknown`.
74 //!
75 //! ### Custom implementations
76 //!
77 //! The [`register_custom_getrandom!`] macro allows a user to mark their own
78 //! function as the backing implementation for [`getrandom`]. See the macro's
79 //! documentation for more information about writing and registering your own
80 //! custom implementations.
81 //!
82 //! Note that registering a custom implementation only has an effect on targets
83 //! that would otherwise not compile. Any supported targets (including those
84 //! using `"rdrand"` and `"js"` Cargo features) continue using their normal
85 //! implementations even if a function is registered.
86 //!
87 //! ### Indirect Dependencies
88 //!
89 //! If `getrandom` is not a direct dependency of your crate, you can still
90 //! enable any of the above fallback behaviors by enabling the relevant
91 //! feature in your root crate's `Cargo.toml`:
92 //! ```toml
93 //! [dependencies]
94 //! getrandom = { version = "0.2", features = ["js"] }
95 //! ```
96 //!
97 //! ## Early boot
98 //!
99 //! Sometimes, early in the boot process, the OS has not collected enough
100 //! entropy to securely seed its RNG. This is especially common on virtual
101 //! machines, where standard "random" events are hard to come by.
102 //!
103 //! Some operating system interfaces always block until the RNG is securely
104 //! seeded. This can take anywhere from a few seconds to more than a minute.
105 //! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
106 //! getting an error; in these cases, we always choose to block.
107 //!
108 //! On Linux (when the `getrandom` system call is not available), reading from
109 //! `/dev/urandom` never blocks, even when the OS hasn't collected enough
110 //! entropy yet. To avoid returning low-entropy bytes, we first poll
111 //! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
112 //!
113 //! ## Error handling
114 //!
115 //! We always choose failure over returning insecure "random" bytes. In general,
116 //! on supported platforms, failure is highly unlikely, though not impossible.
117 //! If an error does occur, then it is likely that it will occur on every call to
118 //! `getrandom`, hence after the first successful call one can be reasonably
119 //! confident that no errors will occur.
120 //!
121 //! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
122 //! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
123 //! [3]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
124 //! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
125 //! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
126 //! [6]: https://man.openbsd.org/getentropy.2
127 //! [7]: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7+NetBSD-8.0
128 //! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4
129 //! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
130 //! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
131 //! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
132 //! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
133 //! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
134 //! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
135 //! [16]: #webassembly-support
136 //! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
137 //! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
138 //! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
139 //! [20]: https://www.unix.com/man-page/mojave/4/random/
140 //! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
141
142 #![doc(
143 html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
144 html_favicon_url = "https://www.rust-lang.org/favicon.ico",
145 html_root_url = "https://docs.rs/getrandom/0.2.2"
146 )]
147 #![no_std]
148 #![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
149 #![cfg_attr(docsrs, feature(doc_cfg))]
150
151 #[macro_use]
152 extern crate cfg_if;
153
154 mod error;
155 mod util;
156 // To prevent a breaking change when targets are added, we always export the
157 // register_custom_getrandom macro, so old Custom RNG crates continue to build.
158 #[cfg(feature = "custom")]
159 mod custom;
160 #[cfg(feature = "std")]
161 mod error_impls;
162
163 pub use crate::error::Error;
164
165 // System-specific implementations.
166 //
167 // These should all provide getrandom_inner with the same signature as getrandom.
168 cfg_if! {
169 if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
170 target_os = "haiku", target_os = "redox"))] {
171 mod util_libc;
172 #[path = "use_file.rs"] mod imp;
173 } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
174 mod util_libc;
175 mod use_file;
176 #[path = "linux_android.rs"] mod imp;
177 } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
178 mod util_libc;
179 mod use_file;
180 #[path = "solaris_illumos.rs"] mod imp;
181 } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
182 mod util_libc;
183 #[path = "bsd_arandom.rs"] mod imp;
184 } else if #[cfg(target_os = "fuchsia")] {
185 #[path = "fuchsia.rs"] mod imp;
186 } else if #[cfg(target_os = "ios")] {
187 #[path = "ios.rs"] mod imp;
188 } else if #[cfg(target_os = "macos")] {
189 mod util_libc;
190 mod use_file;
191 #[path = "macos.rs"] mod imp;
192 } else if #[cfg(target_os = "openbsd")] {
193 mod util_libc;
194 #[path = "openbsd.rs"] mod imp;
195 } else if #[cfg(target_os = "wasi")] {
196 #[path = "wasi.rs"] mod imp;
197 } else if #[cfg(target_os = "vxworks")] {
198 mod util_libc;
199 #[path = "vxworks.rs"] mod imp;
200 } else if #[cfg(windows)] {
201 #[path = "windows.rs"] mod imp;
202 } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
203 #[path = "rdrand.rs"] mod imp;
204 } else if #[cfg(all(feature = "rdrand",
205 any(target_arch = "x86_64", target_arch = "x86")))] {
206 #[path = "rdrand.rs"] mod imp;
207 } else if #[cfg(all(feature = "js",
208 target_arch = "wasm32", target_os = "unknown"))] {
209 #[path = "js.rs"] mod imp;
210 } else if #[cfg(feature = "custom")] {
211 use custom as imp;
212 } else {
213 compile_error!("target is not supported, for more information see: \
214 https://docs.rs/getrandom/#unsupported-targets");
215 }
216 }
217
218 /// Fill `dest` with random bytes from the system's preferred random number
219 /// source.
220 ///
221 /// This function returns an error on any failure, including partial reads. We
222 /// make no guarantees regarding the contents of `dest` on error. If `dest` is
223 /// empty, `getrandom` immediately returns success, making no calls to the
224 /// underlying operating system.
225 ///
226 /// Blocking is possible, at least during early boot; see module documentation.
227 ///
228 /// In general, `getrandom` will be fast enough for interactive usage, though
229 /// significantly slower than a user-space CSPRNG; for the latter consider
230 /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
getrandom(dest: &mut [u8]) -> Result<(), Error>231 pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
232 if dest.is_empty() {
233 return Ok(());
234 }
235 imp::getrandom_inner(dest)
236 }
237