From 710b24dd270191ebe3d244037e3eb00098de2c54 Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Sun, 23 Oct 2022 15:09:31 -0700 Subject: [PATCH] Use getentropy on Emscripten (#307) Signed-off-by: Joe Richey Signed-off-by: Joe Richey --- src/emscripten.rs | 18 ++++++++++++++++++ src/lib.rs | 9 ++++++--- src/use_file.rs | 17 +++-------------- 3 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 src/emscripten.rs diff --git a/src/emscripten.rs b/src/emscripten.rs new file mode 100644 index 00000000..a50372f5 --- /dev/null +++ b/src/emscripten.rs @@ -0,0 +1,18 @@ +//! Implementation for Emscripten +use crate::{util_libc::last_os_error, Error}; +use core::mem::MaybeUninit; + +// Not yet defined in libc crate. +extern "C" { + fn getentropy(buffer: *mut libc::c_void, length: usize) -> libc::c_int; +} + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + // Emscripten 2.0.5 added getentropy, so we can use it unconditionally. + // Unlike other getentropy implementations, there is no max buffer length. + let ret = unsafe { getentropy(dest.as_mut_ptr() as *mut libc::c_void, dest.len()) }; + if ret < 0 { + return Err(last_os_error()); + } + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 6f9fcd8a..fb81400a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ //! | SGX | `x86_64‑*‑sgx` | [`RDRAND`] //! | VxWorks | `*‑wrs‑vxworks‑*` | `randABytes` after checking entropy pool initialization with `randSecure` //! | ESP-IDF | `*‑espidf` | [`esp_fill_random`] -//! | Emscripten | `*‑emscripten` | `/dev/urandom` (identical to `/dev/random`) +//! | Emscripten | `*‑emscripten` | [`getentropy`][13] //! | WASI | `wasm32‑wasi` | [`random_get`] //! | Web Browser and Node.js | `wasm*‑*‑unknown` | [`Crypto.getRandomValues`] if available, then [`crypto.randomFillSync`] if on Node.js, see [WebAssembly support] //! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes` @@ -159,6 +159,7 @@ //! [10]: https://leaf.dragonflybsd.org/cgi/web-man?command=random§ion=4 //! [11]: https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html //! [12]: https://docs.oracle.com/cd/E86824_01/html/E54777/random-7d.html +//! [13]: https://github.com/emscripten-core/emscripten/pull/12240 //! //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom //! [`Crypto.getRandomValues`]: https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues @@ -208,8 +209,7 @@ pub use crate::error::Error; // The function MUST NOT ever write uninitialized bytes into `dest`, // regardless of what value it returns. cfg_if! { - if #[cfg(any(target_os = "emscripten", target_os = "haiku", - target_os = "redox"))] { + if #[cfg(any(target_os = "haiku", target_os = "redox"))] { mod util_libc; #[path = "use_file.rs"] mod imp; } else if #[cfg(any(target_os = "android", target_os = "linux"))] { @@ -256,6 +256,9 @@ cfg_if! { // uses Horizon OS (it is aarch64). mod util_libc; #[path = "3ds.rs"] mod imp; + } else if #[cfg(target_os = "emscripten")] { + mod util_libc; + #[path = "emscripten.rs"] mod imp; } else if #[cfg(all(target_arch = "x86_64", target_env = "sgx"))] { #[path = "rdrand.rs"] mod imp; } else if #[cfg(all(feature = "rdrand", diff --git a/src/use_file.rs b/src/use_file.rs index 73dc9a47..facd8fad 100644 --- a/src/use_file.rs +++ b/src/use_file.rs @@ -29,7 +29,6 @@ const FILE_PATH: &str = "/dev/random\0"; target_os = "linux", target_os = "redox", target_os = "dragonfly", - target_os = "emscripten", target_os = "haiku", target_os = "macos" ))] @@ -37,19 +36,9 @@ const FILE_PATH: &str = "/dev/urandom\0"; pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { let fd = get_rng_fd()?; - let read = |buf: &mut [MaybeUninit]| unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) - }; - - if cfg!(target_os = "emscripten") { - // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes. - for chunk in dest.chunks_mut(65536) { - sys_fill_exact(chunk, read)?; - } - } else { - sys_fill_exact(dest, read)?; - } - Ok(()) + sys_fill_exact(dest, |buf| unsafe { + libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) + }) } // Returns the file descriptor for the device file used to retrieve random