Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add functions to generate random u32 and u64 values #544

Merged
merged 2 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,20 @@ cfg_if! {
mod apple_other;
pub use apple_other::*;
} else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] {
mod wasi;
pub use wasi::*;
cfg_if! {
if #[cfg(target_env = "p1")] {
mod wasi_p1;
pub use wasi_p1::*;
} else if #[cfg(target_env = "p2")] {
mod wasi_p2;
pub use wasi_p2::*;
} else {
compile_error!(
"Unknown version of WASI (only previews 1 and 2 are supported) \
or Rust version older than 1.80 was used"
);
}
}
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
Expand Down
2 changes: 2 additions & 0 deletions src/backends/apple_other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let dst_ptr = dest.as_mut_ptr().cast::<c_void>();
let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) };
Expand Down
2 changes: 2 additions & 0 deletions src/backends/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
extern "Rust" {
fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>;
Expand Down
2 changes: 2 additions & 0 deletions src/backends/esp_idf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[cfg(not(target_os = "espidf"))]
compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!");

Expand Down
2 changes: 2 additions & 0 deletions src/backends/fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

#[link(name = "zircon")]
extern "C" {
fn zx_cprng_draw(buffer: *mut u8, length: usize);
Expand Down
2 changes: 2 additions & 0 deletions src/backends/getentropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
26 changes: 26 additions & 0 deletions src/backends/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@ use core::mem::MaybeUninit;

extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
// Note that `sys_secure_rand32/64` are implemented using `sys_read_entropy`:
// https://github.com/hermit-os/kernel/blob/430da84/src/syscalls/entropy.rs#L62-L104
// But this may change in future and can depend on compilation target,
// so to future-proof we use these "syscalls".
fn sys_secure_rand32(value: *mut u32) -> i32;
fn sys_secure_rand64(value: *mut u64) -> i32;
}

pub fn inner_u32() -> Result<u32, Error> {
let mut res = MaybeUninit::uninit();
let ret = unsafe { sys_secure_rand32(res.as_mut_ptr()) };
match ret {
0 => Ok(unsafe { res.assume_init() }),
-1 => Err(Error::UNSUPPORTED),
_ => Err(Error::UNEXPECTED),
}
}

pub fn inner_u64() -> Result<u64, Error> {
let mut res = MaybeUninit::uninit();
let ret = unsafe { sys_secure_rand64(res.as_mut_ptr()) };
match ret {
0 => Ok(unsafe { res.assume_init() }),
-1 => Err(Error::UNSUPPORTED),
_ => Err(Error::UNEXPECTED),
}
}

pub fn fill_inner(mut dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use core::{
};
use use_file::util_libc;

pub use crate::util::{inner_u32, inner_u64};

type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;

/// Sentinel value which indicates that `libc::getrandom` either not available,
Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_rustix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::{Error, MaybeUninit};
use rustix::rand::{getrandom_uninit, GetRandomFlags};

pub use crate::util::{inner_u32, inner_u64};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!");

Expand Down
2 changes: 2 additions & 0 deletions src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use core::{
sync::atomic::{AtomicPtr, Ordering},
};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
61 changes: 52 additions & 9 deletions src/backends/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ cfg_if! {
}
}

static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();

// 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.
Expand Down Expand Up @@ -99,15 +101,6 @@ fn is_rdrand_good() -> bool {
unsafe { self_test() }
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND)
}

// TODO: make this function safe when we have feature(target_feature_11)
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
Expand All @@ -127,3 +120,53 @@ unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
}
Some(())
}

#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand().map(crate::util::truncate)
}

#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
rdrand()
}

#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand()
}

#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
let a = rdrand()?;
let b = rdrand()?;
Some((u64::from(a) << 32) || u64::from(b))
}

pub fn inner_u32() -> Result<u32, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u32() }.ok_or(Error::FAILED_RDRAND)
}

pub fn inner_u64() -> Result<u64, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u64() }.ok_or(Error::FAILED_RDRAND)
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND)
}
25 changes: 24 additions & 1 deletion src/backends/rndr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
//!
//! Arm Architecture Reference Manual for A-profile architecture:
//! ARM DDI 0487K.a, ID032224, D23.2.147 RNDR, Random Number
use crate::{util::slice_as_uninit, Error};
use crate::{
util::{slice_as_uninit, truncate},
Error,
};
use core::arch::asm;
use core::mem::{size_of, MaybeUninit};

Expand Down Expand Up @@ -101,6 +104,26 @@ fn is_rndr_available() -> bool {
}
}

pub fn inner_u32() -> Result<u32, Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.map(truncate).ok_or(Error::RNDR_FAILURE)
} else {
Err(Error::RNDR_NOT_AVAILABLE)
}
}

pub fn inner_u64() -> Result<u64, Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.ok_or(Error::RNDR_FAILURE)
} else {
Err(Error::RNDR_NOT_AVAILABLE)
}
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
Expand Down
2 changes: 2 additions & 0 deletions src/backends/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/solid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

extern "C" {
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;
}
Expand Down
3 changes: 3 additions & 0 deletions src/backends/use_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use core::{
sync::atomic::{AtomicI32, Ordering},
};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
pub(super) mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/vxworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use core::{
#[path = "../util_libc.rs"]
mod util_libc;

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
while !RNG_INIT.load(Relaxed) {
Expand Down
73 changes: 0 additions & 73 deletions src/backends/wasi.rs

This file was deleted.

Loading