|
1 | 1 | //! Implementation for Windows |
2 | 2 | use crate::Error; |
3 | | -use core::{ffi::c_void, mem::MaybeUninit, num::NonZeroU32, ptr}; |
| 3 | +use core::mem::MaybeUninit; |
4 | 4 |
|
5 | | -const BCRYPT_USE_SYSTEM_PREFERRED_RNG: u32 = 0x00000002; |
| 5 | +type BOOL = i32; |
| 6 | +const TRUE: BOOL = 1; |
6 | 7 |
|
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 | +)] |
8 | 20 | 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; |
23 | 22 | } |
24 | 23 |
|
25 | 24 | 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); |
58 | 28 | Ok(()) |
59 | 29 | } |
0 commit comments