1010
1111//! Entropy generator, or wrapper around external generators 
1212
13- use  rand_core:: { RngCore ,  CryptoRng ,  Error ,  impls} ; 
14- use  rngs:: { OsRng ,  JitterRng } ; 
13+ use  rand_core:: { RngCore ,  CryptoRng ,  Error ,  ErrorKind ,  impls} ; 
14+ #[ allow( unused) ]  
15+ use  rngs; 
1516
1617/// An interface returning random data from external source(s), provided 
1718/// specifically for securely seeding algorithmic generators (PRNGs). 
@@ -46,13 +47,14 @@ use rngs::{OsRng, JitterRng};
4647/// [`try_fill_bytes`]: ../trait.RngCore.html#method.tymethod.try_fill_bytes 
4748#[ derive( Debug ) ]  
4849pub  struct  EntropyRng  { 
49-     rng :   EntropySource , 
50+     source :   Source , 
5051} 
5152
5253#[ derive( Debug ) ]  
53- enum  EntropySource  { 
54-     Os ( OsRng ) , 
55-     Jitter ( JitterRng ) , 
54+ enum  Source  { 
55+     Os ( Os ) , 
56+     Custom ( Custom ) , 
57+     Jitter ( Jitter ) , 
5658    None , 
5759} 
5860
@@ -63,7 +65,7 @@ impl EntropyRng {
6365     /// those are done on first use. This is done to make `new` infallible, 
6466     /// and `try_fill_bytes` the only place to report errors. 
6567     pub  fn  new ( )  -> Self  { 
66-         EntropyRng  {  rng :   EntropySource :: None  } 
68+         EntropyRng  {  source :   Source :: None  } 
6769    } 
6870} 
6971
@@ -88,82 +90,199 @@ impl RngCore for EntropyRng {
8890    } 
8991
9092    fn  try_fill_bytes ( & mut  self ,  dest :  & mut  [ u8 ] )  -> Result < ( ) ,  Error >  { 
91-         fn  try_os_new ( dest :  & mut  [ u8 ] )  -> Result < OsRng ,  Error > 
92-         { 
93-             let  mut  rng = OsRng :: new ( ) ?; 
94-             rng. try_fill_bytes ( dest) ?; 
95-             Ok ( rng) 
96-         } 
93+         let  mut  reported_error = None ; 
9794
98-         fn  try_jitter_new ( dest :  & mut  [ u8 ] )  -> Result < JitterRng ,  Error > 
99-         { 
100-             let  mut  rng = JitterRng :: new ( ) ?; 
101-             rng. try_fill_bytes ( dest) ?; 
102-             Ok ( rng) 
95+         if  let  Source :: Os ( ref  mut  os_rng)  = self . source  { 
96+             match  os_rng. fill ( dest)  { 
97+                 Ok ( ( ) )  => return  Ok ( ( ) ) , 
98+                 Err ( err)  => { 
99+                     warn ! ( "EntropyRng: OsRng failed \  
100+                            [trying other entropy sources]: {}",  err) ; 
101+                     reported_error = Some ( err) ; 
102+                 } , 
103+             } 
104+         }  else  if  Os :: is_supported ( )  { 
105+             match  Os :: new_and_fill ( dest)  { 
106+                 Ok ( os_rng)  => { 
107+                     debug ! ( "EntropyRng: using OsRng" ) ; 
108+                     self . source  = Source :: Os ( os_rng) ; 
109+                     return  Ok ( ( ) ) ; 
110+                 } , 
111+                 Err ( err)  => {  reported_error = reported_error. or ( Some ( err) )  } , 
112+             } 
103113        } 
104114
105-         let  mut  switch_rng = None ; 
106-         match  self . rng  { 
107-             EntropySource :: None  => { 
108-                 let  os_rng_result = try_os_new ( dest) ; 
109-                 match  os_rng_result { 
110-                     Ok ( os_rng)  => { 
111-                         debug ! ( "EntropyRng: using OsRng" ) ; 
112-                         switch_rng = Some ( EntropySource :: Os ( os_rng) ) ; 
113-                     } 
114-                     Err ( os_rng_error)  => { 
115-                         warn ! ( "EntropyRng: OsRng failed [falling back to JitterRng]: {}" , 
116-                               os_rng_error) ; 
117-                         match  try_jitter_new ( dest)  { 
118-                             Ok ( jitter_rng)  => { 
119-                                 debug ! ( "EntropyRng: using JitterRng" ) ; 
120-                                 switch_rng = Some ( EntropySource :: Jitter ( jitter_rng) ) ; 
121-                             } 
122-                             Err ( _jitter_error)  => { 
123-                                 warn ! ( "EntropyRng: JitterRng failed: {}" , 
124-                                       _jitter_error) ; 
125-                                 return  Err ( os_rng_error) ; 
126-                             } 
127-                         } 
128-                     } 
129-                 } 
115+         if  let  Source :: Custom ( ref  mut  rng)  = self . source  { 
116+             match  rng. fill ( dest)  { 
117+                 Ok ( ( ) )  => return  Ok ( ( ) ) , 
118+                 Err ( err)  => { 
119+                     warn ! ( "EntropyRng: custom entropy source failed \  
120+                            [trying other entropy sources]: {}",  err) ; 
121+                     reported_error = Some ( err) ; 
122+                 } , 
130123            } 
131-             EntropySource :: Os ( ref  mut  rng)  => { 
132-                 let  os_rng_result = rng. try_fill_bytes ( dest) ; 
133-                 if  let  Err ( os_rng_error)  = os_rng_result { 
134-                     warn ! ( "EntropyRng: OsRng failed [falling back to JitterRng]: {}" , 
135-                           os_rng_error) ; 
136-                     match  try_jitter_new ( dest)  { 
137-                         Ok ( jitter_rng)  => { 
138-                             debug ! ( "EntropyRng: using JitterRng" ) ; 
139-                             switch_rng = Some ( EntropySource :: Jitter ( jitter_rng) ) ; 
140-                         } 
141-                         Err ( _jitter_error)  => { 
142-                             warn ! ( "EntropyRng: JitterRng failed: {}" , 
143-                                   _jitter_error) ; 
144-                             return  Err ( os_rng_error) ; 
145-                         } 
146-                     } 
147-                 } 
124+         }  else  if  Custom :: is_supported ( )  { 
125+             match  Custom :: new_and_fill ( dest)  { 
126+                 Ok ( custom)  => { 
127+                     debug ! ( "EntropyRng: using custom entropy source" ) ; 
128+                     self . source  = Source :: Custom ( custom) ; 
129+                     return  Ok ( ( ) ) ; 
130+                 } , 
131+                 Err ( err)  => {  reported_error = reported_error. or ( Some ( err) )  } , 
148132            } 
149-             EntropySource :: Jitter ( ref  mut  rng)  => { 
150-                 if  let  Ok ( os_rng)  = try_os_new ( dest)  { 
151-                     debug ! ( "EntropyRng: using OsRng" ) ; 
152-                     switch_rng = Some ( EntropySource :: Os ( os_rng) ) ; 
153-                 }  else  { 
154-                     return  rng. try_fill_bytes ( dest) ;  // use JitterRng 
155-                 } 
133+         } 
134+ 
135+         if  let  Source :: Jitter ( ref  mut  jitter_rng)  = self . source  { 
136+             match  jitter_rng. fill ( dest)  { 
137+                 Ok ( ( ) )  => return  Ok ( ( ) ) , 
138+                 Err ( err)  => { 
139+                     warn ! ( "EntropyRng: JitterRng failed: {}" ,  err) ; 
140+                     reported_error = Some ( err) ; 
141+                 } , 
142+             } 
143+         }  else  if  Jitter :: is_supported ( )  { 
144+             match  Jitter :: new_and_fill ( dest)  { 
145+                 Ok ( jitter_rng)  => { 
146+                     debug ! ( "EntropyRng: using JitterRng" ) ; 
147+                     self . source  = Source :: Jitter ( jitter_rng) ; 
148+                     return  Ok ( ( ) ) ; 
149+                 } , 
150+                 Err ( err)  => {  reported_error = reported_error. or ( Some ( err) )  } , 
156151            } 
157152        } 
158-         if  let  Some ( rng)  = switch_rng { 
159-             self . rng  = rng; 
153+ 
154+         if  let  Some ( err)  = reported_error { 
155+             Err ( Error :: with_cause ( ErrorKind :: Unavailable , 
156+                                   "All entropy sources failed" , 
157+                                   err) ) 
158+         }  else  { 
159+             Err ( Error :: new ( ErrorKind :: Unavailable , 
160+                            "No entropy sources available" ) ) 
160161        } 
161-         Ok ( ( ) ) 
162162    } 
163163} 
164164
165165impl  CryptoRng  for  EntropyRng  { } 
166166
167+ 
168+ 
169+ trait  EntropySource  { 
170+     fn  new_and_fill ( dest :  & mut  [ u8 ] )  -> Result < Self ,  Error > 
171+         where  Self :  Sized ; 
172+ 
173+     fn  fill ( & mut  self ,  dest :  & mut  [ u8 ] )  -> Result < ( ) ,  Error > ; 
174+ 
175+     fn  is_supported ( )  -> bool  {  true  } 
176+ } 
177+ 
178+ #[ allow( unused) ]  
179+ #[ derive( Clone ,  Debug ) ]  
180+ struct  NoSource ; 
181+ 
182+ #[ allow( unused) ]  
183+ impl  EntropySource  for  NoSource  { 
184+     fn  new_and_fill ( dest :  & mut  [ u8 ] )  -> Result < Self ,  Error >  { 
185+         Err ( Error :: new ( ErrorKind :: Unavailable ,  "Source not supported" ) ) 
186+     } 
187+ 
188+     fn  fill ( & mut  self ,  dest :  & mut  [ u8 ] )  -> Result < ( ) ,  Error >  { 
189+         unreachable ! ( ) 
190+     } 
191+ 
192+     fn  is_supported ( )  -> bool  {  false  } 
193+ } 
194+ 
195+ 
196+ #[ cfg( all( feature="std" ,  
197+           any( target_os = "linux" ,  target_os = "android" ,  
198+               target_os = "netbsd" ,  
199+               target_os = "dragonfly" ,  
200+               target_os = "haiku" ,  
201+               target_os = "emscripten" ,  
202+               target_os = "solaris" ,  
203+               target_os = "cloudabi" ,  
204+               target_os = "macos" ,  target_os = "ios" ,  
205+               target_os = "freebsd" ,  
206+               target_os = "openbsd" ,  target_os = "bitrig" ,  
207+               target_os = "redox" ,  
208+               target_os = "fuchsia" ,  
209+               windows,  
210+               all( target_arch = "wasm32" ,  feature = "stdweb" )  
211+ ) ) ) ] 
212+ #[ derive( Clone ,  Debug ) ]  
213+ pub  struct  Os ( rngs:: OsRng ) ; 
214+ 
215+ #[ cfg( all( feature="std" ,  
216+           any( target_os = "linux" ,  target_os = "android" ,  
217+               target_os = "netbsd" ,  
218+               target_os = "dragonfly" ,  
219+               target_os = "haiku" ,  
220+               target_os = "emscripten" ,  
221+               target_os = "solaris" ,  
222+               target_os = "cloudabi" ,  
223+               target_os = "macos" ,  target_os = "ios" ,  
224+               target_os = "freebsd" ,  
225+               target_os = "openbsd" ,  target_os = "bitrig" ,  
226+               target_os = "redox" ,  
227+               target_os = "fuchsia" ,  
228+               windows,  
229+               all( target_arch = "wasm32" ,  feature = "stdweb" )  
230+ ) ) ) ] 
231+ impl  EntropySource  for  Os  { 
232+     fn  new_and_fill ( dest :  & mut  [ u8 ] )  -> Result < Self ,  Error >  { 
233+         let  mut  rng = rngs:: OsRng :: new ( ) ?; 
234+         rng. try_fill_bytes ( dest) ?; 
235+         Ok ( Os ( rng) ) 
236+     } 
237+ 
238+     fn  fill ( & mut  self ,  dest :  & mut  [ u8 ] )  -> Result < ( ) ,  Error >  { 
239+         self . 0 . try_fill_bytes ( dest) 
240+     } 
241+ } 
242+ 
243+ #[ cfg( not( all( feature="std" ,  
244+               any( target_os = "linux" ,  target_os = "android" ,  
245+                   target_os = "netbsd" ,  
246+                   target_os = "dragonfly" ,  
247+                   target_os = "haiku" ,  
248+                   target_os = "emscripten" ,  
249+                   target_os = "solaris" ,  
250+                   target_os = "cloudabi" ,  
251+                   target_os = "macos" ,  target_os = "ios" ,  
252+                   target_os = "freebsd" ,  
253+                   target_os = "openbsd" ,  target_os = "bitrig" ,  
254+                   target_os = "redox" ,  
255+                   target_os = "fuchsia" ,  
256+                   windows,  
257+                   all( target_arch = "wasm32" ,  feature = "stdweb" )  
258+ ) ) ) ) ] 
259+ type  Os  = NoSource ; 
260+ 
261+ 
262+ type  Custom  = NoSource ; 
263+ 
264+ 
265+ #[ cfg( not( target_arch = "wasm32" ) ) ]  
266+ #[ derive( Clone ,  Debug ) ]  
267+ pub  struct  Jitter ( rngs:: JitterRng ) ; 
268+ 
269+ #[ cfg( not( target_arch = "wasm32" ) ) ]  
270+ impl  EntropySource  for  Jitter  { 
271+     fn  new_and_fill ( dest :  & mut  [ u8 ] )  -> Result < Self ,  Error >  { 
272+         let  mut  rng = rngs:: JitterRng :: new ( ) ?; 
273+         rng. try_fill_bytes ( dest) ?; 
274+         Ok ( Jitter ( rng) ) 
275+     } 
276+ 
277+     fn  fill ( & mut  self ,  dest :  & mut  [ u8 ] )  -> Result < ( ) ,  Error >  { 
278+         self . 0 . try_fill_bytes ( dest) 
279+     } 
280+ } 
281+ 
282+ #[ cfg( target_arch = "wasm32" ) ]  
283+ type  Jitter  = NoSource ; 
284+ 
285+ 
167286#[ cfg( test) ]  
168287mod  test { 
169288    use  super :: * ; 
0 commit comments