Skip to content

Commit 5223c3e

Browse files
committed
New impl
Signed-off-by: Joe Richey <[email protected]>
1 parent c60085f commit 5223c3e

File tree

3 files changed

+44
-49
lines changed

3 files changed

+44
-49
lines changed

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ cfg_if! {
318318
#[path = "solid.rs"] mod imp;
319319
} else if #[cfg(target_os = "espidf")] {
320320
#[path = "espidf.rs"] mod imp;
321+
} else if #[cfg(all(windows, target_vendor = "win7"))] {
322+
#[path = "windows7.rs"] mod imp;
321323
} else if #[cfg(windows)] {
322324
#[path = "windows.rs"] mod imp;
323325
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {

src/windows.rs

+19-49
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,29 @@
11
//! Implementation for Windows
22
use crate::Error;
3-
use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr};
3+
use core::mem::MaybeUninit;
44

5-
const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
5+
type BOOL = i32;
6+
const TRUE: BOOL = 1;
67

7-
#[link(name = "bcrypt")]
8+
#[cfg_attr(
9+
target_arch = "x86",
10+
link(
11+
name = "bcryptprimitives",
12+
kind = "raw-dylib",
13+
import_name_type = "undecorated"
14+
)
15+
)]
16+
#[cfg_attr(
17+
not(target_arch = "x86"),
18+
link(name = "bcryptprimitives", kind = "raw-dylib")
19+
)]
820
extern "system" {
9-
fn BCryptGenRandom(
10-
hAlgorithm: *mut c_void,
11-
pBuffer: *mut u8,
12-
cbBuffer: u32,
13-
dwFlags: u32,
14-
) -> u32;
15-
}
16-
17-
// Forbidden when targetting UWP
18-
#[cfg(not(target_vendor = "uwp"))]
19-
#[link(name = "advapi32")]
20-
extern "system" {
21-
#[link_name = "SystemFunction036"]
22-
fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: u32) -> u8;
21+
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
2322
}
2423

2524
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
26-
// Prevent overflow of u32
27-
for chunk in dest.chunks_mut(u32::max_value() as usize) {
28-
// BCryptGenRandom was introduced in Windows Vista
29-
let ret = unsafe {
30-
BCryptGenRandom(
31-
ptr::null_mut(),
32-
chunk.as_mut_ptr() as *mut u8,
33-
chunk.len() as u32,
34-
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
35-
)
36-
};
37-
// NTSTATUS codes use the two highest bits for severity status.
38-
if ret >> 30 == 0b11 {
39-
// Failed. Try RtlGenRandom as a fallback.
40-
#[cfg(not(target_vendor = "uwp"))]
41-
{
42-
let ret =
43-
unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) };
44-
if ret != 0 {
45-
continue;
46-
}
47-
}
48-
// We zeroize the highest bit, so the error code will reside
49-
// inside the range designated for OS codes.
50-
let code = ret ^ (1 << 31);
51-
// SAFETY: the second highest bit is always equal to one,
52-
// so it's impossible to get zero. Unfortunately the type
53-
// system does not have a way to express this yet.
54-
let code = unsafe { NonZeroU32::new_unchecked(code) };
55-
return Err(Error::from(code));
56-
}
57-
}
25+
let ret = unsafe { ProcessPrng(dest.as_mut_ptr() as *mut u8, dest.len()) };
26+
// ProcessPrng always returns TRUE
27+
assert_eq!(ret, TRUE);
5828
Ok(())
5929
}

src/windows7.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::Error;
2+
use core::{ffi::c_void, mem::MaybeUninit};
3+
4+
type BOOLEAN = u8;
5+
type ULONG = u32;
6+
const TRUE: BOOLEAN = 1;
7+
8+
#[link(name = "advapi32")]
9+
extern "system" {
10+
#[link_name = "SystemFunction036"]
11+
fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: ULONG) -> BOOLEAN;
12+
}
13+
14+
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
15+
// Prevent overflow of ULONG
16+
for chunk in dest.chunks_mut(u32::max_value() as usize) {
17+
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) };
18+
if ret != TRUE {
19+
return Err(Error::WINDOWS_RTL_GEN_RANDOM);
20+
}
21+
}
22+
Ok(())
23+
}

0 commit comments

Comments
 (0)