From 73dbb2524202df0955fca2c9f962f17334c06f5e Mon Sep 17 00:00:00 2001 From: Palash Tyagi <23239946+Magnus167@users.noreply.github.com> Date: Tue, 29 Jul 2025 23:23:04 +0100 Subject: [PATCH] Refactor CryptoRng implementation for Windows and Unix, adding support for secure random byte generation on Windows. --- src/random/crypto.rs | 71 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/src/random/crypto.rs b/src/random/crypto.rs index 9cfa725..6943d6a 100644 --- a/src/random/crypto.rs +++ b/src/random/crypto.rs @@ -1,21 +1,23 @@ -use std::fs::File; -use std::io::Read; +#[cfg(unix)] +use std::{fs::File, io::Read}; use crate::random::Rng; -/// Cryptographically secure RNG sourcing randomness from `/dev/urandom`. +#[cfg(unix)] pub struct CryptoRng { file: File, } +#[cfg(unix)] impl CryptoRng { - /// Open `/dev/urandom` and create a new generator. + /// Open `/dev/urandom`. pub fn new() -> Self { let file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); Self { file } } } +#[cfg(unix)] impl Rng for CryptoRng { fn next_u64(&mut self) -> u64 { let mut buf = [0u8; 8]; @@ -26,6 +28,67 @@ impl Rng for CryptoRng { } } +#[cfg(windows)] +pub struct CryptoRng; + +#[cfg(windows)] +impl CryptoRng { + /// No handle is needed on Windows. + pub fn new() -> Self { + Self + } +} + +#[cfg(windows)] +impl Rng for CryptoRng { + fn next_u64(&mut self) -> u64 { + let mut buf = [0u8; 8]; + win_fill(&mut buf).expect("BCryptGenRandom failed"); + u64::from_ne_bytes(buf) + } +} + +/// Fill `buf` with cryptographically secure random bytes using CNG. +/// +/// * `BCryptGenRandom(NULL, buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG)` +/// asks the OS for its system‑preferred DRBG (CTR_DRBG on modern +/// Windows). +#[cfg(windows)] +fn win_fill(buf: &mut [u8]) -> Result<(), ()> { + use core::ffi::c_void; + + type BCRYPT_ALG_HANDLE = *mut c_void; + type NTSTATUS = i32; + + const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x0000_0002; + + #[link(name = "bcrypt")] + extern "system" { + fn BCryptGenRandom( + hAlgorithm: BCRYPT_ALG_HANDLE, + pbBuffer: *mut u8, + cbBuffer: u32, + dwFlags: u32, + ) -> NTSTATUS; + } + + // NT_SUCCESS(status) == status >= 0 + let status = unsafe { + BCryptGenRandom( + core::ptr::null_mut(), + buf.as_mut_ptr(), + buf.len() as u32, + BCRYPT_USE_SYSTEM_PREFERRED_RNG, + ) + }; + + if status >= 0 { + Ok(()) + } else { + Err(()) + } +} + /// Convenience constructor for [`CryptoRng`]. pub fn crypto_rng() -> CryptoRng { CryptoRng::new()