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 617