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