diff options
Diffstat (limited to 'vendor/getrandom/src/windows.rs')
-rw-r--r-- | vendor/getrandom/src/windows.rs | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/vendor/getrandom/src/windows.rs b/vendor/getrandom/src/windows.rs index 41dc37a5c..92d70429e 100644 --- a/vendor/getrandom/src/windows.rs +++ b/vendor/getrandom/src/windows.rs @@ -7,7 +7,7 @@ // except according to those terms. use crate::Error; -use core::{ffi::c_void, num::NonZeroU32, ptr}; +use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr}; const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; @@ -21,20 +21,37 @@ extern "system" { ) -> u32; } -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { +// 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; +} + +pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> 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(), + 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); |