diff --git a/src/lib.rs b/src/lib.rs index f9ea6ada..b90c2c63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,6 +318,8 @@ cfg_if! { #[path = "solid.rs"] mod imp; } else if #[cfg(target_os = "espidf")] { #[path = "espidf.rs"] mod imp; + } else if #[cfg(all(windows, target_vendor = "win7"))] { + #[path = "windows7.rs"] mod imp; } else if #[cfg(windows)] { #[path = "windows.rs"] mod imp; } else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] { diff --git a/src/windows.rs b/src/windows.rs index 2d1c4835..fde78243 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,59 +1,29 @@ //! Implementation for Windows use crate::Error; -use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr}; +use core::mem::MaybeUninit; -const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; +type BOOL = i32; +const TRUE: BOOL = 1; -#[link(name = "bcrypt")] +#[cfg_attr( + target_arch = "x86", + link( + name = "bcryptprimitives", + kind = "raw-dylib", + import_name_type = "undecorated" + ) +)] +#[cfg_attr( + not(target_arch = "x86"), + link(name = "bcryptprimitives", kind = "raw-dylib") +)] extern "system" { - fn BCryptGenRandom( - hAlgorithm: *mut c_void, - pBuffer: *mut u8, - cbBuffer: u32, - dwFlags: u32, - ) -> u32; -} - -// Forbidden when targetting UWP -#[cfg(not(target_vendor = "uwp"))] -#[link(name = "advapi32")] -extern "system" { - #[link_name = "SystemFunction036"] - fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: u32) -> u8; + fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; } pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { - // Prevent overflow of u32 - for chunk in dest.chunks_mut(u32::max_value() as usize) { - // BCryptGenRandom was introduced in Windows Vista - let ret = unsafe { - BCryptGenRandom( - ptr::null_mut(), - chunk.as_mut_ptr() as *mut u8, - chunk.len() as u32, - BCRYPT_USE_SYSTEM_PREFERRED_RNG, - ) - }; - // NTSTATUS codes use the two highest bits for severity status. - if ret >> 30 == 0b11 { - // Failed. Try RtlGenRandom as a fallback. - #[cfg(not(target_vendor = "uwp"))] - { - let ret = - unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) }; - if ret != 0 { - continue; - } - } - // We zeroize the highest bit, so the error code will reside - // inside the range designated for OS codes. - let code = ret ^ (1 << 31); - // SAFETY: the second highest bit is always equal to one, - // so it's impossible to get zero. Unfortunately the type - // system does not have a way to express this yet. - let code = unsafe { NonZeroU32::new_unchecked(code) }; - return Err(Error::from(code)); - } - } + let ret = unsafe { ProcessPrng(dest.as_mut_ptr() as *mut u8, dest.len()) }; + // ProcessPrng always returns TRUE + assert_eq!(ret, TRUE); Ok(()) } diff --git a/src/windows7.rs b/src/windows7.rs new file mode 100644 index 00000000..a985635d --- /dev/null +++ b/src/windows7.rs @@ -0,0 +1,23 @@ +use crate::Error; +use core::{ffi::c_void, mem::MaybeUninit}; + +type BOOLEAN = u8; +type ULONG = u32; +const TRUE: BOOLEAN = 1; + +#[link(name = "advapi32")] +extern "system" { + #[link_name = "SystemFunction036"] + fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: ULONG) -> BOOLEAN; +} + +pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { + // Prevent overflow of ULONG + for chunk in dest.chunks_mut(u32::max_value() as usize) { + let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) }; + if ret != TRUE { + return Err(Error::WINDOWS_RTL_GEN_RANDOM); + } + } + Ok(()) +}