diff --git a/src/api/mod.rs b/src/api/mod.rs index 9f5c347..009ee40 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -89,7 +89,7 @@ pub mod fs; pub mod io; pub mod process; pub mod prompt; -pub mod random; +pub mod rng; pub mod regex; pub mod syscall; pub mod time; diff --git a/src/api/random.rs b/src/api/rng.rs similarity index 100% rename from src/api/random.rs rename to src/api/rng.rs diff --git a/src/lib.rs b/src/lib.rs index 0a8d656..04527d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,7 @@ pub fn init(boot_info: &'static BootInfo) { sys::mem::init(boot_info); sys::acpi::init(); // Require MEM sys::cpu::init(); + sys::rng::init(); sys::pci::init(); // Require MEM sys::net::init(); // Require PCI sys::ata::init(); diff --git a/src/sys/fs/device.rs b/src/sys/fs/device.rs index bd70fc1..983e2cc 100644 --- a/src/sys/fs/device.rs +++ b/src/sys/fs/device.rs @@ -9,7 +9,7 @@ use crate::sys::cmos::RTC; use crate::sys::console::Console; use crate::sys::net::socket::tcp::TcpSocket; use crate::sys::net::socket::udp::UdpSocket; -use crate::sys::random::Random; +use crate::sys::rng::Random; use alloc::vec; use alloc::vec::Vec; diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 27e3927..f89fb1a 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -54,7 +54,7 @@ pub mod net; pub mod pci; pub mod pic; pub mod process; -pub mod random; +pub mod rng; pub mod serial; pub mod syscall; pub mod time; diff --git a/src/sys/net/socket/mod.rs b/src/sys/net/socket/mod.rs index 9aad3a3..ee90bb1 100644 --- a/src/sys/net/socket/mod.rs +++ b/src/sys/net/socket/mod.rs @@ -16,7 +16,7 @@ lazy_static! { } fn random_port() -> u16 { - 49152 + sys::random::get_u16() % 16384 + 49152 + sys::rng::get_u16() % 16384 } fn wait(duration: Duration) { diff --git a/src/sys/random.rs b/src/sys/random.rs deleted file mode 100644 index 6f3fee9..0000000 --- a/src/sys/random.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::api::fs::{FileIO, IO}; -use crate::sys; - -use rand::{RngCore, SeedableRng}; -use rand_hc::Hc128Rng; -use x86_64::instructions::random::RdRand; - -#[derive(Debug, Clone)] -pub struct Random; - -impl Random { - pub fn new() -> Self { - Self {} - } -} - -impl FileIO for Random { - fn read(&mut self, buf: &mut [u8]) -> Result { - let n = buf.len(); - for i in 0..n { - buf[i] = get_u64() as u8; - } - Ok(n) - } - - fn write(&mut self, _buf: &[u8]) -> Result { - unimplemented!(); - } - - fn close(&mut self) {} - - fn poll(&mut self, event: IO) -> bool { - match event { - IO::Read => true, - IO::Write => false, - } - } -} - -pub fn get_u64() -> u64 { - let mut seed = [0u8; 32]; - if let Some(rdrand) = RdRand::new() { - for i in 0..4 { - if let Some(rand) = rdrand.get_u64() { - let bytes = rand.to_be_bytes(); - for j in 0..8 { - seed[8 * i + j] = bytes[j]; - } - } - } - } else { - // FIXME: RDRAND instruction is not available on old CPUs - seed[0..8].clone_from_slice(&sys::time::ticks().to_be_bytes()); - seed[8..16].clone_from_slice(&sys::clock::realtime().to_be_bytes()); - seed[16..24].clone_from_slice(&sys::clock::uptime().to_be_bytes()); - seed[24..32].clone_from_slice(&sys::time::ticks().to_be_bytes()); - } - let mut rng = Hc128Rng::from_seed(seed); - rng.next_u64() -} - -pub fn get_u32() -> u32 { - get_u64() as u32 -} - -pub fn get_u16() -> u16 { - get_u64() as u16 -} diff --git a/src/sys/rng.rs b/src/sys/rng.rs new file mode 100644 index 0000000..f2c618f --- /dev/null +++ b/src/sys/rng.rs @@ -0,0 +1,91 @@ +use crate::api::fs::{FileIO, IO}; +use crate::sys; + +use lazy_static::lazy_static; +use rand::{RngCore, SeedableRng}; +use rand_hc::Hc128Rng; +use sha2::{Digest, Sha256}; +use spin::Mutex; +use x86_64::instructions::random::RdRand; + +lazy_static! { + static ref RNG: Mutex = Mutex::new(Hc128Rng::from_seed([0; 32])); +} + +#[derive(Debug, Clone)] +pub struct Random; + +impl Random { + pub fn new() -> Self { + Self {} + } +} + +impl FileIO for Random { + fn read(&mut self, buf: &mut [u8]) -> Result { + let n = buf.len(); + for chunk in buf.chunks_mut(8) { + let bytes = get_u64().to_le_bytes(); + let count = chunk.len(); + chunk.clone_from_slice(&bytes[..count]); + } + Ok(n) + } + + fn write(&mut self, _buf: &[u8]) -> Result { + unimplemented!(); + } + + fn close(&mut self) {} + + fn poll(&mut self, event: IO) -> bool { + match event { + IO::Read => true, + IO::Write => false, + } + } +} + +pub fn get_u64() -> u64 { + RNG.lock().next_u64() +} + +pub fn get_u32() -> u32 { + get_u64() as u32 +} + +pub fn get_u16() -> u16 { + get_u64() as u16 +} + +pub fn init() { + let mut seed = [0; 32]; + if let Some(rng) = RdRand::new() { + log!("RNG RDRAND available"); + for chunk in seed.chunks_mut(8) { + // NOTE: Intel's Software Developer's Manual, Volume 1, 7.3.17.1 + let mut retry = true; + for _ in 0..10 { // Retry up to 10 times + if let Some(num) = rng.get_u64() { + chunk.clone_from_slice(&num.to_be_bytes()); + retry = false; + break; + } else { + //debug!("RDRAND: read failed"); + } + } + if retry { + //debug!("RDRAND: retry failed"); + } + } + } else { + log!("RNG RDRAND unavailable"); + let mut hasher = Sha256::new(); + hasher.update(&sys::time::ticks().to_be_bytes()); + hasher.update(&sys::clock::realtime().to_be_bytes()); + hasher.update(&sys::clock::uptime().to_be_bytes()); + seed = hasher.finalize().into(); + } + + *RNG.lock() = Hc128Rng::from_seed(seed); +} diff --git a/src/usr/host.rs b/src/usr/host.rs index 03475d0..a3cae2f 100644 --- a/src/usr/host.rs +++ b/src/usr/host.rs @@ -1,6 +1,6 @@ use crate::api::console::Style; use crate::api::process::ExitCode; -use crate::api::random; +use crate::api::rng; use crate::api::syscall; use crate::sys::fs::OpenFlag; use crate::usr; @@ -61,7 +61,7 @@ impl Message { pub fn query(qname: &str, qtype: QueryType, qclass: QueryClass) -> Self { let mut datagram = Vec::new(); - let id = random::get_u16(); + let id = rng::get_u16(); for b in id.to_be_bytes().iter() { datagram.push(*b); // Transaction ID } diff --git a/src/usr/life.rs b/src/usr/life.rs index bc8fdf2..a455e9b 100644 --- a/src/usr/life.rs +++ b/src/usr/life.rs @@ -2,7 +2,7 @@ use crate::{api, sys}; use crate::api::console::Style; use crate::api::fs; use crate::api::process::ExitCode; -use crate::api::random; +use crate::api::rng; use crate::sys::console; use alloc::collections::BTreeSet; @@ -109,8 +109,8 @@ impl Game { fn seed(&mut self) { let n = self.seed_population; for _ in 0..n { - let x = (random::get_u64() % (self.cols as u64)) as i64; - let y = (random::get_u64() % (self.rows as u64)) as i64; + let x = (rng::get_u64() % (self.cols as u64)) as i64; + let y = (rng::get_u64() % (self.rows as u64)) as i64; self.grid.insert((x, y)); } } diff --git a/src/usr/pow.rs b/src/usr/pow.rs index c76d941..c0b7874 100644 --- a/src/usr/pow.rs +++ b/src/usr/pow.rs @@ -1,6 +1,6 @@ use crate::api::console::Style; use crate::api::process::ExitCode; -use crate::api::{console, io, random}; +use crate::api::{console, io, rng}; use alloc::format; use alloc::string::ToString; @@ -52,7 +52,7 @@ impl Game { let zeros: Vec<_> = (0..16).filter(|i| self.board[*i] == 0).collect(); if !zeros.is_empty() { - let i = (random::get_u64() as usize) % zeros.len(); + let i = (rng::get_u64() as usize) % zeros.len(); self.board[zeros[i]] = 2; } } diff --git a/src/usr/user.rs b/src/usr/user.rs index dd6d5bd..334d7f3 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -2,7 +2,7 @@ use crate::api::console::Style; use crate::api::fs; use crate::api::io; use crate::api::process::ExitCode; -use crate::api::random; +use crate::api::rng; use crate::api::syscall; use crate::{api, sys, usr}; use alloc::collections::btree_map::BTreeMap; @@ -165,7 +165,7 @@ pub fn hash(password: &str) -> String { // Generating salt for i in 0..2 { - let num = random::get_u64(); + let num = rng::get_u64(); let buf = num.to_be_bytes(); let n = buf.len(); for j in 0..n {