Skip to content

Commit e080813

Browse files
committed
Add ProcessPrng implementation
1 parent ea0207f commit e080813

File tree

3 files changed

+13
-51
lines changed

3 files changed

+13
-51
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ libc = { version = "0.2.154", default-features = false }
2323
[target.'cfg(target_os = "wasi")'.dependencies]
2424
wasi = { version = "0.11", default-features = false }
2525

26+
[target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies]
27+
windows-targets = "0.52"
28+
2629
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
2730
wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
2831
js-sys = { version = "0.3", optional = true }

src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ impl Error {
5353
/// Called from an ES module on Node.js. This is unsupported, see:
5454
/// <https://docs.rs/getrandom#nodejs-es-module-support>.
5555
pub const NODE_ES_MODULE: Error = internal_error(14);
56+
/// Calling Windows ProcessPrng failed.
57+
pub const WINDOWS_PROCESS_PRNG: Error = internal_error(15);
5658

5759
/// Codes below this point represent OS Errors (i.e. positive i32 values).
5860
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
@@ -172,6 +174,7 @@ fn internal_desc(error: Error) -> Option<&'static str> {
172174
Error::NODE_CRYPTO => Some("Node.js crypto CommonJS module is unavailable"),
173175
Error::NODE_RANDOM_FILL_SYNC => Some("Calling Node.js API crypto.randomFillSync failed"),
174176
Error::NODE_ES_MODULE => Some("Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es-module-support"),
177+
Error::WINDOWS_PROCESS_PRNG => Some("ProcessPrng: Windows system function failure"),
175178
_ => None,
176179
}
177180
}

src/windows.rs

+7-51
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,15 @@
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-
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;
23-
}
8+
windows_targets::link!("bcryptprimitives.dll" "system" fn ProcessPrng(pbdata : *mut u8, cbdata : usize) -> BOOL);
249

2510
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-
}
11+
match unsafe { ProcessPrng(dest.as_mut_ptr() as *mut u8, dest.len()) } {
12+
TRUE => Ok(()),
13+
_ => Err(Error::WINDOWS_PROCESS_PRNG),
5714
}
58-
Ok(())
5915
}

0 commit comments

Comments
 (0)