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