Skip to content

Commit 4374fd7

Browse files
committed
Add getrandom wrapper func and documentation
1 parent 24e7f8f commit 4374fd7

16 files changed

+135
-16
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ A Rust library to securely get random entropy. This crate derives its name from
99
Linux's `getrandom` function, but is cross platform, roughly supporting the same
1010
set of platforms as Rust's `std` lib.
1111

12+
This is a low-level API. Most users should prefer a high-level random-number
13+
library like [Rand] or a cryptography library.
14+
15+
[Rand]: https://crates.io/crates/rand
16+
1217

1318
## Usage
1419

@@ -19,7 +24,15 @@ Add this to your `Cargo.toml`:
1924
getrandom = "0.1"
2025
```
2126

22-
TODO
27+
Then invoke the `getrandom` function:
28+
29+
```rust
30+
fn get_random_buf() -> Result<[u8; 32], getrandom::Error> {
31+
let mut buf = [0u8; 32];
32+
getrandom::getrandom(&mut buf)?;
33+
buf
34+
}
35+
```
2336

2437

2538
# License

src/cloudabi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern "C" {
1111
fn cloudabi_sys_random_get(buf: *mut u8, len: usize) -> u16;
1212
}
1313

14-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
14+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1515
let errno = unsafe { cloudabi_sys_random_get(dest.as_ptr(), dest.len()) };
1616
if errno == 0 {
1717
Ok(())

src/dragonfly_haiku.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::cell::RefCell;
1515

1616
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
1717

18-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
18+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1919
RNG_FILE.with(|f| {
2020
use_init(f,
2121
|| File::open("/dev/random").map_err(From::from),

src/dummy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
//! `Err(UNAVAILABLE_ERROR)`
1111
use super::UNAVAILABLE_ERROR;
1212

13-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
13+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1414
Err(UNAVAILABLE_ERROR)
1515
}

src/emscripten.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::utils::use_init;
1515

1616
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
1717

18-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
18+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1919
// `Crypto.getRandomValues` documents `dest` should be at most 65536
2020
// bytes. `crypto.randomBytes` documents: "To minimize threadpool
2121
// task length variation, partition large randomBytes requests when

src/freebsd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use super::Error;
1313
use core::ptr;
1414
use std::io;
1515

16-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
16+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1717
let mib = [libc::CTL_KERN, libc::KERN_ARND];
1818
// kern.arandom permits a maximum buffer size of 256 bytes
1919
for chunk in dest.chunks_mut(256) {

src/fuchsia.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern crate fuchsia_cprng;
1111

1212
use super::Error;
1313

14-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
14+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
1515
fuchsia_cprng::cprng_draw(dest);
1616
Ok(())
1717
}

src/lib.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,91 @@
55
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
8+
9+
//! Interface to the random number generator of the operating system.
10+
//!
11+
//! # Platform sources
12+
//!
13+
//! | OS | interface
14+
//! |------------------|---------------------------------------------------------
15+
//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after reading from `/dev/random` once
16+
//! | Windows | [`RtlGenRandom`][3]
17+
//! | macOS, iOS | [`SecRandomCopyBytes`][4]
18+
//! | FreeBSD | [`kern.arandom`][5]
19+
//! | OpenBSD, Bitrig | [`getentropy`][6]
20+
//! | NetBSD | [`/dev/urandom`][7] after reading from `/dev/random` once
21+
//! | Dragonfly BSD | [`/dev/random`][8]
22+
//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
23+
//! | Fuchsia OS | [`cprng_draw`][11]
24+
//! | Redox | [`rand:`][12]
25+
//! | CloudABI | [`random_get`][13]
26+
//! | Haiku | `/dev/random` (identical to `/dev/urandom`)
27+
//! | SGX | RDRAND
28+
//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and ams.js][14])
29+
//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and ams.js][16])
30+
//!
31+
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
32+
//! systems that reads from `/dev/urandom`. This ensures all supported operating
33+
//! systems are using the recommended interface and respect maximum buffer
34+
//! sizes.
35+
//!
36+
//! ## Support for WebAssembly and ams.js
37+
//!
38+
//! The three Emscripten targets `asmjs-unknown-emscripten`,
39+
//! `wasm32-unknown-emscripten` and `wasm32-experimental-emscripten` use
40+
//! Emscripten's emulation of `/dev/random` on web browsers and Node.js.
41+
//!
42+
//! The bare WASM target `wasm32-unknown-unknown` tries to call the javascript
43+
//! methods directly, using either `stdweb` or `wasm-bindgen` depending on what
44+
//! features are activated for this crate. Note that if both features are
45+
//! enabled `wasm-bindgen` will be used.
46+
//!
47+
//! ## Early boot
48+
//!
49+
//! It is possible that early in the boot process the OS hasn't had enough time
50+
//! yet to collect entropy to securely seed its RNG, especially on virtual
51+
//! machines.
52+
//!
53+
//! Some operating systems always block the thread until the RNG is securely
54+
//! seeded. This can take anywhere from a few seconds to more than a minute.
55+
//! Others make a best effort to use a seed from before the shutdown and don't
56+
//! document much.
57+
//!
58+
//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and
59+
//! getting an error; in these cases we always choose to block.
60+
//!
61+
//! On Linux (when the `genrandom` system call is not available) and on NetBSD
62+
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
63+
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
64+
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
65+
//!
66+
//! # Error handling
67+
//!
68+
//! We always choose failure over returning insecure "random" bytes. In general,
69+
//! on supported platforms, failure is unlikely, though not impossible. If an
70+
//! error does occur, then it is likely that it will occur on every call to
71+
//! `getrandom`, hence after the first successful call one can be reasonably
72+
//! confident that no errors will occur.
73+
//!
74+
//! On unsupported platforms, `getrandom` always fails.
75+
//!
76+
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
77+
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
78+
//! [3]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
79+
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
80+
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
81+
//! [6]: https://man.openbsd.org/getentropy.2
82+
//! [7]: http://netbsd.gw.com/cgi-bin/man-cgi?random+4+NetBSD-current
83+
//! [8]: https://leaf.dragonflybsd.org/cgi/web-man?command=random&section=4
84+
//! [9]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
85+
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
86+
//! [11]: https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md
87+
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
88+
//! [13]: https://github.com/NuxiNL/cloudabi/blob/v0.20/cloudabi.txt#L1826
89+
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
90+
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
91+
//! [16]: #support-for-webassembly-and-amsjs
92+
893
#![no_std]
994

1095
#[cfg(not(target_env = "sgx"))]
@@ -24,12 +109,17 @@ mod utils;
24109
mod error;
25110
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
26111

112+
113+
// System-specific implementations.
114+
//
115+
// These should all provide getrandom_os with the same signature as getrandom.
116+
27117
macro_rules! mod_use {
28118
($cond:meta, $module:ident) => {
29119
#[$cond]
30120
mod $module;
31121
#[$cond]
32-
pub use $module::getrandom;
122+
use $module::getrandom_os;
33123
}
34124
}
35125

@@ -100,3 +190,19 @@ mod_use!(
100190
))),
101191
dummy
102192
);
193+
194+
195+
/// Fill `dest` with random bytes from the system's preferred random number
196+
/// source.
197+
///
198+
/// This function returns an error on any failure, including partial reads. We
199+
/// make no guarantees regarding the contents of `dest` on error.
200+
///
201+
/// Blocking is possible, at least during early boot; see module documentation.
202+
///
203+
/// In general, `getrandom` will be fast enough for interactive usage, though
204+
/// significantly slower than a user-space CSPRNG; for the latter consider
205+
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
206+
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
207+
getrandom_os(dest)
208+
}

src/linux_android.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
3838
Ok(())
3939
}
4040

41-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
41+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
4242
RNG_SOURCE.with(|f| {
4343
use_init(f,
4444
|| {

src/macos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ extern {
2121
) -> c_int;
2222
}
2323

24-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
24+
pub fn getrandom_os(dest: &mut [u8]) -> Result<(), Error> {
2525
let ret = unsafe {
2626
SecRandomCopyBytes(
2727
kSecRandomDefault,

0 commit comments

Comments
 (0)