Skip to content

Commit ab8c2d5

Browse files
committed
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 rust-random#314
1 parent 7c83ea0 commit ab8c2d5

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

src/windows.rs

+32-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ extern "system" {
2121
) -> u32;
2222
}
2323

24+
extern "system" {
25+
// Forbidden when targetting UWP
26+
#[link_name = "SystemFunction036"]
27+
fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
28+
}
29+
2430
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
2531
// Prevent overflow of u32
2632
for chunk in dest.chunks_mut(u32::max_value() as usize) {
@@ -33,17 +39,33 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
3339
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
3440
)
3541
};
36-
// NTSTATUS codes use the two highest bits for severity status.
37-
if ret >> 30 == 0b11 {
38-
// We zeroize the highest bit, so the error code will reside
39-
// inside the range designated for OS codes.
40-
let code = ret ^ (1 << 31);
41-
// SAFETY: the second highest bit is always equal to one,
42-
// so it's impossible to get zero. Unfortunately the type
43-
// system does not have a way to express this yet.
44-
let code = unsafe { NonZeroU32::new_unchecked(code) };
45-
return Err(Error::from(code));
42+
if ret > 0 {
43+
// Failed. Try RtlGenRandom as a fallback.
44+
let fallback_ret = fallback_rng(chunk);
45+
// NTSTATUS codes use the two highest bits for severity status.
46+
if fallback_ret > 0 {
47+
// We zeroize the highest bit, so the error code will reside
48+
// inside the range designated for OS codes.
49+
let code = ret ^ (1 << 31);
50+
// SAFETY: the second highest bit is always equal to one,
51+
// so it's impossible to get zero. Unfortunately the type
52+
// system does not have a way to express this yet.
53+
let code = unsafe { NonZeroU32::new_unchecked(code) };
54+
return Err(Error::from(code));
55+
}
4656
}
4757
}
4858
Ok(())
4959
}
60+
61+
#[cfg(not(target_vendor = "uwp"))]
62+
#[inline(never)]
63+
fn fallback_rng(chunk: &mut [MaybeUninit<u8>]) -> u8 {
64+
unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut u8, chunk.len() as u32) }
65+
}
66+
67+
#[cfg(target_vendor = "uwp")]
68+
#[inline(never)]
69+
fn fallback_rng(_chunk: &mut [MaybeUninit<u8>]) -> u8 {
70+
return Error::WINDOWS_RTL_GEN_RANDOM;
71+
}

0 commit comments

Comments
 (0)