22
22
//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
23
23
//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
24
24
//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles
25
- use crate :: io;
26
25
use crate :: mem;
27
26
use crate :: ptr;
28
27
use crate :: sys:: c;
@@ -34,35 +33,41 @@ use crate::sys::c;
34
33
/// [`HashMap`]: crate::collections::HashMap
35
34
/// [`RandomState`]: crate::collections::hash_map::RandomState
36
35
pub 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 > {
37
42
let mut v = ( 0 , 0 ) ;
38
- let ret = unsafe {
43
+ let status = unsafe {
39
44
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 )
48
46
} ;
49
- if ret != 0 { fallback_rng ( ) } else { v }
47
+ if c :: nt_success ( status ) { Ok ( v ) } else { Err ( status ) }
50
48
}
51
49
52
50
/// Generate random numbers using the fallback RNG function (RtlGenRandom)
53
51
#[ cfg( not( target_vendor = "uwp" ) ) ]
54
52
#[ inline( never) ]
55
- fn fallback_rng ( ) -> ( u64 , u64 ) {
53
+ fn fallback_rng ( rng_status : c :: NTSTATUS ) -> ( u64 , u64 ) {
56
54
let mut v = ( 0 , 0 ) ;
57
55
let ret =
58
56
unsafe { c:: RtlGenRandom ( & mut v as * mut _ as * mut u8 , mem:: size_of_val ( & v) as c:: ULONG ) } ;
59
57
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
+ }
61
66
}
62
67
63
68
/// We can't use RtlGenRandom with UWP, so there is no fallback
64
69
#[ cfg( target_vendor = "uwp" ) ]
65
70
#[ 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" ) ;
68
73
}
0 commit comments