Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docs for 0.2 Release #135

Merged
merged 10 commits into from
Sep 10, 2020
Merged
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
- cargo doc --no-deps --features=std,custom
- cargo deadlinks --dir target/doc
# Check that our tests pass in the default/minimal configuration
- cargo test --tests --benches
- cargo test --tests --benches --features=std,custom
- cargo generate-lockfile -Z minimal-versions
- cargo test --tests --benches

Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
wasm-bindgen-test = "0.3.12"

[features]
# Implement std-only traits for getrandom::Error
std = []
# Feature to enable fallback RDRAND-based implementation
# Feature to enable fallback RDRAND-based implementation on x86/x86_64
rdrand = []
# Feature to enable JavaScript bindings on wasm32-unknown-unknown
js = ["stdweb", "wasm-bindgen"]
# Feature to enable custom RNG implementations
custom = []
# Unstable feature to support being a libstd dependency
rustc-dep-of-std = ["compiler_builtins", "core"]

# Test/wasm-bindgen only feature to run tests in a browser
# Unstable/test-only feature to run wasm-bindgen tests in a browser
test-in-browser = []

[package.metadata.docs.rs]
Expand Down
25 changes: 4 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,10 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> {
}
```

## Features

This library is `no_std` for every supported target. However, getting randomness
usually requires calling some external system API. This means most platforms
will require linking against system libraries (i.e. `libc` for Unix,
`Advapi32.dll` for Windows, Security framework on iOS, etc...).

For the `wasm32-unknown-unknown` target, one of the following features should be
enabled:

- [`wasm-bindgen`](https://crates.io/crates/wasm_bindgen)
- [`stdweb`](https://crates.io/crates/stdweb)

By default, compiling `getrandom` for an unsupported target will result in
a compilation error. If you want to build an application which uses `getrandom`
for such target, you can either:
- Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
to switch to a custom implementation with a support of your target.

[replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
[patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
For more information about supported targets, entropy sources, `no_std` targets,
crate features, WASM support and Custom RNGs see the
[`getrandom` documentation](https://docs.rs/getrandom/latest) and
[`getrandom::Error` documentation](https://docs.rs/getrandom/latest/getrandom/struct.Error.html).

## Minimum Supported Rust Version

Expand Down
70 changes: 64 additions & 6 deletions src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,79 @@
use crate::Error;
use core::num::NonZeroU32;

/// Register a function to be invoked by `getrandom` on custom targets.
/// Register a function to be invoked by `getrandom` on unsupported targets.
///
/// This function will only be invoked on targets not supported by `getrandom`.
/// This prevents crate dependencies from either inadvertently or maliciously
/// overriding the secure RNG implementations in `getrandom`.
/// *This API requires the `"custom"` Cargo feature to be activated*.
///
/// *This API requires the following crate features to be activated: `custom`*
/// ## Writing a custom `getrandom` implementation
///
/// The function to register must have the same signature as
/// [`getrandom::getrandom`](crate::getrandom). The function can be defined
/// wherever you want, either in root crate or a dependant crate.
///
/// For example, if we wanted a `failure-getrandom` crate containing an
/// implementation that always fails, we would first depend on `getrandom`
/// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`:
/// ```toml
/// [dependencies]
/// getrandom = "0.2"
/// ```
/// Note that the crate containing this function does **not** need to enable the
/// `"custom"` Cargo feature.
///
/// Next, in `failure-getrandom/src/lib.rs`, we define our function:
/// ```rust
/// use core::num::NonZeroU32;
/// use getrandom::Error;
///
/// // Some application-specific error code
/// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42;
/// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> {
/// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap();
/// Err(Error::from(code))
/// }
/// ```
///
/// ## Registering a custom `getrandom` implementation
///
/// Functions can only be registered in the root binary crate. Attempting to
/// register a function in a non-root crate will result in a linker error.
/// This is similar to
/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
/// where helper crates define handlers/allocators but only the binary crate
/// actually _uses_ the functionality.
///
/// To register the function, we first depend on `failure-getrandom` _and_
/// `getrandom` in `Cargo.toml`:
/// ```toml
/// [dependencies]
/// failure-getrandom = "0.1"
/// getrandom = { version = "0.2", features = ["custom"] }
/// ```
///
/// Then, we register the function in `src/main.rs`:
/// ```rust
/// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } }
/// use failure_getrandom::always_fail;
/// use getrandom::register_custom_getrandom;
///
/// register_custom_getrandom!(always_fail);
/// ```
///
/// Now any user of `getrandom` (direct or indirect) on this target will use the
/// registered function. As noted in the
/// [top-level documentation](index.html#use-a-custom-implementation) this
/// registration only has an effect on unsupported targets.
#[macro_export]
macro_rules! register_custom_getrandom {
($path:path) => {
// We use an extern "C" function to get the guarantees of a stable ABI.
#[no_mangle]
extern "C" fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
let f: fn(&mut [u8]) -> Result<(), ::getrandom::Error> = $path;
let slice = unsafe { ::core::slice::from_raw_parts_mut(dest, len) };
match $path(slice) {
match f(slice) {
Ok(()) => 0,
Err(e) => e.code().get(),
}
Expand Down
8 changes: 7 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@
// except according to those terms.
use core::{fmt, num::NonZeroU32};

/// A small and `no_std` compatible error type.
/// A small and `no_std` compatible error type
///
/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
/// if so, which error code the OS gave the application. If such an error is
/// encountered, please consult with your system documentation.
///
/// Internally this type is a NonZeroU32, with certain values reserved for
/// certain purposes, see [`Error::INTERNAL_START`] and [`Error::CUSTOM_START`].
///
/// *If this crate's `"std"` Cargo feature is enabled*, then:
/// - [`getrandom::Error`][Error] implements
/// [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
/// - [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html) implements
/// [`From<getrandom::Error>`](https://doc.rust-lang.org/std/convert/trait.From.html).
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroU32);

Expand Down
129 changes: 77 additions & 52 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interface to the random number generator of the operating system.
//! Interface to the operating system's random number generator.
//!
//! # Platform sources
//! # Supported targets
//!
//! | OS | interface
//! | Target | Implementation
//! |------------------|---------------------------------------------------------
josephlr marked this conversation as resolved.
Show resolved Hide resolved
//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
//! | Windows | [`RtlGenRandom`][3]
//! | [Windows UWP][22]| [`BCryptGenRandom`][23]
//! | macOS | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
//! | iOS | [`SecRandomCopyBytes`][4]
//! | FreeBSD | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
Expand All @@ -27,75 +28,99 @@
//! | Haiku | `/dev/random` (identical to `/dev/urandom`)
//! | SGX | [RDRAND][18]
//! | VxWorks | `randABytes` after checking entropy pool initialization with `randSecure`
//! | Web browsers | [`Crypto.getRandomValues`][14] (see [Support for WebAssembly and asm.js][16])
//! | Node.js | [`crypto.randomBytes`][15] (see [Support for WebAssembly and asm.js][16])
//! | Emscripten | `/dev/random` (identical to `/dev/urandom`)
//! | WASI | [`__wasi_random_get`][17]
//! | Web Browser | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16]
//! | Node.js | [`crypto.randomBytes`][15], see [WebAssembly support][16]
//!
//! Getrandom doesn't have a blanket implementation for all Unix-like operating
//! systems that reads from `/dev/urandom`. This ensures all supported operating
//! systems are using the recommended interface and respect maximum buffer
//! sizes.
//! There is no blanket implementation on `unix` targets that reads from
//! `/dev/urandom`. This ensures all supported targets are using the recommended
//! interface and respect maximum buffer sizes.
//!
//! Pull Requests that add support for new targets to `getrandom` are always welcome.
//!
//! ## Unsupported targets
//!
//! By default, compiling `getrandom` for an unsupported target will result in
//! a compilation error. If you want to build an application which uses `getrandom`
//! for such target, you can either:
//! - Use [`[replace]`][replace] or [`[patch]`][patch] section in your `Cargo.toml`
//! to switch to a custom implementation with a support of your target.
//! By default, `getrandom` will not compile on unsupported targets, but certain
//! features allow a user to select a "fallback" implementation if no supported
//! implementation exists.
//!
//! All of the below mechanisms only affect unsupported
//! targets. Supported targets will _always_ use their supported implementations.
//! This prevents a crate from overriding a secure source of randomness
//! (either accidentally or intentionally).
//!
//! ### RDRAND on x86
//!
//! *If the `"rdrand"` Cargo feature is enabled*, `getrandom` will fallback to using
//! the [`RDRAND`][18] instruction to get randomness on `no_std` `x86`/`x86_64`
//! targets. This feature has no effect on other CPU architectures.
//!
//! ### WebAssembly support
//!
//! [replace]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-replace-section
//! [patch]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section
//! This crate fully supports the
//! [`wasm32-wasi`](https://github.com/CraneStation/wasi) and
//! [`wasm32-unknown-emscripten`](https://www.hellorust.com/setup/emscripten/)
//! targets. However, the `wasm32-unknown-unknown` target is not automatically
//! supported since, from the target name alone, we cannot deduce which
//! JavaScript interface is in use (or if JavaScript is available at all).
//!
//! ## Support for WebAssembly and asm.js
//! Instead, *if the `"js"` Cargo feature is enabled*, this crate will assume
//! that you are building for an environment containing JavaScript, and will
//! call the appropriate methods. Both web browser (main window and Web Workers)
//! and Node.js environments are supported, invoking the methods
//! [described above](#supported-targets). This crate can be built with either
//! the [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) or
//! [cargo-web](https://github.com/koute/cargo-web) toolchains.
//!
//! Getrandom supports all of Rust's current `wasm32` targets, and it works with
//! both Node.js and web browsers. The three Emscripten targets
//! `asmjs-unknown-emscripten`, `wasm32-unknown-emscripten`, and
//! `wasm32-experimental-emscripten` use Emscripten's `/dev/random` emulation.
//! The WASI target `wasm32-wasi` uses the [`__wasi_random_get`][17] function
//! defined by the WASI standard.
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
//! Getrandom also supports `wasm32-unknown-unknown` by directly calling
//! JavaScript methods. Rust currently has two ways to do this: [bindgen] and
//! [stdweb]. Getrandom supports using either one by enabling the
//! `wasm-bindgen` or `stdweb` crate features. Note that if both features are
//! enabled, `wasm-bindgen` will be used. If neither feature is enabled, calls
//! to `getrandom` will always fail at runtime.
//! ### Custom implementations
//!
//! [bindgen]: https://github.com/rust-lang/rust-bindgen
//! [stdweb]: https://github.com/koute/stdweb
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
//! function as the backing implementation for [`getrandom`]. See the macro's
//! documentation for more information about writing and registering your own
//! custom implementations.
//!
//! Note that registering a custom implementation only has an effect on targets
//! that would otherwise not compile. Any supported targets (including those
//! using `"rdrand"` and `"js"` Cargo features) continue using their normal
//! implementations even if a function is registered.
//!
//! ### Indirect Dependencies
//!
//! If `getrandom` is not a direct dependency of your crate, you can still
//! enable any of the above fallback behaviors by enabling the relevant
//! feature in your root crate's `Cargo.toml`:
//! ```toml
//! [dependencies]
//! getrandom = { version = "0.2", features = ["js"] }
//! ```
//!
//! ## Early boot
//!
//! It is possible that early in the boot process the OS hasn't had enough time
//! yet to collect entropy to securely seed its RNG, especially on virtual
//! machines.
//! Sometimes, early in the boot process, the OS has not collected enough
//! entropy to securely seed its RNG. This is especially common on virtual
//! machines, where standard "random" events are hard to come by.
//!
//! Some operating systems always block the thread until the RNG is securely
//! Some operating system interfaces always block until the RNG is securely
//! seeded. This can take anywhere from a few seconds to more than a minute.
//! Others make a best effort to use a seed from before the shutdown and don't
//! document much.
//! A few (Linux, NetBSD and Solaris) offer a choice between blocking and
//! getting an error; in these cases, we always choose to block.
//!
//! A few, Linux, NetBSD and Solaris, offer a choice between blocking and
//! getting an error; in these cases we always choose to block.
//!
//! On Linux (when the `getrandom` system call is not available) and on NetBSD
//! reading from `/dev/urandom` never blocks, even when the OS hasn't collected
//! enough entropy yet. To avoid returning low-entropy bytes, we first read from
//! On Linux (when the `getrandom` system call is not available), reading from
//! `/dev/urandom` never blocks, even when the OS hasn't collected enough
//! entropy yet. To avoid returning low-entropy bytes, we first poll
//! `/dev/random` and only switch to `/dev/urandom` once this has succeeded.
//!
//! # Error handling
//! ## Error handling
//!
//! We always choose failure over returning insecure "random" bytes. In general,
//! on supported platforms, failure is highly unlikely, though not impossible.
//! If an error does occur, then it is likely that it will occur on every call to
//! `getrandom`, hence after the first successful call one can be reasonably
//! confident that no errors will occur.
//!
//! On unsupported platforms, `getrandom` always fails. See the [`Error`] type
//! for more information on what data is returned on failure.
//!
//! [1]: http://man7.org/linux/man-pages/man2/getrandom.2.html
//! [2]: http://man7.org/linux/man-pages/man4/urandom.4.html
//! [3]: https://docs.microsoft.com/en-us/windows/desktop/api/ntsecapi/nf-ntsecapi-rtlgenrandom
Expand All @@ -111,12 +136,14 @@
//! [13]: https://github.com/nuxinl/cloudabi#random_get
//! [14]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
//! [15]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [16]: #support-for-webassembly-and-asmjs
//! [16]: #webassembly-support
//! [17]: https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md#__wasi_random_get
//! [18]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [19]: https://www.unix.com/man-page/mojave/2/getentropy/
//! [20]: https://www.unix.com/man-page/mojave/4/random/
//! [21]: https://www.freebsd.org/cgi/man.cgi?query=getrandom&manpath=FreeBSD+12.0-stable
//! [22]: https://docs.microsoft.com/en-us/windows/uwp/
//! [23]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom

#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
Expand Down Expand Up @@ -194,10 +221,8 @@ cfg_if! {
} else if #[cfg(feature = "custom")] {
use custom as imp;
} else {
compile_error!("\
target is not supported, for more information see: \
https://docs.rs/getrandom/#unsupported-targets\
");
compile_error!("target is not supported, for more information see: \
https://docs.rs/getrandom/#unsupported-targets");
}
}

Expand Down