1#[cfg(not(feature = "newlib"))]
2use core::mem::size_of;
3use core::slice;
45use hermit_sync::TicketMutex;
67use crate::arch;
8use crate::entropy::{self, Flags};
9use crate::errno::EINVAL;
1011static PARK_MILLER_LEHMER_SEED: TicketMutex<u32> = TicketMutex::new(0);
12const RAND_MAX: u64 = 0x7fff_ffff;
1314fn generate_park_miller_lehmer_random_number() -> u32 {
15let mut seed = PARK_MILLER_LEHMER_SEED.lock();
16let random = ((u64::from(*seed) * 48271) % RAND_MAX) as u32;
17*seed = random;
18 random
19}
2021unsafe fn read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize {
22let Some(flags) = Flags::from_bits(flags) else {
23return -EINVAL as isize;
24 };
2526let buf = unsafe {
27// Cap the number of bytes to be read at a time to isize::MAX to uphold
28 // the safety guarantees of `from_raw_parts`.
29let len = usize::min(len, isize::MAX as usize);
30 buf.write_bytes(0, len);
31 slice::from_raw_parts_mut(buf, len)
32 };
3334let ret = entropy::read(buf, flags);
35if ret < 0 {
36warn!("Unable to read entropy! Fallback to a naive implementation!");
37for i in &mut *buf {
38*i = (generate_park_miller_lehmer_random_number() & 0xff)
39 .try_into()
40 .unwrap();
41 }
42 buf.len().try_into().unwrap()
43 } else {
44 ret
45 }
46}
4748unsafe extern "C" fn __sys_read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize {
49unsafe { read_entropy(buf, len, flags) }
50}
5152/// Fill `len` bytes in `buf` with cryptographically secure random data.
53///
54/// Returns either the number of bytes written to buf (a positive value) or
55/// * `-EINVAL` if `flags` contains unknown flags.
56/// * `-ENOSYS` if the system does not support random data generation.
57#[unsafe(no_mangle)]
58pub unsafe extern "C" fn sys_read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize {
59unsafe { kernel_function!(__sys_read_entropy(buf, len, flags)) }
60}
6162/// Create a cryptographicly secure 32bit random number with the support of
63/// the underlying hardware. If the required hardware isn't available,
64/// the function returns `-1`.
65#[cfg(not(feature = "newlib"))]
66#[hermit_macro::system]
67#[unsafe(no_mangle)]
68pub unsafe extern "C" fn sys_secure_rand32(value: *mut u32) -> i32 {
69let mut buf = value.cast();
70let mut len = size_of::<u32>();
71while len != 0 {
72let res = unsafe { read_entropy(buf, len, 0) };
73if res < 0 {
74return -1;
75 }
7677 buf = unsafe { buf.add(res as usize) };
78 len -= res as usize;
79 }
80810
82}
8384/// Create a cryptographicly secure 64bit random number with the support of
85/// the underlying hardware. If the required hardware isn't available,
86/// the function returns -1.
87#[cfg(not(feature = "newlib"))]
88#[hermit_macro::system]
89#[unsafe(no_mangle)]
90pub unsafe extern "C" fn sys_secure_rand64(value: *mut u64) -> i32 {
91let mut buf = value.cast();
92let mut len = size_of::<u64>();
93while len != 0 {
94let res = unsafe { read_entropy(buf, len, 0) };
95if res < 0 {
96return -1;
97 }
9899 buf = unsafe { buf.add(res as usize) };
100 len -= res as usize;
101 }
1021030
104}
105106/// The function computes a sequence of pseudo-random integers
107/// in the range of 0 to RAND_MAX
108#[hermit_macro::system]
109#[unsafe(no_mangle)]
110pub extern "C" fn sys_rand() -> u32 {
111 generate_park_miller_lehmer_random_number()
112}
113114/// The function sets its argument as the seed for a new sequence
115/// of pseudo-random numbers to be returned by rand()
116#[hermit_macro::system]
117#[unsafe(no_mangle)]
118pub extern "C" fn sys_srand(seed: u32) {
119*(PARK_MILLER_LEHMER_SEED.lock()) = seed;
120}
121122pub(crate) fn init_entropy() {
123let seed: u32 = arch::processor::get_timestamp() as u32;
124125*PARK_MILLER_LEHMER_SEED.lock() = seed;
126}