Skip to content

Commit 16250fd

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 16250fd

File tree

1 file changed

+32
-8
lines changed

1 file changed

+32
-8
lines changed

src/windows.rs

+32-8
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) {
@@ -35,15 +41,33 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
3541
};
3642
// NTSTATUS codes use the two highest bits for severity status.
3743
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));
44+
// Failed. Try RtlGenRandom as a fallback.
45+
let success = fallback_rng(chunk);
46+
if !success {
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>]) -> bool {
64+
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut u8, chunk.len() as u32) };
65+
// RtlGenRandom returns BOOLEAN TRUE (i.e. 1) on success, FALSE (i.e. 0) on failure.
66+
ret != 0
67+
}
68+
69+
#[cfg(target_vendor = "uwp")]
70+
#[inline(never)]
71+
fn fallback_rng(_chunk: &mut [MaybeUninit<u8>]) -> bool {
72+
return false;
73+
}

0 commit comments

Comments
 (0)