Skip to content

Commit

Permalink
New impl
Browse files Browse the repository at this point in the history
Signed-off-by: Joe Richey <[email protected]>
  • Loading branch information
josephlr committed Apr 30, 2024
1 parent c60085f commit 5223c3e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ cfg_if! {
#[path = "solid.rs"] mod imp;
} else if #[cfg(target_os = "espidf")] {
#[path = "espidf.rs"] mod imp;
} else if #[cfg(all(windows, target_vendor = "win7"))] {
#[path = "windows7.rs"] mod imp;
} else if #[cfg(windows)] {
#[path = "windows.rs"] mod imp;
} else if #[cfg(all(target_os = "horizon", target_arch = "arm"))] {
Expand Down
68 changes: 19 additions & 49 deletions src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,29 @@
//! Implementation for Windows
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr};
use core::mem::MaybeUninit;

const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002;
type BOOL = i32;
const TRUE: BOOL = 1;

#[link(name = "bcrypt")]
#[cfg_attr(
target_arch = "x86",
link(
name = "bcryptprimitives",
kind = "raw-dylib",
import_name_type = "undecorated"
)
)]
#[cfg_attr(
not(target_arch = "x86"),
link(name = "bcryptprimitives", kind = "raw-dylib")
)]
extern "system" {
fn BCryptGenRandom(
hAlgorithm: *mut c_void,
pBuffer: *mut u8,
cbBuffer: u32,
dwFlags: u32,
) -> 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;
fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
}

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) {
// BCryptGenRandom was introduced in Windows Vista
let ret = unsafe {
BCryptGenRandom(
ptr::null_mut(),
chunk.as_mut_ptr() as *mut u8,
chunk.len() as u32,
BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};
// 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);
// SAFETY: the second highest bit is always equal to one,
// so it's impossible to get zero. Unfortunately the type
// system does not have a way to express this yet.
let code = unsafe { NonZeroU32::new_unchecked(code) };
return Err(Error::from(code));
}
}
let ret = unsafe { ProcessPrng(dest.as_mut_ptr() as *mut u8, dest.len()) };
// ProcessPrng always returns TRUE
assert_eq!(ret, TRUE);
Ok(())
}
23 changes: 23 additions & 0 deletions src/windows7.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

type BOOLEAN = u8;
type ULONG = u32;
const TRUE: BOOLEAN = 1;

#[link(name = "advapi32")]
extern "system" {
#[link_name = "SystemFunction036"]
fn RtlGenRandom(RandomBuffer: *mut c_void, RandomBufferLength: ULONG) -> BOOLEAN;
}

pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Prevent overflow of ULONG
for chunk in dest.chunks_mut(u32::max_value() as usize) {
let ret = unsafe { RtlGenRandom(chunk.as_mut_ptr() as *mut c_void, chunk.len() as u32) };
if ret != TRUE {
return Err(Error::WINDOWS_RTL_GEN_RANDOM);
}
}
Ok(())
}

0 comments on commit 5223c3e

Please sign in to comment.