]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/random/randomdev.c
c73553994b5d0d97d8058d95e93c69a87924b4e0
[apple/xnu.git] / bsd / dev / random / randomdev.c
1 /*
2 * Copyright (c) 1999-2009 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
31
32 THIS FILE IS NEEDED TO PASS FIPS ACCEPTANCE FOR THE RANDOM NUMBER GENERATOR.
33 IF YOU ALTER IT IN ANY WAY, WE WILL NEED TO GO THOUGH FIPS ACCEPTANCE AGAIN,
34 AN OPERATION THAT IS VERY EXPENSIVE AND TIME CONSUMING. IN OTHER WORDS,
35 DON'T MESS WITH THIS FILE.
36
37 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/errno.h>
44 #include <sys/ioctl.h>
45 #include <sys/conf.h>
46 #include <sys/fcntl.h>
47 #include <string.h>
48 #include <miscfs/devfs/devfs.h>
49 #include <kern/lock.h>
50 #include <kern/clock.h>
51 #include <sys/time.h>
52 #include <sys/malloc.h>
53 #include <sys/uio_internal.h>
54
55 #include <dev/random/randomdev.h>
56 #include <dev/random/YarrowCoreLib/include/yarrow.h>
57
58 #include <libkern/OSByteOrder.h>
59 #include <libkern/OSAtomic.h>
60
61 #include <mach/mach_time.h>
62 #include <machine/machine_routines.h>
63
64 #include "fips_sha1.h"
65
66 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */
67
68 d_ioctl_t random_ioctl;
69
70 /* To generate the seed for the RNG */
71 extern uint64_t early_random();
72
73 /*
74 * A struct describing which functions will get invoked for certain
75 * actions.
76 */
77 static struct cdevsw random_cdevsw =
78 {
79 random_open, /* open */
80 random_close, /* close */
81 random_read, /* read */
82 random_write, /* write */
83 random_ioctl, /* ioctl */
84 (stop_fcn_t *)nulldev, /* stop */
85 (reset_fcn_t *)nulldev, /* reset */
86 NULL, /* tty's */
87 eno_select, /* select */
88 eno_mmap, /* mmap */
89 eno_strat, /* strategy */
90 eno_getc, /* getc */
91 eno_putc, /* putc */
92 0 /* type */
93 };
94
95
96 /*
97 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
98
99 ANY CODE PROTECTED UNDER "#ifdef __arm__" IS SERIOUSLY SUPPOSED TO BE THERE!
100 IF YOU REMOVE ARM CODE, RANDOM WILL NOT MEAN ANYTHING FOR iPHONES ALL OVER.
101 PLEASE DON'T TOUCH __arm__ CODE IN THIS FILE!
102
103 WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
104 */
105
106
107 /* Used to detect whether we've already been initialized */
108 static UInt8 gRandomInstalled = 0;
109 static PrngRef gPrngRef;
110 static int gRandomError = 1;
111 static lck_grp_t *gYarrowGrp;
112 static lck_attr_t *gYarrowAttr;
113 static lck_grp_attr_t *gYarrowGrpAttr;
114 static lck_mtx_t *gYarrowMutex = 0;
115 static UInt8 gYarrowInitializationLock = 0;
116
117 #define RESEED_TICKS 50 /* how long a reseed operation can take */
118
119
120 typedef u_int8_t BlockWord;
121 enum {kBSize = 20};
122 typedef BlockWord Block[kBSize];
123 enum {kBlockSize = sizeof(Block)};
124
125 /* define prototypes to keep the compiler happy... */
126
127 void add_blocks(Block a, Block b, BlockWord carry);
128 void fips_initialize(void);
129 void random_block(Block b, int addOptional);
130 u_int32_t CalculateCRC(u_int8_t* buffer, size_t length);
131
132 /*
133 * Get 120 bits from yarrow
134 */
135
136 /*
137 * add block b to block a
138 */
139 void
140 add_blocks(Block a, Block b, BlockWord carry)
141 {
142 int i = kBlockSize - 1;
143 while (i >= 0)
144 {
145 u_int32_t c = (u_int32_t)carry +
146 (u_int32_t)a[i] +
147 (u_int32_t)b[i];
148 a[i] = c & 0xff;
149 carry = c >> 8;
150 i -= 1;
151 }
152 }
153
154
155
156 static char zeros[(512 - kBSize * 8) / 8];
157 static Block g_xkey;
158 static Block g_random_data;
159 static int g_bytes_used;
160 static unsigned char g_SelfTestInitialized = 0;
161 static u_int32_t gLastBlockChecksum;
162
163 static const u_int32_t g_crc_table[] =
164 {
165 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
166 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
167 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
168 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
169 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
170 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
171 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
172 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
173 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
174 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
175 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
176 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
177 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
178 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
179 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
180 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
181 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
182 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
183 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
184 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
185 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
186 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
187 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
188 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
189 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
190 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
191 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
192 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
193 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
194 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
195 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
196 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
197 };
198
199 /*
200 * Setup for fips compliance
201 */
202
203 /*
204 * calculate a crc-32 checksum
205 */
206 u_int32_t CalculateCRC(u_int8_t* buffer, size_t length)
207 {
208 u_int32_t crc = 0;
209
210 size_t i;
211 for (i = 0; i < length; ++i)
212 {
213 u_int32_t temp = (crc ^ ((u_int32_t) buffer[i])) & 0xFF;
214 crc = (crc >> 8) ^ g_crc_table[temp];
215 }
216
217 return crc;
218 }
219
220 /*
221 * get a random block of data per fips 186-2
222 */
223 void
224 random_block(Block b, int addOptional)
225 {
226 SHA1_CTX sha1_ctx;
227
228 int repeatCount = 0;
229 do
230 {
231 // do one iteration
232
233 if (addOptional)
234 {
235 // create an xSeed to add.
236 Block xSeed;
237 prngOutput (gPrngRef, (BYTE*) &xSeed, sizeof (xSeed));
238
239 // add the seed to the previous value of g_xkey
240 add_blocks (g_xkey, xSeed, 0);
241 }
242
243 // initialize the value of H
244 FIPS_SHA1Init(&sha1_ctx);
245
246 // to stay compatible with the FIPS specification, we need to flip the bytes in
247 // g_xkey to little endian byte order. In our case, this makes exactly no difference
248 // (random is random), but we need to do it anyway to keep FIPS happy
249
250 // compute "G"
251 FIPS_SHA1Update(&sha1_ctx, g_xkey, kBlockSize);
252
253 // add zeros to fill the internal SHA-1 buffer
254 FIPS_SHA1Update (&sha1_ctx, (const u_int8_t *)zeros, sizeof (zeros));
255
256 // we have to do a byte order correction here because the sha1 math is being done internally
257 // as u_int32_t, not a stream of bytes. Since we maintain our data as a byte stream, we need
258 // to convert
259
260 u_int32_t* finger = (u_int32_t*) b;
261
262 unsigned j;
263 for (j = 0; j < kBlockSize / sizeof (u_int32_t); ++j)
264 {
265 *finger++ = OSSwapHostToBigInt32(sha1_ctx.h.b32[j]);
266 }
267
268 // calculate the CRC-32 of the block
269 u_int32_t new_crc = CalculateCRC(sha1_ctx.h.b8, sizeof (Block));
270
271 // make sure we don't repeat
272 int cmp = new_crc == gLastBlockChecksum;
273 gLastBlockChecksum = new_crc;
274 if (!g_SelfTestInitialized)
275 {
276 g_SelfTestInitialized = 1;
277 return;
278 }
279 else if (!cmp)
280 {
281 return;
282 }
283
284 repeatCount += 1;
285
286 // fix up the next value of g_xkey
287 add_blocks (g_xkey, b, 1);
288 } while (repeatCount < 2);
289
290 /*
291 * If we got here, three sucessive checksums of the random number
292 * generator have been the same. Since the odds of this happening are
293 * 1 in 18,446,744,073,709,551,616, (1 in 18 quintillion) one of the following has
294 * most likely happened:
295 *
296 * 1: There is a significant bug in this code.
297 * 2: There has been a massive system failure.
298 * 3: The universe has ceased to exist.
299 *
300 * There is no good way to recover from any of these cases. We
301 * therefore panic.
302 */
303
304 panic("FIPS random self-test failed.");
305 }
306
307 /*
308 *Initialize ONLY the Yarrow generator.
309 */
310 void
311 PreliminarySetup(void)
312 {
313 prng_error_status perr;
314
315 /* Multiple threads can enter this as a result of an earlier
316 * check of gYarrowMutex. We make sure that only one of them
317 * can enter at a time. If one of them enters and discovers
318 * that gYarrowMutex is no longer NULL, we know that another
319 * thread has initialized the Yarrow state and we can exit.
320 */
321
322 /* The first thread that enters this function will find
323 * gYarrowInitializationLock set to 0. It will atomically
324 * set the value to 1 and, seeing that it was zero, drop
325 * out of the loop. Other threads will see that the value is
326 * 1 and continue to loop until we are initialized.
327 */
328
329 while (OSTestAndSet(0, &gYarrowInitializationLock)); /* serialize access to this function */
330
331 if (gYarrowMutex) {
332 /* we've already been initialized, clear and get out */
333 goto function_exit;
334 }
335
336 /* create a Yarrow object */
337 perr = prngInitialize(&gPrngRef);
338 if (perr != 0) {
339 printf ("Couldn't initialize Yarrow, /dev/random will not work.\n");
340 return;
341 }
342
343 /* clear the error flag, reads and write should then work */
344 gRandomError = 0;
345
346 uint64_t tt;
347 char buffer [16];
348
349 /* get a little non-deterministic data as an initial seed. */
350 /* On OSX, securityd will add much more entropy as soon as it */
351 /* comes up. On iOS, entropy is added with each system interrupt. */
352 tt = early_random();
353
354 perr = prngInput(gPrngRef, (BYTE*) &tt, sizeof (tt), SYSTEM_SOURCE, 8);
355 if (perr != 0) {
356 /* an error, complain */
357 printf ("Couldn't seed Yarrow.\n");
358 goto function_exit;
359 }
360
361 /* turn the data around */
362 perr = prngOutput(gPrngRef, (BYTE*) buffer, sizeof (buffer));
363
364 /* and scramble it some more */
365 perr = prngForceReseed(gPrngRef, RESEED_TICKS);
366
367 /* make a mutex to control access */
368 gYarrowGrpAttr = lck_grp_attr_alloc_init();
369 gYarrowGrp = lck_grp_alloc_init("random", gYarrowGrpAttr);
370 gYarrowAttr = lck_attr_alloc_init();
371 gYarrowMutex = lck_mtx_alloc_init(gYarrowGrp, gYarrowAttr);
372
373 fips_initialize ();
374
375 function_exit:
376 /* allow other threads to figure out whether or not we have been initialized. */
377 gYarrowInitializationLock = 0;
378 }
379
380 const Block kKnownAnswer = {0x92, 0xb4, 0x04, 0xe5, 0x56, 0x58, 0x8c, 0xed, 0x6c, 0x1a, 0xcd, 0x4e, 0xbf, 0x05, 0x3f, 0x68, 0x09, 0xf7, 0x3a, 0x93};
381
382 void
383 fips_initialize(void)
384 {
385 /* So that we can do the self test, set the seed to zero */
386 memset(&g_xkey, 0, sizeof(g_xkey));
387
388 /* other initializations */
389 memset (zeros, 0, sizeof (zeros));
390 g_bytes_used = 0;
391 random_block(g_random_data, FALSE);
392
393 // check here to see if we got the initial data we were expecting
394 if (memcmp(kKnownAnswer, g_random_data, kBlockSize) != 0)
395 {
396 panic("FIPS random self test failed");
397 }
398
399 // now do the random block again to make sure that userland doesn't get predicatable data
400 random_block(g_random_data, TRUE);
401 }
402
403 /*
404 * Called to initialize our device,
405 * and to register ourselves with devfs
406 */
407 void
408 random_init(void)
409 {
410 int ret;
411
412 if (OSTestAndSet(0, &gRandomInstalled)) {
413 /* do this atomically so that it works correctly with
414 multiple threads */
415 return;
416 }
417
418 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw);
419 if (ret < 0) {
420 printf("random_init: failed to allocate a major number!\n");
421 gRandomInstalled = 0;
422 return;
423 }
424
425 devfs_make_node(makedev (ret, 0), DEVFS_CHAR,
426 UID_ROOT, GID_WHEEL, 0666, "random", 0);
427
428 /*
429 * also make urandom
430 * (which is exactly the same thing in our context)
431 */
432 devfs_make_node(makedev (ret, 1), DEVFS_CHAR,
433 UID_ROOT, GID_WHEEL, 0666, "urandom", 0);
434
435 /* setup yarrow and the mutex if needed*/
436 PreliminarySetup();
437 }
438
439 int
440 random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data,
441 __unused int flag, __unused struct proc *p )
442 {
443 switch (cmd) {
444 case FIONBIO:
445 case FIOASYNC:
446 break;
447 default:
448 return ENODEV;
449 }
450
451 return (0);
452 }
453
454 /*
455 * Open the device. Make sure init happened, and make sure the caller is
456 * authorized.
457 */
458
459 int
460 random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p)
461 {
462 if (gRandomError != 0) {
463 /* forget it, yarrow didn't come up */
464 return (ENOTSUP);
465 }
466
467 /*
468 * if we are being opened for write,
469 * make sure that we have privledges do so
470 */
471 if (flags & FWRITE) {
472 if (securelevel >= 2)
473 return (EPERM);
474 #ifndef __APPLE__
475 if ((securelevel >= 1) && proc_suser(p))
476 return (EPERM);
477 #endif /* !__APPLE__ */
478 }
479
480 return (0);
481 }
482
483
484 /*
485 * close the device.
486 */
487
488 int
489 random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p)
490 {
491 return (0);
492 }
493
494
495 /*
496 * Get entropic data from the Security Server, and use it to reseed the
497 * prng.
498 */
499 int
500 random_write (__unused dev_t dev, struct uio *uio, __unused int ioflag)
501 {
502 int retCode = 0;
503 char rdBuffer[256];
504
505 if (gRandomError != 0) {
506 return (ENOTSUP);
507 }
508
509 /* get control of the Yarrow instance, Yarrow is NOT thread safe */
510 lck_mtx_lock(gYarrowMutex);
511
512 /* Security server is sending us entropy */
513
514 while (uio_resid(uio) > 0 && retCode == 0) {
515 /* get the user's data */
516 int bytesToInput = min(uio_resid(uio), sizeof (rdBuffer));
517 retCode = uiomove(rdBuffer, bytesToInput, uio);
518 if (retCode != 0)
519 goto /*ugh*/ error_exit;
520
521 /* put it in Yarrow */
522 if (prngInput(gPrngRef, (BYTE*) rdBuffer,
523 bytesToInput, SYSTEM_SOURCE,
524 bytesToInput * 8) != 0) {
525 retCode = EIO;
526 goto error_exit;
527 }
528 }
529
530 /* force a reseed */
531 if (prngForceReseed(gPrngRef, RESEED_TICKS) != 0) {
532 retCode = EIO;
533 goto error_exit;
534 }
535
536 /* retCode should be 0 at this point */
537
538 error_exit: /* do this to make sure the mutex unlocks. */
539 lck_mtx_unlock(gYarrowMutex);
540 return (retCode);
541 }
542
543
544 /* export good random numbers to the rest of the kernel */
545 void
546 read_random(void* buffer, u_int numbytes)
547 {
548 if (gYarrowMutex == 0) { /* are we initialized? */
549 PreliminarySetup ();
550 }
551
552 lck_mtx_lock(gYarrowMutex);
553
554
555 int bytes_read = 0;
556
557 int bytes_remaining = numbytes;
558 while (bytes_remaining > 0) {
559 int bytes_to_read = min(bytes_remaining, kBlockSize - g_bytes_used);
560 if (bytes_to_read == 0)
561 {
562 random_block(g_random_data, TRUE);
563 g_bytes_used = 0;
564 bytes_to_read = min(bytes_remaining, kBlockSize);
565 }
566
567 memmove ((u_int8_t*) buffer + bytes_read, ((u_int8_t*)g_random_data)+ g_bytes_used, bytes_to_read);
568 g_bytes_used += bytes_to_read;
569 bytes_read += bytes_to_read;
570 bytes_remaining -= bytes_to_read;
571 }
572
573 lck_mtx_unlock(gYarrowMutex);
574 }
575
576 /*
577 * return data to the caller. Results unpredictable.
578 */
579 int
580 random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag)
581 {
582 int retCode = 0;
583
584 if (gRandomError != 0)
585 return (ENOTSUP);
586
587 char buffer[64];
588
589 user_ssize_t bytes_remaining = uio_resid(uio);
590 while (bytes_remaining > 0 && retCode == 0) {
591 user_ssize_t bytesToRead = min(sizeof(buffer), bytes_remaining);
592 read_random(buffer, bytesToRead);
593 retCode = uiomove(buffer, bytesToRead, uio);
594
595 if (retCode != 0)
596 goto error_exit;
597
598 bytes_remaining = uio_resid(uio);
599 }
600
601 retCode = 0;
602
603 error_exit:
604 return retCode;
605 }
606 /*
607 * Return an u_int32_t pseudo-random number.
608 */
609 u_int32_t
610 RandomULong(void)
611 {
612 u_int32_t buf;
613 read_random(&buf, sizeof (buf));
614 return (buf);
615 }
616