hermit/syscalls/
entropy.rs

1#[cfg(not(feature = "newlib"))]
2use core::mem::size_of;
3use core::slice;
4
5use hermit_sync::TicketMutex;
6
7use crate::arch;
8use crate::entropy::{self, Flags};
9use crate::errno::Errno;
10
11static PARK_MILLER_LEHMER_SEED: TicketMutex<u32> = TicketMutex::new(0);
12const RAND_MAX: u64 = 0x7fff_ffff;
13
14fn generate_park_miller_lehmer_random_number() -> u32 {
15	let mut seed = PARK_MILLER_LEHMER_SEED.lock();
16	let random = ((u64::from(*seed) * 48271) % RAND_MAX) as u32;
17	*seed = random;
18	random
19}
20
21unsafe fn read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize {
22	let Some(flags) = Flags::from_bits(flags) else {
23		return -i32::from(Errno::Inval) as isize;
24	};
25
26	let 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`.
29		let len = usize::min(len, isize::MAX as usize);
30		buf.write_bytes(0, len);
31		slice::from_raw_parts_mut(buf, len)
32	};
33
34	let ret = entropy::read(buf, flags);
35	if ret < 0 {
36		warn!("Unable to read entropy! Fallback to a naive implementation!");
37		for 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}
47
48/// Fill `len` bytes in `buf` with cryptographically secure random data.
49///
50/// Returns either the number of bytes written to buf (a positive value) or
51/// * `-EINVAL` if `flags` contains unknown flags.
52/// * `-ENOSYS` if the system does not support random data generation.
53#[hermit_macro::system]
54#[unsafe(no_mangle)]
55pub unsafe extern "C" fn sys_read_entropy(buf: *mut u8, len: usize, flags: u32) -> isize {
56	unsafe { read_entropy(buf, len, flags) }
57}
58
59/// Create a cryptographicly secure 32bit random number with the support of
60/// the underlying hardware. If the required hardware isn't available,
61/// the function returns `-1`.
62#[cfg(not(feature = "newlib"))]
63#[hermit_macro::system]
64#[unsafe(no_mangle)]
65pub unsafe extern "C" fn sys_secure_rand32(value: *mut u32) -> i32 {
66	let mut buf = value.cast();
67	let mut len = size_of::<u32>();
68	while len != 0 {
69		let res = unsafe { read_entropy(buf, len, 0) };
70		if res < 0 {
71			return -1;
72		}
73
74		buf = unsafe { buf.add(res as usize) };
75		len -= res as usize;
76	}
77
78	0
79}
80
81/// Create a cryptographicly secure 64bit random number with the support of
82/// the underlying hardware. If the required hardware isn't available,
83/// the function returns -1.
84#[cfg(not(feature = "newlib"))]
85#[hermit_macro::system]
86#[unsafe(no_mangle)]
87pub unsafe extern "C" fn sys_secure_rand64(value: *mut u64) -> i32 {
88	let mut buf = value.cast();
89	let mut len = size_of::<u64>();
90	while len != 0 {
91		let res = unsafe { read_entropy(buf, len, 0) };
92		if res < 0 {
93			return -1;
94		}
95
96		buf = unsafe { buf.add(res as usize) };
97		len -= res as usize;
98	}
99
100	0
101}
102
103/// The function computes a sequence of pseudo-random integers
104/// in the range of 0 to RAND_MAX
105#[hermit_macro::system]
106#[unsafe(no_mangle)]
107pub extern "C" fn sys_rand() -> u32 {
108	generate_park_miller_lehmer_random_number()
109}
110
111/// The function sets its argument as the seed for a new sequence
112/// of pseudo-random numbers to be returned by rand()
113#[hermit_macro::system]
114#[unsafe(no_mangle)]
115pub extern "C" fn sys_srand(seed: u32) {
116	*(PARK_MILLER_LEHMER_SEED.lock()) = seed;
117}
118
119pub(crate) fn init_entropy() {
120	let seed: u32 = arch::processor::get_timestamp() as u32;
121
122	*PARK_MILLER_LEHMER_SEED.lock() = seed;
123}