11use crate :: sys:: c;
22
3- #[ cfg( not( target_vendor = "win7" ) ) ]
3+ #[ cfg( not( any ( target_vendor = "win7" , target_vendor = "rust9x" ) ) ) ]
44#[ inline]
55pub fn fill_bytes ( bytes : & mut [ u8 ] ) {
66 let ret = unsafe { c:: ProcessPrng ( bytes. as_mut_ptr ( ) , bytes. len ( ) ) } ;
@@ -18,3 +18,96 @@ pub fn fill_bytes(mut bytes: &mut [u8]) {
1818 bytes = & mut bytes[ len as usize ..] ;
1919 }
2020}
21+
22+ #[ cfg( target_vendor = "rust9x" ) ]
23+ mod rust9x {
24+ use super :: * ;
25+ use crate :: sys:: sync:: OnceBox ;
26+
27+ pub fn fill_bytes ( mut bytes : & mut [ u8 ] ) {
28+ if let Some ( f) = c:: RtlGenRandom :: available ( ) {
29+ while !bytes. is_empty ( ) {
30+ let len = bytes. len ( ) . try_into ( ) . unwrap_or ( u32:: MAX ) ;
31+ let ret = unsafe { f ( bytes. as_mut_ptr ( ) . cast ( ) , len) } ;
32+ assert_ne ! ( ret, 0 , "failed to generate random data" ) ;
33+ bytes = & mut bytes[ len as usize ..] ;
34+ }
35+ } else if let Some ( f) = c:: CryptGenRandom :: available ( ) {
36+ let ctx = CRYPT_CONTEXT . get_or_init ( init_crypt_context) ;
37+ while !bytes. is_empty ( ) {
38+ let len = bytes. len ( ) . try_into ( ) . unwrap_or ( u32:: MAX ) ;
39+ let ret = unsafe { f ( ctx. 0 , len, bytes. as_mut_ptr ( ) . cast ( ) ) } ;
40+ assert_ne ! ( ret, 0 , "failed to generate random data" ) ;
41+ bytes = & mut bytes[ len as usize ..] ;
42+ }
43+ } else {
44+ // well, we tried, fall back to a non-cryptographically-secure PRNG
45+ // for NT <4.0 and 95 without IE3.02 or higher.
46+
47+ // seed with stack address and tick count
48+ let mut state: [ u32 ; 2 ] = [ unsafe { c:: GetTickCount ( ) } , 0 ] ;
49+ state[ 1 ] = ( & raw const state) as u32 ;
50+
51+ let mut chunks = bytes. chunks_exact_mut ( 4 ) ;
52+ for chunk in & mut chunks {
53+ let [ a, b, c, d] = xoroshiro64_star_star ( & mut state) . to_ne_bytes ( ) ;
54+ chunk[ 0 ] = a;
55+ chunk[ 1 ] = b;
56+ chunk[ 2 ] = c;
57+ chunk[ 3 ] = d;
58+ }
59+
60+ let remainder = chunks. into_remainder ( ) ;
61+ if remainder. is_empty ( ) {
62+ return ;
63+ }
64+
65+ for ( rem, val) in
66+ remainder. iter_mut ( ) . zip ( xoroshiro64_star_star ( & mut state) . to_ne_bytes ( ) )
67+ {
68+ * rem = val;
69+ }
70+ }
71+ }
72+
73+ static CRYPT_CONTEXT : OnceBox < HCryptProvider > = OnceBox :: new ( ) ;
74+
75+ struct HCryptProvider ( usize ) ;
76+ impl Drop for HCryptProvider {
77+ fn drop ( & mut self ) {
78+ unsafe {
79+ c:: CryptReleaseContext ( self . 0 , 0 ) ;
80+ }
81+ }
82+ }
83+
84+ fn init_crypt_context ( ) -> Box < HCryptProvider > {
85+ let mut crypt_context = 0 ;
86+ unsafe {
87+ let ret = c:: CryptAcquireContextA (
88+ & mut crypt_context,
89+ core:: ptr:: null ( ) ,
90+ core:: ptr:: null ( ) ,
91+ c:: PROV_RSA_FULL ,
92+ c:: CRYPT_VERIFYCONTEXT ,
93+ ) ;
94+ assert_ne ! ( ret, c:: FALSE , "failed to acquire crypt context: {:#X}" , c:: GetLastError ( ) ) ;
95+ } ;
96+ Box :: new ( HCryptProvider ( crypt_context) )
97+ }
98+
99+ // xoroshiro64**
100+ // 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org)
101+ // https://prng.di.unimi.it/xoroshiro64starstar.c
102+ fn xoroshiro64_star_star ( state : & mut [ u32 ; 2 ] ) -> u32 {
103+ let result = state[ 0 ] . wrapping_mul ( 0x9E3779BB ) . rotate_left ( 5 ) . wrapping_mul ( 5 ) ;
104+ state[ 1 ] ^= state[ 0 ] ;
105+ state[ 0 ] = state[ 0 ] . rotate_left ( 26 ) ^ state[ 1 ] ^ ( state[ 1 ] << 9 ) ;
106+ state[ 1 ] = state[ 1 ] . rotate_left ( 13 ) ;
107+
108+ result
109+ }
110+ }
111+
112+ #[ cfg( target_vendor = "rust9x" ) ]
113+ pub use rust9x:: fill_bytes;
0 commit comments