Add in a RtlGenRandom fallback for non-UWP Windows (#337)
* Add in a RtlGenRandom fallback for non-UWP Windows In some instances BCryptRandom will fail when RtlGenRandom will work. On UWP, we might be unable to actually use RtlGenRandom. Thread the needle and use RtlGenRandom when we have to, when we're able. See also rust-lang/rust#108060 Fixes #314 * style suggestion Co-authored-by: Artyom Pavlov <newpavlov@gmail.com> * appease clippy --------- Co-authored-by: Artyom Pavlov <newpavlov@gmail.com>
This commit is contained in:
@@ -21,6 +21,14 @@ extern "system" {
|
||||
) -> 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -35,6 +43,15 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
|
||||
};
|
||||
// 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);
|
||||
|
||||
Reference in New Issue
Block a user