@@ -154,40 +154,65 @@ mod imp {
154
154
}
155
155
}
156
156
157
- #[ cfg( target_os = "macos " ) ]
157
+ #[ cfg( target_vendor = "apple " ) ]
158
158
mod imp {
159
- use crate :: fs:: File ;
160
- use crate :: io:: Read ;
161
- use crate :: sys:: os:: errno;
162
- use crate :: sys:: weak:: weak;
159
+ use crate :: io;
163
160
use libc:: { c_int, c_void, size_t} ;
164
161
165
- fn getentropy_fill_bytes ( v : & mut [ u8 ] ) -> bool {
166
- weak ! ( fn getentropy( * mut c_void, size_t) -> c_int) ;
167
-
168
- getentropy
169
- . get ( )
170
- . map ( |f| {
171
- // getentropy(2) permits a maximum buffer size of 256 bytes
172
- for s in v. chunks_mut ( 256 ) {
173
- let ret = unsafe { f ( s. as_mut_ptr ( ) as * mut c_void , s. len ( ) ) } ;
174
- if ret == -1 {
175
- panic ! ( "unexpected getentropy error: {}" , errno( ) ) ;
176
- }
177
- }
178
- true
179
- } )
180
- . unwrap_or ( false )
162
+ #[ inline( always) ]
163
+ fn random_failure ( ) -> ! {
164
+ panic ! ( "unexpected random generation error: {}" , io:: Error :: last_os_error( ) ) ;
181
165
}
182
166
183
- pub fn fill_bytes ( v : & mut [ u8 ] ) {
184
- if getentropy_fill_bytes ( v) {
185
- return ;
167
+ #[ cfg( target_os = "macos" ) ]
168
+ fn getentropy_fill_bytes ( v : & mut [ u8 ] ) {
169
+ extern "C" {
170
+ fn getentropy ( bytes : * mut c_void , count : size_t ) -> c_int ;
186
171
}
187
172
188
- // for older macos which doesn't support getentropy
189
- let mut file = File :: open ( "/dev/urandom" ) . expect ( "failed to open /dev/urandom" ) ;
190
- file. read_exact ( v) . expect ( "failed to read /dev/urandom" )
173
+ // getentropy(2) permits a maximum buffer size of 256 bytes
174
+ for s in v. chunks_mut ( 256 ) {
175
+ let ret = unsafe { getentropy ( s. as_mut_ptr ( ) . cast ( ) , s. len ( ) ) } ;
176
+ if ret == -1 {
177
+ random_failure ( )
178
+ }
179
+ }
180
+ }
181
+
182
+ #[ cfg( not( target_os = "macos" ) ) ]
183
+ fn ccrandom_fill_bytes ( v : & mut [ u8 ] ) {
184
+ extern "C" {
185
+ fn CCRandomGenerateBytes ( bytes : * mut c_void , count : size_t ) -> c_int ;
186
+ }
187
+
188
+ let ret = unsafe { CCRandomGenerateBytes ( v. as_mut_ptr ( ) . cast ( ) , v. len ( ) ) } ;
189
+ if ret == -1 {
190
+ random_failure ( )
191
+ }
192
+ }
193
+
194
+ pub fn fill_bytes ( v : & mut [ u8 ] ) {
195
+ // All supported versions of macOS (10.12+) support getentropy.
196
+ //
197
+ // `getentropy` is measurably faster then the other alternatives, so its preferred
198
+ // when usable.
199
+ #[ cfg( target_os = "macos" ) ]
200
+ getentropy_fill_bytes ( v) ;
201
+
202
+ // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
203
+ // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
204
+ // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
205
+ // its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
206
+ // so we only use it on non-Mac OSes where the better entrypoints are blocked.
207
+ //
208
+ // `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
209
+ // via `libSystem` (libc) while the other needs to link to `Security.framework`.
210
+ //
211
+ // Note that while `getentropy` has a available attribute in the macOS headers, the lack
212
+ // of a header in the iOS (and others) SDK means that its can cause app store rejections.
213
+ // Just use `CCRandomGenerateBytes` instead.
214
+ #[ cfg( not( target_os = "macos" ) ) ]
215
+ ccrandom_fill_bytes ( v) ;
191
216
}
192
217
}
193
218
@@ -206,36 +231,6 @@ mod imp {
206
231
}
207
232
}
208
233
209
- // On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
210
- // `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
211
- // from `/dev/random` and which runs on its own thread accessed via GCD.
212
- // This seems needlessly heavyweight for the purposes of generating two u64s
213
- // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
214
- // only used on iOS where direct access to `/dev/urandom` is blocked by the
215
- // sandbox.
216
- #[ cfg( any( target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
217
- mod imp {
218
- use crate :: io;
219
- use crate :: ptr;
220
- use libc:: { c_int, size_t} ;
221
-
222
- enum SecRandom { }
223
-
224
- #[ allow( non_upper_case_globals) ]
225
- const kSecRandomDefault: * const SecRandom = ptr:: null ( ) ;
226
-
227
- extern "C" {
228
- fn SecRandomCopyBytes ( rnd : * const SecRandom , count : size_t , bytes : * mut u8 ) -> c_int ;
229
- }
230
-
231
- pub fn fill_bytes ( v : & mut [ u8 ] ) {
232
- let ret = unsafe { SecRandomCopyBytes ( kSecRandomDefault, v. len ( ) , v. as_mut_ptr ( ) ) } ;
233
- if ret == -1 {
234
- panic ! ( "couldn't generate random bytes: {}" , io:: Error :: last_os_error( ) ) ;
235
- }
236
- }
237
- }
238
-
239
234
#[ cfg( target_os = "netbsd" ) ]
240
235
mod imp {
241
236
use crate :: ptr;
0 commit comments