Use BCRYPT_RNG_ALG_HANDLE by default

Also briefly document the history of `sys/windows/rand.rs` as they may be relevant to any future changes.
This commit is contained in:
Chris Denton 2022-09-02 13:23:52 +01:00
parent e4f049312c
commit bc793c9fb2
No known key found for this signature in database
GPG Key ID: 713472F2F45627DE
2 changed files with 38 additions and 5 deletions

View File

@ -285,7 +285,7 @@ pub fn nt_success(status: NTSTATUS) -> bool {
status >= 0 status >= 0
} }
pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81;
#[repr(C)] #[repr(C)]
pub struct UNICODE_STRING { pub struct UNICODE_STRING {

View File

@ -1,16 +1,49 @@
//! # Random key generation
//!
//! This module wraps the RNG provided by the OS. There are a few different
//! ways to interface with the OS RNG so it's worth exploring each of the options.
//! Note that at the time of writing these all go through the (undocumented)
//! `bcryptPrimitives.dll` but they use different route to get there.
//!
//! Originally we were using [`RtlGenRandom`], however that function is
//! deprecated and warns it "may be altered or unavailable in subsequent versions".
//!
//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG`
//! flag to query and find the system configured RNG. However, this change caused a small
//! but significant number of users to experience panics caused by a failure of
//! this function. See [#94098].
//!
//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE`
//! [Pseudo-handle], which gets the default RNG algorithm without querying the
//! system preference thus hopefully avoiding the previous issue.
//! This is only supported on Windows 10+ so a fallback is used for older versions.
//!
//! [#94098]: https://github.com/rust-lang/rust/issues/94098
//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
use crate::io; use crate::io;
use crate::mem; use crate::mem;
use crate::ptr; use crate::ptr;
use crate::sys::c; use crate::sys::c;
/// Generates high quality secure random keys for use by [`HashMap`].
///
/// This is used to seed the default [`RandomState`].
///
/// [`HashMap`]: crate::collections::HashMap
/// [`RandomState`]: crate::collections::hash_map::RandomState
pub fn hashmap_random_keys() -> (u64, u64) { pub fn hashmap_random_keys() -> (u64, u64) {
let mut v = (0, 0); let mut v = (0, 0);
let ret = unsafe { let ret = unsafe {
let size = mem::size_of_val(&v).try_into().unwrap();
c::BCryptGenRandom( c::BCryptGenRandom(
ptr::null_mut(), // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
&mut v as *mut _ as *mut u8, // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails.
mem::size_of_val(&v) as c::ULONG, ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE),
c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, ptr::addr_of_mut!(v).cast(),
size,
0,
) )
}; };
if ret != 0 { fallback_rng() } else { v } if ret != 0 { fallback_rng() } else { v }