diff --git a/src/windows.rs b/src/windows.rs index e5a626c0..1282a92b 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -21,6 +21,12 @@ extern "system" { ) -> u32; } +extern "system" { + // Forbidden when targetting UWP + #[link_name = "SystemFunction036"] + fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8; +} + pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { // Prevent overflow of u32 for chunk in dest.chunks_mut(u32::max_value() as usize) { @@ -33,17 +39,33 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit]) -> Result<(), Error> { BCRYPT_USE_SYSTEM_PREFERRED_RNG, ) }; - // NTSTATUS codes use the two highest bits for severity status. - if ret >> 30 == 0b11 { - // 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)); + if ret > 0 { + // Failed. Try RtlGenRandom as a fallback. + let ret = fallback_rng(chunk); + // NTSTATUS codes use the two highest bits for severity status. + if ret >> 30 == 0b11 { + // 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)); + } } } Ok(()) } + +#[cfg(not(target_vendor = "uwp"))] +#[inline(never)] +fn fallback_rng(chunk: &mut [MaybeUninit]) -> u8 { + unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut u8, chunk.len() as u32) } +} + +#[cfg(target_vendor = "uwp")] +#[inline(never)] +fn fallback_rng(_chunk: &mut [MaybeUninit]) -> u8 { + return Error::WINDOWS_RTL_GEN_RANDOM; +}