2222//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
2323//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
2424//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
25- use crate :: io;
2625use crate :: mem;
2726use crate :: ptr;
2827use crate :: sys:: c;
@@ -34,35 +33,41 @@ use crate::sys::c;
3433/// [`HashMap`]: crate::collections::HashMap
3534/// [`RandomState`]: crate::collections::hash_map::RandomState
3635pub fn hashmap_random_keys ( ) -> ( u64 , u64 ) {
36+ // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
37+ // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails
38+ gen_random_keys ( c:: BCRYPT_RNG_ALG_HANDLE ) . unwrap_or_else ( fallback_rng)
39+ }
40+
41+ fn gen_random_keys ( algorithm : c:: BCRYPT_ALG_HANDLE ) -> Result < ( u64 , u64 ) , c:: NTSTATUS > {
3742 let mut v = ( 0 , 0 ) ;
38- let ret = unsafe {
43+ let status = unsafe {
3944 let size = mem:: size_of_val ( & v) . try_into ( ) . unwrap ( ) ;
40- c:: BCryptGenRandom (
41- // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+.
42- // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails.
43- ptr:: invalid_mut ( c:: BCRYPT_RNG_ALG_HANDLE ) ,
44- ptr:: addr_of_mut!( v) . cast ( ) ,
45- size,
46- 0 ,
47- )
45+ c:: BCryptGenRandom ( algorithm, ptr:: addr_of_mut!( v) . cast ( ) , size, 0 )
4846 } ;
49- if ret != 0 { fallback_rng ( ) } else { v }
47+ if c :: nt_success ( status ) { Ok ( v ) } else { Err ( status ) }
5048}
5149
5250/// Generate random numbers using the fallback RNG function (RtlGenRandom)
5351#[ cfg( not( target_vendor = "uwp" ) ) ]
5452#[ inline( never) ]
55- fn fallback_rng ( ) -> ( u64 , u64 ) {
53+ fn fallback_rng ( rng_status : c :: NTSTATUS ) -> ( u64 , u64 ) {
5654 let mut v = ( 0 , 0 ) ;
5755 let ret =
5856 unsafe { c:: RtlGenRandom ( & mut v as * mut _ as * mut u8 , mem:: size_of_val ( & v) as c:: ULONG ) } ;
5957
60- if ret != 0 { v } else { panic ! ( "fallback RNG broken: {}" , io:: Error :: last_os_error( ) ) }
58+ if ret != 0 {
59+ v
60+ } else {
61+ panic ! (
62+ "RNG broken: {rng_status:#x}, fallback RNG broken: {}" ,
63+ crate :: io:: Error :: last_os_error( )
64+ )
65+ }
6166}
6267
6368/// We can't use RtlGenRandom with UWP, so there is no fallback
6469#[ cfg( target_vendor = "uwp" ) ]
6570#[ inline( never) ]
66- fn fallback_rng ( ) -> ( u64 , u64 ) {
67- panic ! ( "fallback RNG broken: RtlGenRandom() not supported on UWP" ) ;
71+ fn fallback_rng ( rng_status : c :: NTSTATUS ) -> ( u64 , u64 ) {
72+ panic ! ( "RMG broken: {rng_status:#x} fallback RNG broken: RtlGenRandom() not supported on UWP" ) ;
6873}
0 commit comments