2 releases
new 0.2.17 | Nov 2, 2024 |
---|---|
0.2.15 | Nov 1, 2024 |
#110 in Operating systems
259 downloads per month
98KB
1K
SLoC
getrandom: system's random number generator
getrandom
is a Rust library for retrieving random data from (operating) system sources.
It is assumed that the system always provides high-quality, cryptographically secure random
data, ideally backed by hardware entropy sources. This crate derives its name from
the Linux getrandom
syscall but is cross-platform, roughly supporting the same set
of platforms as Rust's std
library.
This is a low-level API. Most users should prefer using a higher-level random-number
library like rand
.
Usage
Add the getrandom
dependency to your Cargo.toml
file:
[dependencies]
getrandom = "0.3"
Then invoke the fill
function on a byte buffer to fill it with random data:
fn get_random_u128() -> Result<u128, getrandom::Error> {
let mut buf = [0u8; 16];
getrandom::fill(&mut buf)?;
Ok(u128::from_ne_bytes(buf))
}
Supported targets
Target | Target Triple | Implementation |
---|---|---|
Linux, Android | *‑linux‑* |
getrandom system call if available, otherwise /dev/urandom after successfully polling /dev/random |
Windows 10+ | *‑windows‑* |
ProcessPrng |
Windows 7, 8 | *-win7‑windows‑* |
RtlGenRandom |
macOS | *‑apple‑darwin |
getentropy |
iOS, tvOS, watchOS | *‑apple‑{ios,tvos,watchos} |
CCRandomGenerateBytes |
FreeBSD | *‑freebsd |
getrandom |
OpenBSD | *‑openbsd |
getentropy |
NetBSD | *‑netbsd |
getrandom if available, otherwise kern.arandom |
Dragonfly BSD | *‑dragonfly |
getrandom |
Solaris | *‑solaris |
getrandom with GRND_RANDOM |
illumos | *‑illumos |
getrandom |
Fuchsia OS | *‑fuchsia |
cprng_draw |
Redox | *‑redox |
/dev/urandom |
Haiku | *‑haiku |
/dev/urandom (identical to /dev/random ) |
Hermit | *-hermit |
sys_read_entropy |
Hurd | *-hurd-* |
getrandom |
SGX | x86_64‑*‑sgx |
RDRAND |
VxWorks | *‑wrs‑vxworks‑* |
randABytes after checking entropy pool initialization with randSecure |
Emscripten | *‑emscripten |
getentropy |
WASI 0.1 | wasm32‑wasip1 |
random_get |
WASI 0.2 | wasm32‑wasip2 |
get-random-u64 |
SOLID | *-kmc-solid_* |
SOLID_RNG_SampleRandomBytes |
Nintendo 3DS | *-nintendo-3ds |
getrandom |
PS Vita | *-vita-* |
getentropy |
QNX Neutrino | *‑nto-qnx* |
/dev/urandom (identical to /dev/random ) |
AIX | *-ibm-aix |
/dev/urandom |
Pull Requests that add support for new targets to getrandom
are always welcome.
Opt-in backends
getrandom
also provides optional (opt-in) backends, which allow users to customize the source
of randomness based on their specific needs:
Backend name | Target | Target Triple | Implementation |
---|---|---|---|
linux_getrandom |
Linux, Android | *‑linux‑* |
getrandom system call (without /dev/urandom fallback). Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow). |
linux_rustix |
Linux, Android | *‑linux‑* |
Same as linux_getrandom , but uses rustix instead of libc . |
rdrand |
x86, x86-64 | x86_64-* , i686-* |
RDRAND instruction |
rndr |
AArch64 | aarch64-* |
RNDR register |
esp_idf |
ESP-IDF | *‑espidf |
esp_fill_random . WARNING: can return low-quality entropy without proper hardware configuration! |
wasm_js |
Web Browser, Node.js | wasm*‑*‑unknown |
Crypto.getRandomValues if available, then crypto.randomFillSync if on Node.js (see WebAssembly support) |
custom |
All targets | * |
User-provided custom implementation (see custom backend) |
Opt-in backends can be enabled using the getrandom_backend
configuration flag.
The flag can be set either by specifying the rustflags
field in
.cargo/config.toml
(note that it can be done on a per-target basis), or by using
the RUSTFLAGS
environment variable:
RUSTFLAGS='--cfg getrandom_backend="linux_getrandom"' cargo build
Enabling an opt-in backend will replace the backend used by default. Doing this for
an incorrect target (e.g. using linux_getrandom
while compiling for a Windows target)
will result in a compilation error. Be extremely careful while using opt-in backends,
as incorrect configuration may result in vulnerable applications or applications
that always panic.
Note that using an opt-in backend in a library (e.g. for tests or benchmarks) WILL NOT have any effect on its downstream users.
WebAssembly support
This crate fully supports the WASI and Emscripten targets. However,
the wasm32-unknown-unknown
target (i.e. the target used by wasm-pack
)
is not automatically supported since, from the target name alone, we cannot deduce
which JavaScript interface should be used (or if JavaScript is available at all).
Instead, if the wasm_js
backend 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 using the wasm-bindgen
toolchain.
To enable the wasm_js
backend, you can add the following lines to your
project's .cargo/config.toml
file:
[target.wasm32-unknown-unknown]
rustflags = ['--cfg', 'getrandom_backend="wasm_js"']
Node.js ES module support
Node.js supports both CommonJS modules and ES modules. Due to
limitations in wasm-bindgen's module
support, we cannot directly
support ES Modules running on Node.js. However, on Node v15 and later, the
module author can add a simple shim to support the Web Cryptography API:
import { webcrypto } from 'node:crypto'
globalThis.crypto = webcrypto
This crate will then use the provided webcrypto
implementation.
Custom backend
If this crate does not support your target out of the box or you have to use
a non-default entropy source, then you can provide a custom implementation.
You need to enable the custom backend as described in the configuration flags
section. Next, you need to define an extern
function with the following
signature:
use getrandom::Error;
#[no_mangle]
unsafe extern "Rust" fn __getrandom_v03_custom(
dest: *mut u8,
len: usize,
) -> Result<(), Error> {
todo!()
}
This function should, ideally, be defined in the root crate of your project,
e.g. in your main.rs
. This function MUST be defined only once for your
project, i.e. upstream library crates SHOULD NOT define it outside of
tests and benchmarks. Improper configuration of this backend may result
in linking errors.
The function accepts a pointer to a buffer that should be filled with random
data and its length in bytes. Note that the buffer MAY be uninitialized.
On success, the function should return Ok(())
and fully fill the input buffer;
otherwise, it should return an error value.
If you are confident that getrandom
is not used in your project, but
it gets pulled nevertheless by one of your dependencies, then you can
use the following custom backend, which always returns the "unsupported" error:
use getrandom::Error;
#[no_mangle]
unsafe extern "Rust" fn __getrandom_v03_custom(
dest: *mut u8,
len: usize,
) -> Result<(), Error> {
Err(Error::UNSUPPORTED)
}
Platform Support
This crate generally supports the same operating system and platform versions that the Rust standard library does. Additional targets may be supported using the opt-in custom backend.
This means that as Rust drops support for old versions of operating systems
(such as old Linux kernel versions, Android API levels, etc.) in stable releases,
getrandom
may create new patch releases that remove support for
outdated platform versions.
/dev/urandom
fallback on Linux and Android
On Linux targets, the /dev/urandom
fallback is present only if either target_env
is musl
, or target_arch
is one of the following: aarch64
, arm
, powerpc
,
powerpc64
, s390x
, x86
, x86_64
. Other supported targets require
kernel versions that support the getrandom
system call, so the fallback is not needed.
On Android targets the fallback is present only for the following target_arch
es:
aarch64
, arm
, x86
, x86_64
. Other target_arch
es (e.g. RISC-V) require
sufficiently high API levels.
The fallback can be disabled by enabling the linux_getrandom
opt-in backend.
Note that doing so will bump minimum supported Linux kernel version to 3.17
and Android API level to 23 (Marshmallow).
Early boot
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 system interfaces always block until the RNG is securely seeded. This can take anywhere from a few seconds to more than a minute. 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), 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.
On OpenBSD, this kind of entropy accounting isn't available, and on NetBSD, blocking on it is discouraged. On these platforms, nonblocking interfaces are used, even when reliable entropy may not be available. On the platforms where it is used, the reliability of entropy accounting itself isn't free from controversy. This library provides randomness sourced according to the platform's best practices, but each platform has its own limits on the grade of randomness it can promise in environments with few sources of entropy.
Error handling
We always prioritize failure over returning known insecure "random" bytes.
Generally, on supported platforms, failure is highly unlikely, though not
impossible. If an error does occur, it is likely that it will occur
on every call to getrandom
. Therefore, after the first successful call,
one can be reasonably confident that no errors will occur.
Panic handling
We strive to eliminate all potential panics from our backend implementations.
In other words, when compiled with optimizations enabled, the generated
binary code for getrandom
functions should not contain any panic branches.
Even if the platform misbehaves and returns an unexpected result,
our code should correctly handle it and return an error, e.g.
Error::UNEXPECTED
.
Sanitizer support
If your code uses fill_uninit
and you enable memory sanitization
(i.e. -Zsanitizer=memory
), you need to pass the getrandom_sanitize
configuration flag to enable unpoisoning of the destination buffer
filled by fill_uninit
.
For example, it can be done as follows (requires a Nightly compiler):
RUSTFLAGS="-Zsanitizer=memory --cfg getrandom_sanitize" \
cargo test -Zbuild-std --target=x86_64-unknown-linux-gnu
Minimum Supported Rust Version
This crate requires Rust 1.60.0 or later.
License
The getrandom
library is distributed under either of
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~0–8.5MB
~92K SLoC