aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiébaud Weksteen <tweek@google.com>2021-03-04 11:08:12 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-03-04 11:08:12 +0000
commit9dd66b2f6c3043fc010adffb533341e972be4d14 (patch)
tree5d3eb1dcf2b8ee84112e1cda41dda22c0adc720f
parentd5294521b0e03f6ab8f908cd3f7a160dd18c41e3 (diff)
parent518a22fe12abbd701061eec546ccd33388a3b7ea (diff)
downloadgetrandom-9dd66b2f6c3043fc010adffb533341e972be4d14.tar.gz
Update to 0.2.2 am: 9791b30a05 am: c725abe846 am: 518a22fe12
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/getrandom/+/1614806 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: Id27700affec6b3c53b1c96b7a13cedd2389444a0
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp97
-rw-r--r--CHANGELOG.md76
-rw-r--r--Cargo.toml47
-rw-r--r--Cargo.toml.orig48
-rw-r--r--METADATA10
-rw-r--r--README.md52
-rw-r--r--TEST_MAPPING24
-rw-r--r--benches/mod.rs1
-rw-r--r--build.rs7
-rw-r--r--src/bsd_arandom.rs11
-rw-r--r--src/cloudabi.rs25
-rw-r--r--src/custom.rs102
-rw-r--r--src/dummy.rs14
-rw-r--r--src/error.rs95
-rw-r--r--src/error_impls.rs15
-rw-r--r--src/ios.rs17
-rw-r--r--src/js.rs106
-rw-r--r--src/lib.rs300
-rw-r--r--src/linux_android.rs8
-rw-r--r--src/macos.rs11
-rw-r--r--src/openbsd.rs7
-rw-r--r--src/rdrand.rs31
-rw-r--r--src/solaris_illumos.rs7
-rw-r--r--src/use_file.rs16
-rw-r--r--src/util.rs2
-rw-r--r--src/util_libc.rs16
-rw-r--r--src/vxworks.rs5
-rw-r--r--src/wasm32_bindgen.rs113
-rw-r--r--src/wasm32_stdweb.rs114
-rw-r--r--src/windows.rs35
-rw-r--r--src/windows_uwp.rs59
-rw-r--r--tests/common/mod.rs (renamed from tests/common.rs)28
-rw-r--r--tests/custom.rs50
-rw-r--r--tests/normal.rs11
-rw-r--r--tests/rdrand.rs15
36 files changed, 797 insertions, 780 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index d17f1ee..64fafa1 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "33b859bae16ae0b1c782e48db2ed96eb2306a2fc"
+ "sha1": "d79de0c95c01860268e071bcb6b0d019e18cd608"
}
}
diff --git a/Android.bp b/Android.bp
index 9b9b8a0..d494d22 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,40 +1,5 @@
-// This file is generated by cargo2android.py --device --run --dependencies --tests.
-
-package {
- default_applicable_licenses: ["external_rust_crates_getrandom_license"],
-}
-
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-//
-// large-scale-change included anything that looked like it might be a license
-// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.
-//
-// Please consider removing redundant or irrelevant files from 'license_text:'.
-// See: http://go/android-license-faq
-license {
- name: "external_rust_crates_getrandom_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-MIT",
- ],
- license_text: [
- "LICENSE-APACHE",
- "LICENSE-MIT",
- ],
-}
+// This file is generated by cargo2android.py --device --run --dependencies --tests --features=std.
+// Do not modify this file as changes will be overridden on upgrade.
rust_defaults {
name: "getrandom_defaults",
@@ -43,6 +8,7 @@ rust_defaults {
test_suites: ["general-tests"],
auto_gen_config: true,
edition: "2018",
+ features: ["std"],
rustlibs: [
"libcfg_if",
"liblibc",
@@ -52,6 +18,9 @@ rust_defaults {
rust_test_host {
name: "getrandom_host_test_src_lib",
defaults: ["getrandom_defaults"],
+ test_options: {
+ unit_test: true,
+ },
}
rust_test {
@@ -60,12 +29,12 @@ rust_test {
}
rust_defaults {
- name: "getrandom_defaults_common",
- crate_name: "common",
- srcs: ["tests/common.rs"],
+ name: "getrandom_defaults_getrandom",
+ crate_name: "getrandom",
test_suites: ["general-tests"],
auto_gen_config: true,
edition: "2018",
+ features: ["std"],
rustlibs: [
"libcfg_if",
"libgetrandom",
@@ -74,13 +43,48 @@ rust_defaults {
}
rust_test_host {
- name: "getrandom_host_test_tests_common",
- defaults: ["getrandom_defaults_common"],
+ name: "getrandom_host_test_tests_custom",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/custom.rs"],
+ test_options: {
+ unit_test: true,
+ },
+}
+
+rust_test {
+ name: "getrandom_device_test_tests_custom",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/custom.rs"],
+}
+
+rust_test_host {
+ name: "getrandom_host_test_tests_normal",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/normal.rs"],
+ test_options: {
+ unit_test: true,
+ },
+}
+
+rust_test {
+ name: "getrandom_device_test_tests_normal",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/normal.rs"],
+}
+
+rust_test_host {
+ name: "getrandom_host_test_tests_rdrand",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/rdrand.rs"],
+ test_options: {
+ unit_test: true,
+ },
}
rust_test {
- name: "getrandom_device_test_tests_common",
- defaults: ["getrandom_defaults_common"],
+ name: "getrandom_device_test_tests_rdrand",
+ defaults: ["getrandom_defaults_getrandom"],
+ srcs: ["tests/rdrand.rs"],
}
rust_library {
@@ -89,6 +93,7 @@ rust_library {
crate_name: "getrandom",
srcs: ["src/lib.rs"],
edition: "2018",
+ features: ["std"],
rustlibs: [
"libcfg_if",
"liblibc",
@@ -96,5 +101,5 @@ rust_library {
}
// dependent_library ["feature_list"]
-// cfg-if-0.1.10
-// libc-0.2.72
+// cfg-if-1.0.0
+// libc-0.2.87
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29b447c..c3ca728 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,82 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.2] - 2021-01-19
+### Changed
+- Forward `rustc-dep-of-std` to dependencies. [#198]
+- Highlight feature-dependend functionality in documentation using the `doc_cfg` feature. [#200]
+
+[#198]: https://github.com/rust-random/getrandom/pull/198
+[#200]: https://github.com/rust-random/getrandom/pull/200
+
+## [0.2.1] - 2021-01-03
+### Changed
+- Update `cfg-if` to v1.0. [#166]
+- Update `wasi` to v0.10. [#167]
+
+### Fixed
+- Multithreaded WASM support. [#165]
+
+### Removed
+- Windows XP support. [#177]
+- Direct `stdweb` support. [#178]
+- CloudABI support. [#184]
+
+[#165]: https://github.com/rust-random/getrandom/pull/165
+[#166]: https://github.com/rust-random/getrandom/pull/166
+[#167]: https://github.com/rust-random/getrandom/pull/167
+[#177]: https://github.com/rust-random/getrandom/pull/177
+[#178]: https://github.com/rust-random/getrandom/pull/178
+[#184]: https://github.com/rust-random/getrandom/pull/184
+
+## [0.2.0] - 2020-09-10
+### Features for using getrandom on unsupported targets
+
+The following (off by default) Cargo features have been added:
+- `"rdrand"` - use the RDRAND instruction on `no_std` `x86`/`x86_64` targets [#133]
+- `"js"` - use JavaScript calls on `wasm32-unknown-unknown` [#149]
+ - Replaces the `stdweb` and `wasm-bindgen` features (which are removed)
+- `"custom"` - allows a user to specify a custom implementation [#109]
+
+### Breaking Changes
+- Unsupported targets no longer compile [#107]
+- Change/Add `Error` constants [#120]
+- Only impl `std` traits when the `"std"` Cargo feature is specified [#106]
+- Remove offical support for Hermit, L4Re, and UEFI [#133]
+- Remove optional `"log"` dependancy [#131]
+- Update minimum supported Linux kernel to 2.6.32 [#153]
+- Update MSRV to 1.34 [#159]
+
+[#106]: https://github.com/rust-random/getrandom/pull/106
+[#107]: https://github.com/rust-random/getrandom/pull/107
+[#109]: https://github.com/rust-random/getrandom/pull/109
+[#120]: https://github.com/rust-random/getrandom/pull/120
+[#131]: https://github.com/rust-random/getrandom/pull/131
+[#133]: https://github.com/rust-random/getrandom/pull/133
+[#149]: https://github.com/rust-random/getrandom/pull/149
+[#153]: https://github.com/rust-random/getrandom/pull/153
+[#159]: https://github.com/rust-random/getrandom/pull/159
+
+## [0.1.16] - 2020-12-31
+### Changed
+- Update `cfg-if` to v1.0. [#173]
+- Implement `std::error::Error` for the `Error` type on additional targets. [#169]
+
+### Fixed
+- Multithreaded WASM support. [#171]
+
+[#173]: https://github.com/rust-random/getrandom/pull/173
+[#171]: https://github.com/rust-random/getrandom/pull/171
+[#169]: https://github.com/rust-random/getrandom/pull/169
+
+## [0.1.15] - 2020-09-10
+### Changed
+- Added support for Internet Explorer 11 [#139]
+- Fix Webpack require warning with `wasm-bindgen` [#137]
+
+[#137]: https://github.com/rust-random/getrandom/pull/137
+[#139]: https://github.com/rust-random/getrandom/pull/139
+
## [0.1.14] - 2020-01-07
### Changed
- Remove use of spin-locks in the `use_file` module. [#125]
diff --git a/Cargo.toml b/Cargo.toml
index 1c1f718..2c0c056 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,16 +13,19 @@
[package]
edition = "2018"
name = "getrandom"
-version = "0.1.14"
+version = "0.2.2"
authors = ["The Rand Project Developers"]
-exclude = ["utils/*", ".*", "appveyor.yml"]
+exclude = [".*"]
description = "A small cross-platform library for retrieving random data from system source"
documentation = "https://docs.rs/getrandom"
categories = ["os", "no-std"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-random/getrandom"
+[package.metadata.docs.rs]
+features = ["std", "custom"]
+rustdoc-args = ["--cfg", "docsrs"]
[dependencies.cfg-if]
-version = "0.1.2"
+version = "1"
[dependencies.compiler_builtins]
version = "0.1"
@@ -33,31 +36,25 @@ version = "1.0"
optional = true
package = "rustc-std-workspace-core"
-[dependencies.log]
-version = "0.4"
-optional = true
-
[features]
-dummy = []
-rustc-dep-of-std = ["compiler_builtins", "core"]
+custom = []
+js = ["wasm-bindgen", "js-sys"]
+rdrand = []
+rustc-dep-of-std = ["compiler_builtins", "core", "libc/rustc-dep-of-std", "wasi/rustc-dep-of-std"]
std = []
-test-in-browser = ["wasm-bindgen"]
+test-in-browser = []
+[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.js-sys]
+version = "0.3"
+optional = true
+
+[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dependencies.wasm-bindgen]
+version = "0.2.62"
+optional = true
+default-features = false
+[target."cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))".dev-dependencies.wasm-bindgen-test]
+version = "0.3.18"
[target."cfg(target_os = \"wasi\")".dependencies.wasi]
-version = "0.9"
+version = "0.10"
[target."cfg(unix)".dependencies.libc]
version = "0.2.64"
default-features = false
-[target.wasm32-unknown-unknown.dependencies.stdweb]
-version = "0.4.18"
-optional = true
-
-[target.wasm32-unknown-unknown.dependencies.wasm-bindgen]
-version = "0.2.29"
-optional = true
-[target.wasm32-unknown-unknown.dev-dependencies.wasm-bindgen-test]
-version = "0.2"
-[badges.appveyor]
-repository = "rust-random/getrandom"
-
-[badges.travis-ci]
-repository = "rust-random/getrandom"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index d10183f..dabf016 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "getrandom"
-version = "0.1.14"
+version = "0.2.2" # Also update html_root_url in lib.rs when bumping this
edition = "2018"
authors = ["The Rand Project Developers"]
license = "MIT OR Apache-2.0"
@@ -8,15 +8,10 @@ description = "A small cross-platform library for retrieving random data from sy
documentation = "https://docs.rs/getrandom"
repository = "https://github.com/rust-random/getrandom"
categories = ["os", "no-std"]
-exclude = ["utils/*", ".*", "appveyor.yml"]
-
-[badges]
-travis-ci = { repository = "rust-random/getrandom" }
-appveyor = { repository = "rust-random/getrandom" }
+exclude = [".*"]
[dependencies]
-log = { version = "0.4", optional = true }
-cfg-if = "0.1.2"
+cfg-if = "1"
# When built as part of libstd
compiler_builtins = { version = "0.1", optional = true }
@@ -26,20 +21,33 @@ core = { version = "1.0", optional = true, package = "rustc-std-workspace-core"
libc = { version = "0.2.64", default-features = false }
[target.'cfg(target_os = "wasi")'.dependencies]
-wasi = "0.9"
-
-[target.wasm32-unknown-unknown.dependencies]
-wasm-bindgen = { version = "0.2.29", optional = true }
-stdweb = { version = "0.4.18", optional = true }
+wasi = "0.10"
-[target.wasm32-unknown-unknown.dev-dependencies]
-wasm-bindgen-test = "0.2"
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
+wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
+js-sys = { version = "0.3", optional = true }
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
+wasm-bindgen-test = "0.3.18"
[features]
+# Implement std-only traits for getrandom::Error
std = []
-# Enables dummy implementation for unsupported targets
-dummy = []
+# Feature to enable fallback RDRAND-based implementation on x86/x86_64
+rdrand = []
+# Feature to enable JavaScript bindings on wasm32-unknown-unknown
+js = ["wasm-bindgen", "js-sys"]
+# Feature to enable custom RNG implementations
+custom = []
# Unstable feature to support being a libstd dependency
-rustc-dep-of-std = ["compiler_builtins", "core"]
-# Unstable feature for testing
-test-in-browser = ["wasm-bindgen"]
+rustc-dep-of-std = [
+ "compiler_builtins",
+ "core",
+ "libc/rustc-dep-of-std",
+ "wasi/rustc-dep-of-std",
+]
+# Unstable/test-only feature to run wasm-bindgen tests in a browser
+test-in-browser = []
+
+[package.metadata.docs.rs]
+features = ["std", "custom"]
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/METADATA b/METADATA
index 27f871d..60dca65 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/getrandom/getrandom-0.1.14.crate"
+ value: "https://static.crates.io/crates/getrandom/getrandom-0.2.2.crate"
}
- version: "0.1.14"
+ version: "0.2.2"
license_type: NOTICE
last_upgrade_date {
- year: 2020
- month: 6
- day: 18
+ year: 2021
+ month: 3
+ day: 3
}
}
diff --git a/README.md b/README.md
index 01bbfb5..df2307b 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,18 @@
# getrandom
-[![Build Status](https://travis-ci.org/rust-random/getrandom.svg?branch=master)](https://travis-ci.org/rust-random/getrandom)
-[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/getrandom?svg=true)](https://ci.appveyor.com/project/rust-random/getrandom)
-[![Crate](https://img.shields.io/crates/v/getrandom.svg)](https://crates.io/crates/getrandom)
-[![Documentation](https://docs.rs/getrandom/badge.svg)](https://docs.rs/getrandom)
-[![Dependency status](https://deps.rs/repo/github/rust-random/getrandom/status.svg)](https://deps.rs/repo/github/rust-random/getrandom)
+[![Build Status]][GitHub Actions] [![Crate]][crates.io] [![Documentation]][docs.rs] [![Dependency Status]][deps.rs] [![Downloads]][crates.io] [![License]][LICENSE-MIT]
+
+[GitHub Actions]: https://github.com/rust-random/getrandom/actions?query=workflow:Tests+branch:master
+[Build Status]: https://github.com/rust-random/getrandom/workflows/Tests/badge.svg?branch=master
+[crates.io]: https://crates.io/crates/getrandom
+[Crate]: https://img.shields.io/crates/v/getrandom
+[docs.rs]: https://docs.rs/getrandom
+[Documentation]: https://docs.rs/getrandom/badge.svg
+[deps.rs]: https://deps.rs/repo/github/rust-random/getrandom
+[Dependency Status]: https://deps.rs/repo/github/rust-random/getrandom/status.svg
+[Downloads]: https://img.shields.io/crates/d/getrandom
+[LICENSE-MIT]: https://raw.githubusercontent.com/rust-random/getrandom/master/LICENSE-MIT
+[License]: https://img.shields.io/crates/l/getrandom
A Rust library for retrieving random data from (operating) system source. It is
@@ -24,7 +32,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
-getrandom = "0.1"
+getrandom = "0.2"
```
Then invoke the `getrandom` function:
@@ -37,36 +45,14 @@ 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...).
-
-The `log` library is supported as an optional dependency. If enabled, error
-reporting will be improved on some platforms.
-
-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.
-- Enable the `dummy` feature to have getrandom use an implementation that always
-fails at run-time on unsupported targets.
-
-[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
-This crate requires Rust 1.32.0 or later.
+This crate requires Rust 1.34.0 or later.
# License
diff --git a/TEST_MAPPING b/TEST_MAPPING
index bc55ed7..efa80d7 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -1,14 +1,32 @@
-// Generated by cargo2android.py for tests in Android.bp
+// Generated by update_crate_tests.py for tests that depend on this crate.
{
"presubmit": [
{
- "name": "getrandom_device_test_src_lib"
+ "name": "keystore2_test"
+ },
+ {
+ "name": "getrandom_device_test_tests_custom"
+ },
+ {
+ "name": "rand_xorshift_device_test_tests_mod"
+ },
+ {
+ "name": "getrandom_device_test_tests_normal"
},
{
- "name": "getrandom_device_test_tests_common"
+ "name": "rand_xorshift_device_test_src_lib"
+ },
+ {
+ "name": "getrandom_device_test_tests_rdrand"
},
{
"name": "rand_core_device_test_src_lib"
+ },
+ {
+ "name": "getrandom_device_test_src_lib"
+ },
+ {
+ "name": "vpnprofilestore_test"
}
]
}
diff --git a/benches/mod.rs b/benches/mod.rs
index 07953f1..a93e720 100644
--- a/benches/mod.rs
+++ b/benches/mod.rs
@@ -1,5 +1,4 @@
#![feature(test)]
-extern crate getrandom;
extern crate test;
#[bench]
diff --git a/build.rs b/build.rs
index 1beb4ed..95f4b90 100644
--- a/build.rs
+++ b/build.rs
@@ -4,14 +4,9 @@ use std::env;
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
- if target.contains("-uwp-windows-") {
+ if target.contains("windows") {
// for BCryptGenRandom
println!("cargo:rustc-link-lib=bcrypt");
- // to work around unavailability of `target_vendor` on Rust 1.33
- println!("cargo:rustc-cfg=getrandom_uwp");
- } else if target.contains("windows") {
- // for RtlGenRandom (aka SystemFunction036)
- println!("cargo:rustc-link-lib=advapi32");
} else if target.contains("apple-ios") {
// for SecRandomCopyBytes and kSecRandomDefault
println!("cargo:rustc-link-lib=framework=Security");
diff --git a/src/bsd_arandom.rs b/src/bsd_arandom.rs
index eb564ff..f26f260 100644
--- a/src/bsd_arandom.rs
+++ b/src/bsd_arandom.rs
@@ -7,8 +7,7 @@
// except according to those terms.
//! Implementation for FreeBSD and NetBSD
-use crate::util_libc::sys_fill_exact;
-use crate::Error;
+use crate::{util_libc::sys_fill_exact, Error};
use core::ptr;
fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
@@ -25,7 +24,6 @@ fn kern_arnd(buf: &mut [u8]) -> libc::ssize_t {
)
};
if ret == -1 {
- error!("sysctl kern.arandom: syscall failed");
-1
} else {
len as libc::ssize_t
@@ -45,5 +43,10 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
return sys_fill_exact(dest, |buf| unsafe { func(buf.as_mut_ptr(), buf.len(), 0) });
}
}
- sys_fill_exact(dest, kern_arnd)
+ // Both FreeBSD and NetBSD will only return up to 256 bytes at a time, and
+ // older NetBSD kernels will fail on longer buffers.
+ for chunk in dest.chunks_mut(256) {
+ sys_fill_exact(chunk, kern_arnd)?
+ }
+ Ok(())
}
diff --git a/src/cloudabi.rs b/src/cloudabi.rs
deleted file mode 100644
index d3d0928..0000000
--- a/src/cloudabi.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation for CloudABI
-use crate::Error;
-use core::num::NonZeroU32;
-
-extern "C" {
- fn cloudabi_sys_random_get(buf: *mut u8, buf_len: usize) -> u16;
-}
-
-pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
- let errno = unsafe { cloudabi_sys_random_get(dest.as_mut_ptr(), dest.len()) };
- if let Some(code) = NonZeroU32::new(errno as u32) {
- error!("cloudabi_sys_random_get: failed with {}", errno);
- Err(Error::from(code))
- } else {
- Ok(()) // Zero means success for CloudABI
- }
-}
diff --git a/src/custom.rs b/src/custom.rs
new file mode 100644
index 0000000..0d3123c
--- /dev/null
+++ b/src/custom.rs
@@ -0,0 +1,102 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! An implementation which calls out to an externally defined function.
+use crate::Error;
+use core::num::NonZeroU32;
+
+/// Register a function to be invoked by `getrandom` on unsupported targets.
+///
+/// ## 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#custom-implementations) this
+/// registration only has an effect on unsupported targets.
+#[macro_export]
+#[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
+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 f(slice) {
+ Ok(()) => 0,
+ Err(e) => e.code().get(),
+ }
+ }
+ };
+}
+
+#[allow(dead_code)]
+pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
+ extern "C" {
+ fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
+ }
+ let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
+ match NonZeroU32::new(ret) {
+ None => Ok(()),
+ Some(code) => Err(Error::from(code)),
+ }
+}
diff --git a/src/dummy.rs b/src/dummy.rs
deleted file mode 100644
index 0c24ba0..0000000
--- a/src/dummy.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A dummy implementation for unsupported targets which always fails
-use crate::{error::UNSUPPORTED, Error};
-
-pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> {
- Err(UNSUPPORTED)
-}
diff --git a/src/error.rs b/src/error.rs
index 31ae24d..48abdc1 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -5,10 +5,9 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use core::fmt;
-use core::num::NonZeroU32;
+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
@@ -16,16 +15,44 @@ use core::num::NonZeroU32;
///
/// 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);
+const fn internal_error(n: u16) -> Error {
+ // SAFETY: code > 0 as INTERNAL_START > 0 and adding n won't overflow a u32.
+ let code = Error::INTERNAL_START + (n as u32);
+ Error(unsafe { NonZeroU32::new_unchecked(code) })
+}
+
impl Error {
- #[deprecated(since = "0.1.7")]
- /// Unknown error.
- pub const UNKNOWN: Error = UNSUPPORTED;
- #[deprecated(since = "0.1.7")]
- /// System entropy source is unavailable.
- pub const UNAVAILABLE: Error = UNSUPPORTED;
+ /// This target/platform is not supported by `getrandom`.
+ pub const UNSUPPORTED: Error = internal_error(0);
+ /// The platform-specific `errno` returned a non-positive value.
+ pub const ERRNO_NOT_POSITIVE: Error = internal_error(1);
+ /// Call to iOS [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
+ pub const IOS_SEC_RANDOM: Error = internal_error(3);
+ /// Call to Windows [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
+ pub const WINDOWS_RTL_GEN_RANDOM: Error = internal_error(4);
+ /// RDRAND instruction failed due to a hardware issue.
+ pub const FAILED_RDRAND: Error = internal_error(5);
+ /// RDRAND instruction unsupported on this target.
+ pub const NO_RDRAND: Error = internal_error(6);
+ /// The browser does not have support for `self.crypto`.
+ pub const WEB_CRYPTO: Error = internal_error(7);
+ /// The browser does not have support for `crypto.getRandomValues`.
+ pub const WEB_GET_RANDOM_VALUES: Error = internal_error(8);
+ /// On VxWorks, call to `randSecure` failed (random number generator is not yet initialized).
+ pub const VXWORKS_RAND_SECURE: Error = internal_error(11);
+ /// NodeJS does not have support for the `crypto` module.
+ pub const NODE_CRYPTO: Error = internal_error(12);
+ /// NodeJS does not have support for `crypto.randomFillSync`.
+ pub const NODE_RANDOM_FILL_SYNC: Error = internal_error(13);
/// Codes below this point represent OS Errors (i.e. positive i32 values).
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
@@ -38,9 +65,11 @@ impl Error {
/// Extract the raw OS error code (if this error came from the OS)
///
- /// This method is identical to `std::io::Error::raw_os_error()`, except
+ /// This method is identical to [`std::io::Error::raw_os_error()`][1], except
/// that it works in `no_std` contexts. If this method returns `None`, the
/// error value can still be formatted via the `Display` implementation.
+ ///
+ /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
#[inline]
pub fn raw_os_error(self) -> Option<i32> {
if self.0.get() < Self::INTERNAL_START {
@@ -55,7 +84,7 @@ impl Error {
/// This code can either come from the underlying OS, or be a custom error.
/// Use [`Error::raw_os_error()`] to disambiguate.
#[inline]
- pub fn code(self) -> NonZeroU32 {
+ pub const fn code(self) -> NonZeroU32 {
self.0
}
}
@@ -125,41 +154,19 @@ impl From<NonZeroU32> for Error {
}
}
-// TODO: Convert to a function when min_version >= 1.33
-macro_rules! internal_error {
- ($n:expr) => {
- Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) })
- };
-}
-
-/// Internal Error constants
-pub(crate) const UNSUPPORTED: Error = internal_error!(0);
-pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1);
-pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2);
-pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3);
-pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4);
-pub(crate) const FAILED_RDRAND: Error = internal_error!(5);
-pub(crate) const NO_RDRAND: Error = internal_error!(6);
-pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
-pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
-pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9);
-pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10);
-pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11);
-
fn internal_desc(error: Error) -> Option<&'static str> {
match error {
- UNSUPPORTED => Some("getrandom: this target is not supported"),
- ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
- UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"),
- SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"),
- RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"),
- FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
- NO_RDRAND => Some("RDRAND: instruction not supported"),
- BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"),
- BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
- STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
- STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
- RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"),
+ Error::UNSUPPORTED => Some("getrandom: this target is not supported"),
+ Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
+ Error::IOS_SEC_RANDOM => Some("SecRandomCopyBytes: iOS Security framework failure"),
+ Error::WINDOWS_RTL_GEN_RANDOM => Some("RtlGenRandom: Windows system function failure"),
+ Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
+ Error::NO_RDRAND => Some("RDRAND: instruction not supported"),
+ Error::WEB_CRYPTO => Some("Web API self.crypto is unavailable"),
+ Error::WEB_GET_RANDOM_VALUES => Some("Web API crypto.getRandomValues is unavailable"),
+ Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"),
+ Error::NODE_CRYPTO => Some("Node.js crypto module is unavailable"),
+ Error::NODE_RANDOM_FILL_SYNC => Some("Node.js API crypto.randomFillSync is unavailable"),
_ => None,
}
}
diff --git a/src/error_impls.rs b/src/error_impls.rs
index 007472e..61f46d2 100644
--- a/src/error_impls.rs
+++ b/src/error_impls.rs
@@ -5,24 +5,13 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![cfg_attr(docsrs, doc(cfg(feature = "std")))]
extern crate std;
-use crate::{error::UNKNOWN_IO_ERROR, Error};
+use crate::Error;
use core::convert::From;
-use core::num::NonZeroU32;
use std::io;
-impl From<io::Error> for Error {
- fn from(err: io::Error) -> Self {
- if let Some(errno) = err.raw_os_error() {
- if let Some(code) = NonZeroU32::new(errno as u32) {
- return Error::from(code);
- }
- }
- UNKNOWN_IO_ERROR
- }
-}
-
impl From<Error> for io::Error {
fn from(err: Error) -> Self {
match err.raw_os_error() {
diff --git a/src/ios.rs b/src/ios.rs
index 30c008c..5e38474 100644
--- a/src/ios.rs
+++ b/src/ios.rs
@@ -7,24 +7,19 @@
// except according to those terms.
//! Implementation for iOS
-use crate::{error::SEC_RANDOM_FAILED, Error};
-
-// TODO: Make extern once extern_types feature is stabilized. See:
-// https://github.com/rust-lang/rust/issues/43467
-#[repr(C)]
-struct SecRandom([u8; 0]);
+use crate::Error;
+use core::{ffi::c_void, ptr::null};
#[link(name = "Security", kind = "framework")]
extern "C" {
- static kSecRandomDefault: *const SecRandom;
-
- fn SecRandomCopyBytes(rnd: *const SecRandom, count: usize, bytes: *mut u8) -> i32;
+ fn SecRandomCopyBytes(rnd: *const c_void, count: usize, bytes: *mut u8) -> i32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
- let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
+ // Apple's documentation guarantees kSecRandomDefault is a synonym for NULL.
+ let ret = unsafe { SecRandomCopyBytes(null(), dest.len(), dest.as_mut_ptr()) };
if ret == -1 {
- Err(SEC_RANDOM_FAILED)
+ Err(Error::IOS_SEC_RANDOM)
} else {
Ok(())
}
diff --git a/src/js.rs b/src/js.rs
new file mode 100644
index 0000000..d48c7d3
--- /dev/null
+++ b/src/js.rs
@@ -0,0 +1,106 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+use crate::Error;
+
+extern crate std;
+use std::thread_local;
+
+use js_sys::Uint8Array;
+use wasm_bindgen::prelude::*;
+
+// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
+const BROWSER_CRYPTO_BUFFER_SIZE: usize = 256;
+
+enum RngSource {
+ Node(NodeCrypto),
+ Browser(BrowserCrypto, Uint8Array),
+}
+
+// JsValues are always per-thread, so we initialize RngSource for each thread.
+// See: https://github.com/rustwasm/wasm-bindgen/pull/955
+thread_local!(
+ static RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
+);
+
+pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
+ RNG_SOURCE.with(|result| {
+ let source = result.as_ref().map_err(|&e| e)?;
+
+ match source {
+ RngSource::Node(n) => {
+ if n.random_fill_sync(dest).is_err() {
+ return Err(Error::NODE_RANDOM_FILL_SYNC);
+ }
+ }
+ RngSource::Browser(crypto, buf) => {
+ // getRandomValues does not work with all types of WASM memory,
+ // so we initially write to browser memory to avoid exceptions.
+ for chunk in dest.chunks_mut(BROWSER_CRYPTO_BUFFER_SIZE) {
+ // The chunk can be smaller than buf's length, so we call to
+ // JS to create a smaller view of buf without allocation.
+ let sub_buf = buf.subarray(0, chunk.len() as u32);
+
+ if crypto.get_random_values(&sub_buf).is_err() {
+ return Err(Error::WEB_GET_RANDOM_VALUES);
+ }
+ sub_buf.copy_to(chunk);
+ }
+ }
+ };
+ Ok(())
+ })
+}
+
+fn getrandom_init() -> Result<RngSource, Error> {
+ if let Ok(self_) = Global::get_self() {
+ // If `self` is defined then we're in a browser somehow (main window
+ // or web worker). We get `self.crypto` (called `msCrypto` on IE), so we
+ // can call `crypto.getRandomValues`. If `crypto` isn't defined, we
+ // assume we're in an older web browser and the OS RNG isn't available.
+
+ let crypto: BrowserCrypto = match (self_.crypto(), self_.ms_crypto()) {
+ (crypto, _) if !crypto.is_undefined() => crypto,
+ (_, crypto) if !crypto.is_undefined() => crypto,
+ _ => return Err(Error::WEB_CRYPTO),
+ };
+
+ let buf = Uint8Array::new_with_length(BROWSER_CRYPTO_BUFFER_SIZE as u32);
+ return Ok(RngSource::Browser(crypto, buf));
+ }
+
+ let crypto = MODULE.require("crypto").map_err(|_| Error::NODE_CRYPTO)?;
+ Ok(RngSource::Node(crypto))
+}
+
+#[wasm_bindgen]
+extern "C" {
+ type Global;
+ #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
+ fn get_self() -> Result<Self_, JsValue>;
+
+ type Self_;
+ #[wasm_bindgen(method, getter, js_name = "msCrypto")]
+ fn ms_crypto(me: &Self_) -> BrowserCrypto;
+ #[wasm_bindgen(method, getter)]
+ fn crypto(me: &Self_) -> BrowserCrypto;
+
+ type BrowserCrypto;
+ #[wasm_bindgen(method, js_name = getRandomValues, catch)]
+ fn get_random_values(me: &BrowserCrypto, buf: &Uint8Array) -> Result<(), JsValue>;
+
+ #[wasm_bindgen(js_name = module)]
+ static MODULE: NodeModule;
+
+ type NodeModule;
+ #[wasm_bindgen(method, catch)]
+ fn require(this: &NodeModule, s: &str) -> Result<NodeCrypto, JsValue>;
+
+ type NodeCrypto;
+ #[wasm_bindgen(method, js_name = randomFillSync, catch)]
+ fn random_fill_sync(crypto: &NodeCrypto, buf: &mut [u8]) -> Result<(), JsValue>;
+}
diff --git a/src/lib.rs b/src/lib.rs
index c305406..b1a5b10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,89 +6,111 @@
// 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.
+//!
+//! # Supported targets
+//!
+//! | Target | Target Triple | Implementation
+//! | ----------------- | ------------------ | --------------
+//! | Linux, Android | `*‑linux‑*` | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random` |
+//! | Windows | `*‑windows‑*` | [`BCryptGenRandom`][3] |
+//! | macOS | `*‑apple‑darwin` | [`getentropy()`][19] if available, otherwise [`/dev/random`][20] (identical to `/dev/urandom`)
+//! | iOS | `*‑apple‑ios` | [`SecRandomCopyBytes`][4]
+//! | FreeBSD | `*‑freebsd` | [`getrandom()`][21] if available, otherwise [`kern.arandom`][5]
+//! | OpenBSD | `*‑openbsd` | [`getentropy`][6]
+//! | NetBSD | `*‑netbsd` | [`kern.arandom`][7]
+//! | Dragonfly BSD | `*‑dragonfly` | [`/dev/random`][8]
+//! | Solaris, illumos | `*‑solaris`, `*‑illumos` | [`getrandom()`][9] if available, otherwise [`/dev/random`][10]
+//! | Fuchsia OS | `*‑fuchsia` | [`cprng_draw`][11]
+//! | Redox | `*‑redox` | [`rand:`][12]
+//! | Haiku | `*‑haiku` | `/dev/random` (identical to `/dev/urandom`)
+//! | SGX | `x86_64‑*‑sgx` | [RDRAND][18]
+//! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure`
+//! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`)
+//! | WASI | `wasm32‑wasi` | [`__wasi_random_get`][17]
+//! | Web Browser | `wasm32‑*‑unknown` | [`Crypto.getRandomValues()`][14], see [WebAssembly support][16]
+//! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomBytes`][15], see [WebAssembly support][16]
+//!
+//! 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.
//!
-//! # Platform sources
+//! ## Unsupported targets
//!
-//! | OS | interface
-//! |------------------|---------------------------------------------------------
-//! | Linux, Android | [`getrandom`][1] system call if available, otherwise [`/dev/urandom`][2] after successfully polling `/dev/random`
-//! | Windows | [`RtlGenRandom`][3]
-//! | 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]
-//! | OpenBSD | [`getentropy`][6]
-//! | NetBSD | [`kern.arandom`][7]
-//! | Dragonfly BSD | [`/dev/random`][8]
-//! | Solaris, illumos | [`getrandom`][9] system call if available, otherwise [`/dev/random`][10]
-//! | Fuchsia OS | [`cprng_draw`][11]
-//! | Redox | [`rand:`][12]
-//! | CloudABI | [`cloudabi_sys_random_get`][13]
-//! | Haiku | `/dev/random` (identical to `/dev/urandom`)
-//! | L4RE, SGX, UEFI | [RDRAND][18]
-//! | Hermit | [RDRAND][18] as [`sys_rand`][22] is currently broken.
-//! | 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])
-//! | WASI | [`__wasi_random_get`][17]
+//! 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.
//!
-//! 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.
+//! 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).
//!
-//! ## Unsupported targets
+//! ### 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
+//!
+//! 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).
//!
-//! 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.
-//! - Enable the `dummy` feature to have getrandom use an implementation that always
-//! fails at run-time on unsupported targets.
+//! 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) using the
+//! [wasm-bindgen](https://github.com/rust-lang/rust-bindgen) toolchain.
//!
-//! [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 feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
-//! ## Support for WebAssembly and asm.js
+//! ### Custom implementations
//!
-//! 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.
+//! 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.
//!
-//! 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.
+//! 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.
//!
-//! [bindgen]: https://github.com/rust-lang/rust-bindgen
-//! [stdweb]: https://github.com/koute/stdweb
+//! ### 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.
@@ -96,12 +118,9 @@
//! `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
+//! [3]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! [4]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [5]: https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
//! [6]: https://man.openbsd.org/getentropy.2
@@ -111,153 +130,88 @@
//! [10]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html
//! [11]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [12]: https://github.com/redox-os/randd/blob/master/src/main.rs
-//! [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://github.com/hermitcore/libhermit-rs/blob/09c38b0371cee6f56a541400ba453e319e43db53/src/syscalls/random.rs#L21
#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
- html_root_url = "https://rust-random.github.io/rand/"
+ html_root_url = "https://docs.rs/getrandom/0.2.2"
)]
#![no_std]
-#![cfg_attr(feature = "stdweb", recursion_limit = "128")]
#![warn(rust_2018_idioms, unused_lifetimes, missing_docs)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
#[macro_use]
extern crate cfg_if;
-cfg_if! {
- if #[cfg(feature = "log")] {
- #[allow(unused)]
- #[macro_use]
- extern crate log;
- } else {
- #[allow(unused)]
- macro_rules! error {
- ($($x:tt)*) => {};
- }
- #[allow(unused)]
- macro_rules! warn {
- ($($x:tt)*) => {};
- }
- #[allow(unused)]
- macro_rules! info {
- ($($x:tt)*) => {};
- }
- }
-}
-
mod error;
-pub use crate::error::Error;
-
-#[allow(dead_code)]
mod util;
+// To prevent a breaking change when targets are added, we always export the
+// register_custom_getrandom macro, so old Custom RNG crates continue to build.
+#[cfg(feature = "custom")]
+mod custom;
+#[cfg(feature = "std")]
+mod error_impls;
-#[cfg(target_os = "vxworks")]
-#[allow(dead_code)]
-mod util_libc;
-
-cfg_if! {
- // Unlike the other Unix, Fuchsia and iOS don't use the libc to make any calls.
- if #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten",
- target_os = "freebsd", target_os = "haiku", target_os = "illumos",
- target_os = "linux", target_os = "macos", target_os = "netbsd",
- target_os = "openbsd", target_os = "redox", target_os = "solaris"))] {
- #[allow(dead_code)]
- mod util_libc;
- // Keep std-only trait definitions for backwards compatibility
- mod error_impls;
- } else if #[cfg(feature = "std")] {
- mod error_impls;
- }
-}
-
-// These targets read from a file as a fallback method.
-#[cfg(any(
- target_os = "android",
- target_os = "linux",
- target_os = "macos",
- target_os = "solaris",
- target_os = "illumos",
-))]
-mod use_file;
+pub use crate::error::Error;
// System-specific implementations.
//
// These should all provide getrandom_inner with the same signature as getrandom.
cfg_if! {
- if #[cfg(target_os = "android")] {
- #[path = "linux_android.rs"] mod imp;
- } else if #[cfg(target_os = "cloudabi")] {
- #[path = "cloudabi.rs"] mod imp;
- } else if #[cfg(target_os = "dragonfly")] {
- #[path = "use_file.rs"] mod imp;
- } else if #[cfg(target_os = "emscripten")] {
+ if #[cfg(any(target_os = "dragonfly", target_os = "emscripten",
+ target_os = "haiku", target_os = "redox"))] {
+ mod util_libc;
#[path = "use_file.rs"] mod imp;
- } else if #[cfg(target_os = "freebsd")] {
+ } else if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ mod util_libc;
+ mod use_file;
+ #[path = "linux_android.rs"] mod imp;
+ } else if #[cfg(any(target_os = "illumos", target_os = "solaris"))] {
+ mod util_libc;
+ mod use_file;
+ #[path = "solaris_illumos.rs"] mod imp;
+ } else if #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] {
+ mod util_libc;
#[path = "bsd_arandom.rs"] mod imp;
} else if #[cfg(target_os = "fuchsia")] {
#[path = "fuchsia.rs"] mod imp;
- } else if #[cfg(target_os = "haiku")] {
- #[path = "use_file.rs"] mod imp;
- } else if #[cfg(target_os = "illumos")] {
- #[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "ios")] {
#[path = "ios.rs"] mod imp;
- } else if #[cfg(target_os = "linux")] {
- #[path = "linux_android.rs"] mod imp;
} else if #[cfg(target_os = "macos")] {
+ mod util_libc;
+ mod use_file;
#[path = "macos.rs"] mod imp;
- } else if #[cfg(target_os = "netbsd")] {
- #[path = "bsd_arandom.rs"] mod imp;
} else if #[cfg(target_os = "openbsd")] {
+ mod util_libc;
#[path = "openbsd.rs"] mod imp;
- } else if #[cfg(target_os = "redox")] {
- #[path = "use_file.rs"] mod imp;
- } else if #[cfg(target_os = "solaris")] {
- #[path = "solaris_illumos.rs"] mod imp;
} else if #[cfg(target_os = "wasi")] {
#[path = "wasi.rs"] mod imp;
} else if #[cfg(target_os = "vxworks")] {
+ mod util_libc;
#[path = "vxworks.rs"] mod imp;
- } else if #[cfg(all(windows, getrandom_uwp))] {
- #[path = "windows_uwp.rs"] mod imp;
} else if #[cfg(windows)] {
#[path = "windows.rs"] mod imp;
- } else if #[cfg(all(target_arch = "x86_64", any(
- target_os = "hermit",
- target_os = "l4re",
- target_os = "uefi",
- target_env = "sgx",
- )))] {
+ } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] {
+ #[path = "rdrand.rs"] mod imp;
+ } else if #[cfg(all(feature = "rdrand",
+ any(target_arch = "x86_64", target_arch = "x86")))] {
#[path = "rdrand.rs"] mod imp;
- } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
- cfg_if! {
- if #[cfg(feature = "wasm-bindgen")] {
- #[path = "wasm32_bindgen.rs"] mod imp;
- } else if #[cfg(feature = "stdweb")] {
- #[path = "wasm32_stdweb.rs"] mod imp;
- } else {
- // Always have an implementation for wasm32-unknown-unknown.
- // See https://github.com/rust-random/getrandom/issues/87
- #[path = "dummy.rs"] mod imp;
- }
- }
- } else if #[cfg(feature = "dummy")] {
- #[path = "dummy.rs"] mod imp;
+ } else if #[cfg(all(feature = "js",
+ target_arch = "wasm32", target_os = "unknown"))] {
+ #[path = "js.rs"] mod imp;
+ } 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");
}
}
@@ -274,7 +228,7 @@ cfg_if! {
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
-pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
+pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
if dest.is_empty() {
return Ok(());
}
diff --git a/src/linux_android.rs b/src/linux_android.rs
index a29feb5..5508fdd 100644
--- a/src/linux_android.rs
+++ b/src/linux_android.rs
@@ -7,9 +7,11 @@
// except according to those terms.
//! Implementation for Linux / Android
-use crate::util::LazyBool;
-use crate::util_libc::{last_os_error, sys_fill_exact};
-use crate::{use_file, Error};
+use crate::{
+ util::LazyBool,
+ util_libc::{last_os_error, sys_fill_exact},
+ {use_file, Error},
+};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static HAS_GETRANDOM: LazyBool = LazyBool::new();
diff --git a/src/macos.rs b/src/macos.rs
index c3bc533..585a35a 100644
--- a/src/macos.rs
+++ b/src/macos.rs
@@ -7,8 +7,11 @@
// except according to those terms.
//! Implementation for macOS
-use crate::util_libc::{last_os_error, Weak};
-use crate::{use_file, Error};
+use crate::{
+ use_file,
+ util_libc::{last_os_error, Weak},
+ Error,
+};
use core::mem;
type GetEntropyFn = unsafe extern "C" fn(*mut u8, libc::size_t) -> libc::c_int;
@@ -20,9 +23,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { func(chunk.as_mut_ptr(), chunk.len()) };
if ret != 0 {
- let err = last_os_error();
- error!("getentropy syscall failed");
- return Err(err);
+ return Err(last_os_error());
}
}
Ok(())
diff --git a/src/openbsd.rs b/src/openbsd.rs
index e1ac179..c8d28b3 100644
--- a/src/openbsd.rs
+++ b/src/openbsd.rs
@@ -7,16 +7,13 @@
// except according to those terms.
//! Implementation for OpenBSD
-use crate::util_libc::last_os_error;
-use crate::Error;
+use crate::{util_libc::last_os_error, Error};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
for chunk in dest.chunks_mut(256) {
let ret = unsafe { libc::getentropy(chunk.as_mut_ptr() as *mut libc::c_void, chunk.len()) };
if ret == -1 {
- let err = last_os_error();
- error!("libc::getentropy call failed");
- return Err(err);
+ return Err(last_os_error());
}
}
Ok(())
diff --git a/src/rdrand.rs b/src/rdrand.rs
index e441682..1df21e5 100644
--- a/src/rdrand.rs
+++ b/src/rdrand.rs
@@ -7,24 +7,30 @@
// except according to those terms.
//! Implementation for SGX using RDRAND instruction
-use crate::error::{FAILED_RDRAND, NO_RDRAND};
-#[cfg(not(target_feature = "rdrand"))]
-use crate::util::LazyBool;
use crate::Error;
-use core::arch::x86_64::_rdrand64_step;
use core::mem;
+cfg_if! {
+ if #[cfg(target_arch = "x86_64")] {
+ use core::arch::x86_64 as arch;
+ use arch::_rdrand64_step as rdrand_step;
+ } else if #[cfg(target_arch = "x86")] {
+ use core::arch::x86 as arch;
+ use arch::_rdrand32_step as rdrand_step;
+ }
+}
+
// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
-const WORD_SIZE: usize = mem::size_of::<u64>();
+const WORD_SIZE: usize = mem::size_of::<usize>();
#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
for _ in 0..RETRY_LIMIT {
let mut el = mem::zeroed();
- if _rdrand64_step(&mut el) == 1 {
+ if rdrand_step(&mut el) == 1 {
// AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
// set CF on bogus random data, so we check these values explicitly.
// See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
@@ -33,11 +39,10 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
if el != 0 && el != !0 {
return Ok(el.to_ne_bytes());
}
- error!("RDRAND returned {:X}, CPU RNG may be broken", el);
// Keep looping in case this was a false positive.
}
}
- Err(FAILED_RDRAND)
+ Err(Error::FAILED_RDRAND)
}
// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
@@ -55,16 +60,18 @@ fn is_rdrand_supported() -> bool {
// https://github.com/rust-lang-nursery/stdsimd/issues/464
#[cfg(not(target_feature = "rdrand"))]
fn is_rdrand_supported() -> bool {
- use core::arch::x86_64::__cpuid;
- // SAFETY: All x86_64 CPUs support CPUID leaf 1
+ use crate::util::LazyBool;
+
+ // SAFETY: All Rust x86 targets are new enough to have CPUID, and if CPUID
+ // is supported, CPUID leaf 1 is always supported.
const FLAG: u32 = 1 << 30;
static HAS_RDRAND: LazyBool = LazyBool::new();
- HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 })
+ HAS_RDRAND.unsync_init(|| unsafe { (arch::__cpuid(1).ecx & FLAG) != 0 })
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
if !is_rdrand_supported() {
- return Err(NO_RDRAND);
+ return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, rdrand is supported, so calling the rdrand
diff --git a/src/solaris_illumos.rs b/src/solaris_illumos.rs
index 9473123..2d1b767 100644
--- a/src/solaris_illumos.rs
+++ b/src/solaris_illumos.rs
@@ -17,8 +17,11 @@
//! To make sure we can compile on both Solaris and its derivatives, as well as
//! function, we check for the existence of getrandom(2) in libc by calling
//! libc::dlsym.
-use crate::util_libc::{sys_fill_exact, Weak};
-use crate::{use_file, Error};
+use crate::{
+ use_file,
+ util_libc::{sys_fill_exact, Weak},
+ Error,
+};
use core::mem;
#[cfg(target_os = "illumos")]
diff --git a/src/use_file.rs b/src/use_file.rs
index 6e50955..465c069 100644
--- a/src/use_file.rs
+++ b/src/use_file.rs
@@ -7,11 +7,15 @@
// except according to those terms.
//! Implementations that just need to read from a file
-use crate::util::LazyUsize;
-use crate::util_libc::{open_readonly, sys_fill_exact};
-use crate::Error;
-use core::cell::UnsafeCell;
-use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
+use crate::{
+ util::LazyUsize,
+ util_libc::{open_readonly, sys_fill_exact},
+ Error,
+};
+use core::{
+ cell::UnsafeCell,
+ sync::atomic::{AtomicUsize, Ordering::Relaxed},
+};
#[cfg(target_os = "redox")]
const FILE_PATH: &str = "rand:\0";
@@ -99,7 +103,7 @@ fn wait_until_rng_ready() -> Result<(), Error> {
// A negative timeout means an infinite timeout.
let res = unsafe { libc::poll(&mut pfd, 1, -1) };
if res >= 0 {
- assert_eq!(res, 1); // We only used one fd, and cannot timeout.
+ debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
return Ok(());
}
let err = crate::util_libc::last_os_error();
diff --git a/src/util.rs b/src/util.rs
index 8dbd8ae..06e23c2 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -5,7 +5,7 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![allow(dead_code)]
use core::sync::atomic::{AtomicUsize, Ordering::Relaxed};
// This structure represents a lazily initialized static usize value. Useful
diff --git a/src/util_libc.rs b/src/util_libc.rs
index 1cdc13e..6823609 100644
--- a/src/util_libc.rs
+++ b/src/util_libc.rs
@@ -5,11 +5,9 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use crate::error::ERRNO_NOT_POSITIVE;
-use crate::util::LazyUsize;
-use crate::Error;
-use core::num::NonZeroU32;
-use core::ptr::NonNull;
+#![allow(dead_code)]
+use crate::{util::LazyUsize, Error};
+use core::{num::NonZeroU32, ptr::NonNull};
cfg_if! {
if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] {
@@ -42,7 +40,7 @@ pub fn last_os_error() -> Error {
if errno > 0 {
Error::from(NonZeroU32::new(errno as u32).unwrap())
} else {
- ERRNO_NOT_POSITIVE
+ Error::ERRNO_NOT_POSITIVE
}
}
@@ -108,14 +106,10 @@ cfg_if! {
// SAFETY: path must be null terminated, FD must be manually closed.
pub unsafe fn open_readonly(path: &str) -> Result<libc::c_int, Error> {
- debug_assert!(path.as_bytes().last() == Some(&0));
+ debug_assert_eq!(path.as_bytes().last(), Some(&0));
let fd = open(path.as_ptr() as *const _, libc::O_RDONLY | libc::O_CLOEXEC);
if fd < 0 {
return Err(last_os_error());
}
- // O_CLOEXEC works on all Unix targets except for older Linux kernels (pre
- // 2.6.23), so we also use an ioctl to make sure FD_CLOEXEC is set.
- #[cfg(target_os = "linux")]
- libc::ioctl(fd, libc::FIOCLEX);
Ok(fd)
}
diff --git a/src/vxworks.rs b/src/vxworks.rs
index a2fe52a..6cb5d52 100644
--- a/src/vxworks.rs
+++ b/src/vxworks.rs
@@ -7,8 +7,7 @@
// except according to those terms.
//! Implementation for VxWorks
-use crate::error::{Error, RAND_SECURE_FATAL};
-use crate::util_libc::last_os_error;
+use crate::{util_libc::last_os_error, Error};
use core::sync::atomic::{AtomicBool, Ordering::Relaxed};
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
@@ -16,7 +15,7 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
while !RNG_INIT.load(Relaxed) {
let ret = unsafe { libc::randSecure() };
if ret < 0 {
- return Err(RAND_SECURE_FATAL);
+ return Err(Error::VXWORKS_RAND_SECURE);
} else if ret > 0 {
RNG_INIT.store(true, Relaxed);
break;
diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs
deleted file mode 100644
index 86839a0..0000000
--- a/src/wasm32_bindgen.rs
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation for WASM via wasm-bindgen
-extern crate std;
-
-use core::cell::RefCell;
-use core::mem;
-use std::thread_local;
-
-use wasm_bindgen::prelude::*;
-
-use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
-use crate::Error;
-
-#[derive(Clone, Debug)]
-enum RngSource {
- Node(NodeCrypto),
- Browser(BrowserCrypto),
-}
-
-// JsValues are always per-thread, so we initialize RngSource for each thread.
-// See: https://github.com/rustwasm/wasm-bindgen/pull/955
-thread_local!(
- static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
-);
-
-pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
- assert_eq!(mem::size_of::<usize>(), 4);
-
- RNG_SOURCE.with(|f| {
- let mut source = f.borrow_mut();
- if source.is_none() {
- *source = Some(getrandom_init()?);
- }
-
- match source.as_ref().unwrap() {
- RngSource::Node(n) => n.random_fill_sync(dest),
- RngSource::Browser(n) => {
- // see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
- //
- // where it says:
- //
- // > A QuotaExceededError DOMException is thrown if the
- // > requested length is greater than 65536 bytes.
- for chunk in dest.chunks_mut(65536) {
- n.get_random_values(chunk)
- }
- }
- };
- Ok(())
- })
-}
-
-fn getrandom_init() -> Result<RngSource, Error> {
- if let Ok(self_) = Global::get_self() {
- // If `self` is defined then we're in a browser somehow (main window
- // or web worker). Here we want to try to use
- // `crypto.getRandomValues`, but if `crypto` isn't defined we assume
- // we're in an older web browser and the OS RNG isn't available.
-
- let crypto = self_.crypto();
- if crypto.is_undefined() {
- return Err(BINDGEN_CRYPTO_UNDEF);
- }
-
- // Test if `crypto.getRandomValues` is undefined as well
- let crypto: BrowserCrypto = crypto.into();
- if crypto.get_random_values_fn().is_undefined() {
- return Err(BINDGEN_GRV_UNDEF);
- }
-
- return Ok(RngSource::Browser(crypto));
- }
-
- return Ok(RngSource::Node(node_require("crypto")));
-}
-
-#[wasm_bindgen]
-extern "C" {
- type Global;
- #[wasm_bindgen(getter, catch, static_method_of = Global, js_class = self, js_name = self)]
- fn get_self() -> Result<Self_, JsValue>;
-
- type Self_;
- #[wasm_bindgen(method, getter, structural)]
- fn crypto(me: &Self_) -> JsValue;
-
- #[derive(Clone, Debug)]
- type BrowserCrypto;
-
- // TODO: these `structural` annotations here ideally wouldn't be here to
- // avoid a JS shim, but for now with feature detection they're
- // unavoidable.
- #[wasm_bindgen(method, js_name = getRandomValues, structural, getter)]
- fn get_random_values_fn(me: &BrowserCrypto) -> JsValue;
- #[wasm_bindgen(method, js_name = getRandomValues, structural)]
- fn get_random_values(me: &BrowserCrypto, buf: &mut [u8]);
-
- #[wasm_bindgen(js_name = require)]
- fn node_require(s: &str) -> NodeCrypto;
-
- #[derive(Clone, Debug)]
- type NodeCrypto;
-
- #[wasm_bindgen(method, js_name = randomFillSync, structural)]
- fn random_fill_sync(me: &NodeCrypto, buf: &mut [u8]);
-}
diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs
deleted file mode 100644
index 6e5e78a..0000000
--- a/src/wasm32_stdweb.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation for WASM via stdweb
-extern crate std;
-
-use core::mem;
-
-use stdweb::js;
-use stdweb::unstable::TryInto;
-use stdweb::web::error::Error as WebError;
-
-use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED};
-use crate::Error;
-use std::sync::Once;
-
-#[derive(Clone, Copy, Debug)]
-enum RngSource {
- Browser,
- Node,
-}
-
-pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
- assert_eq!(mem::size_of::<usize>(), 4);
- static ONCE: Once = Once::new();
- static mut RNG_SOURCE: Result<RngSource, Error> = Ok(RngSource::Node);
-
- // SAFETY: RNG_SOURCE is only written once, before being read.
- ONCE.call_once(|| unsafe {
- RNG_SOURCE = getrandom_init();
- });
- getrandom_fill(unsafe { RNG_SOURCE }?, dest)
-}
-
-fn getrandom_init() -> Result<RngSource, Error> {
- let result = js! {
- try {
- if (
- typeof self === "object" &&
- typeof self.crypto === "object" &&
- typeof self.crypto.getRandomValues === "function"
- ) {
- return { success: true, ty: 1 };
- }
-
- if (typeof require("crypto").randomBytes === "function") {
- return { success: true, ty: 2 };
- }
-
- return { success: false, error: new Error("not supported") };
- } catch(err) {
- return { success: false, error: err };
- }
- };
-
- if js! { return @{ result.as_ref() }.success } == true {
- let ty = js! { return @{ result }.ty };
-
- if ty == 1 {
- Ok(RngSource::Browser)
- } else if ty == 2 {
- Ok(RngSource::Node)
- } else {
- unreachable!()
- }
- } else {
- let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
- error!("getrandom unavailable: {}", _err);
- Err(STDWEB_NO_RNG)
- }
-}
-
-fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> {
- for chunk in dest.chunks_mut(65536) {
- let len = chunk.len() as u32;
- let ptr = chunk.as_mut_ptr() as i32;
-
- let result = match source {
- RngSource::Browser => js! {
- try {
- let array = new Uint8Array(@{ len });
- self.crypto.getRandomValues(array);
- HEAPU8.set(array, @{ ptr });
-
- return { success: true };
- } catch(err) {
- return { success: false, error: err };
- }
- },
- RngSource::Node => js! {
- try {
- let bytes = require("crypto").randomBytes(@{ len });
- HEAPU8.set(new Uint8Array(bytes), @{ ptr });
-
- return { success: true };
- } catch(err) {
- return { success: false, error: err };
- }
- },
- };
-
- if js! { return @{ result.as_ref() }.success } != true {
- let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
- error!("getrandom failed: {}", _err);
- return Err(STDWEB_RNG_FAILED);
- }
- }
- Ok(())
-}
diff --git a/src/windows.rs b/src/windows.rs
index e1b8df6..56b3d07 100644
--- a/src/windows.rs
+++ b/src/windows.rs
@@ -6,20 +6,41 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Implementation for Windows
-use crate::{error::RTL_GEN_RANDOM_FAILED, Error};
+use crate::Error;
+use core::{ffi::c_void, num::NonZeroU32, ptr};
+
+const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
extern "system" {
- #[link_name = "SystemFunction036"]
- fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
+ fn BCryptGenRandom(
+ hAlgorithm: *mut c_void,
+ pBuffer: *mut u8,
+ cbBuffer: u32,
+ dwFlags: u32,
+ ) -> u32;
}
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
// Prevent overflow of u32
for chunk in dest.chunks_mut(u32::max_value() as usize) {
- let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr(), chunk.len() as u32) };
- if ret == 0 {
- return Err(RTL_GEN_RANDOM_FAILED);
+ let ret = unsafe {
+ BCryptGenRandom(
+ ptr::null_mut(),
+ chunk.as_mut_ptr(),
+ chunk.len() as u32,
+ BCRYPT_USE_SYSTEM_PREFERRED_RNG,
+ )
+ };
+ // NTSTATUS codes use the two highest bits for severity status.
+ if ret >> 30 == 0b11 {
+ // We zeroize the highest bit, so the error code will reside
+ // inside the range designated for OS codes.
+ let code = ret ^ (1 << 31);
+ // SAFETY: the second highest bit is always equal to one,
+ // so it's impossible to get zero. Unfortunately the type
+ // system does not have a way to express this yet.
+ let code = unsafe { NonZeroU32::new_unchecked(code) };
+ return Err(Error::from(code));
}
}
Ok(())
diff --git a/src/windows_uwp.rs b/src/windows_uwp.rs
deleted file mode 100644
index 586c6f6..0000000
--- a/src/windows_uwp.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation for Windows UWP targets. After deprecation of Windows XP
-//! and Vista, this can supersede the `RtlGenRandom`-based implementation.
-use crate::Error;
-use core::{ffi::c_void, num::NonZeroU32, ptr};
-
-const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
-
-extern "system" {
- fn BCryptGenRandom(
- hAlgorithm: *mut c_void,
- pBuffer: *mut u8,
- cbBuffer: u32,
- dwFlags: u32,
- ) -> u32;
-}
-
-pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
- // Prevent overflow of u32
- for chunk in dest.chunks_mut(u32::max_value() as usize) {
- let ret = unsafe {
- BCryptGenRandom(
- ptr::null_mut(),
- chunk.as_mut_ptr(),
- chunk.len() as u32,
- BCRYPT_USE_SYSTEM_PREFERRED_RNG,
- )
- };
- // NTSTATUS codes use two highest bits for severity status
- match ret >> 30 {
- 0b01 => {
- info!("BCryptGenRandom: information code 0x{:08X}", ret);
- }
- 0b10 => {
- warn!("BCryptGenRandom: warning code 0x{:08X}", ret);
- }
- 0b11 => {
- error!("BCryptGenRandom: failed with 0x{:08X}", ret);
- // We zeroize the highest bit, so the error code will reside
- // inside the range of designated for OS codes.
- let code = ret ^ (1 << 31);
- // SAFETY: the second highest bit is always equal to one,
- // so it's impossible to get zero. Unfortunately compiler
- // is not smart enough to figure out it yet.
- let code = unsafe { NonZeroU32::new_unchecked(code) };
- return Err(Error::from(code));
- }
- _ => (),
- }
- }
- Ok(())
-}
diff --git a/tests/common.rs b/tests/common/mod.rs
index afefa03..006f230 100644
--- a/tests/common.rs
+++ b/tests/common/mod.rs
@@ -1,26 +1,24 @@
-#[cfg(feature = "wasm-bindgen")]
-use wasm_bindgen_test::*;
+use super::getrandom_impl;
-use getrandom::getrandom;
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+use wasm_bindgen_test::wasm_bindgen_test as test;
#[cfg(feature = "test-in-browser")]
-wasm_bindgen_test_configure!(run_in_browser);
+wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
-#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_zero() {
// Test that APIs are happy with zero-length requests
- getrandom(&mut [0u8; 0]).unwrap();
+ getrandom_impl(&mut [0u8; 0]).unwrap();
}
-#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_diff() {
let mut v1 = [0u8; 1000];
- getrandom(&mut v1).unwrap();
+ getrandom_impl(&mut v1).unwrap();
let mut v2 = [0u8; 1000];
- getrandom(&mut v2).unwrap();
+ getrandom_impl(&mut v2).unwrap();
let mut n_diff_bits = 0;
for i in 0..v1.len() {
@@ -31,18 +29,18 @@ fn test_diff() {
assert!(n_diff_bits >= v1.len() as u32);
}
-#[cfg_attr(feature = "wasm-bindgen", wasm_bindgen_test)]
#[test]
fn test_huge() {
let mut huge = [0u8; 100_000];
- getrandom(&mut huge).unwrap();
+ getrandom_impl(&mut huge).unwrap();
}
-#[cfg(any(unix, windows, target_os = "redox", target_os = "fuchsia"))]
+// On WASM, the thread API always fails/panics
+#[cfg(not(target_arch = "wasm32"))]
#[test]
fn test_multithreading() {
- use std::sync::mpsc::channel;
- use std::thread;
+ extern crate std;
+ use std::{sync::mpsc::channel, thread, vec};
let mut txs = vec![];
for _ in 0..20 {
@@ -55,7 +53,7 @@ fn test_multithreading() {
let mut v = [0u8; 1000];
for _ in 0..100 {
- getrandom(&mut v).unwrap();
+ getrandom_impl(&mut v).unwrap();
thread::yield_now();
}
});
diff --git a/tests/custom.rs b/tests/custom.rs
new file mode 100644
index 0000000..62eae1d
--- /dev/null
+++ b/tests/custom.rs
@@ -0,0 +1,50 @@
+// Test that a custom handler works on wasm32-unknown-unknown
+#![cfg(all(
+ target_arch = "wasm32",
+ target_os = "unknown",
+ feature = "custom",
+ not(feature = "js")
+))]
+
+use wasm_bindgen_test::wasm_bindgen_test as test;
+#[cfg(feature = "test-in-browser")]
+wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
+
+use core::{
+ num::NonZeroU32,
+ sync::atomic::{AtomicU8, Ordering},
+};
+use getrandom::{getrandom, register_custom_getrandom, Error};
+
+fn len7_err() -> Error {
+ NonZeroU32::new(Error::INTERNAL_START + 7).unwrap().into()
+}
+
+fn super_insecure_rng(buf: &mut [u8]) -> Result<(), Error> {
+ // Length 7 buffers return a custom error
+ if buf.len() == 7 {
+ return Err(len7_err());
+ }
+ // Otherwise, increment an atomic counter
+ static COUNTER: AtomicU8 = AtomicU8::new(0);
+ for b in buf {
+ *b = COUNTER.fetch_add(1, Ordering::Relaxed);
+ }
+ Ok(())
+}
+
+register_custom_getrandom!(super_insecure_rng);
+
+#[test]
+fn custom_rng_output() {
+ let mut buf = [0u8; 4];
+ assert_eq!(getrandom(&mut buf), Ok(()));
+ assert_eq!(buf, [0, 1, 2, 3]);
+ assert_eq!(getrandom(&mut buf), Ok(()));
+ assert_eq!(buf, [4, 5, 6, 7]);
+}
+
+#[test]
+fn rng_err_output() {
+ assert_eq!(getrandom(&mut [0; 7]), Err(len7_err()));
+}
diff --git a/tests/normal.rs b/tests/normal.rs
new file mode 100644
index 0000000..5fff13b
--- /dev/null
+++ b/tests/normal.rs
@@ -0,0 +1,11 @@
+// Don't test on custom wasm32-unknown-unknown
+#![cfg(not(all(
+ target_arch = "wasm32",
+ target_os = "unknown",
+ feature = "custom",
+ not(feature = "js")
+)))]
+
+// Use the normal getrandom implementation on this architecture.
+use getrandom::getrandom as getrandom_impl;
+mod common;
diff --git a/tests/rdrand.rs b/tests/rdrand.rs
new file mode 100644
index 0000000..4ff85c4
--- /dev/null
+++ b/tests/rdrand.rs
@@ -0,0 +1,15 @@
+// We only test the RDRAND-based RNG source on supported architectures.
+#![cfg(any(target_arch = "x86_64", target_arch = "x86"))]
+
+// rdrand.rs expects to be part of the getrandom main crate, so we need these
+// additional imports to get rdrand.rs to compile.
+use getrandom::Error;
+#[macro_use]
+extern crate cfg_if;
+#[path = "../src/rdrand.rs"]
+mod rdrand;
+#[path = "../src/util.rs"]
+mod util;
+
+use rdrand::getrandom_inner as getrandom_impl;
+mod common;