unix_rand.c (19856B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <signal.h> 8 #include <unistd.h> 9 #include <limits.h> 10 #include <errno.h> 11 #include <stdlib.h> 12 #include <sys/time.h> 13 #include <sys/wait.h> 14 #include <sys/stat.h> 15 #include <sys/types.h> 16 #include <dirent.h> 17 #include "secrng.h" 18 #include "secerr.h" 19 #include "prerror.h" 20 #include "prthread.h" 21 #include "prprf.h" 22 #include "prenv.h" 23 24 size_t RNG_FileUpdate(const char *fileName, size_t limit); 25 26 /* 27 * When copying data to the buffer we want the least signicant bytes 28 * from the input since those bits are changing the fastest. The address 29 * of least significant byte depends upon whether we are running on 30 * a big-endian or little-endian machine. 31 * 32 * Does this mean the least signicant bytes are the most significant 33 * to us? :-) 34 */ 35 36 static size_t 37 CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen) 38 { 39 union endianness { 40 PRInt32 i; 41 char c[4]; 42 } u; 43 44 if (srclen <= dstlen) { 45 memcpy(dst, src, srclen); 46 return srclen; 47 } 48 u.i = 0x01020304; 49 if (u.c[0] == 0x01) { 50 /* big-endian case */ 51 memcpy(dst, (char *)src + (srclen - dstlen), dstlen); 52 } else { 53 /* little-endian case */ 54 memcpy(dst, src, dstlen); 55 } 56 return dstlen; 57 } 58 59 #ifdef SOLARIS 60 61 #include <kstat.h> 62 63 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */ 64 65 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time. 66 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed 67 * by the number of bytes successfully buffered. 68 */ 69 static SECStatus 70 BufferEntropy(char *inbuf, PRUint32 inlen, 71 char *entropy_buf, PRUint32 *entropy_buffered, 72 PRUint32 *total_fed) 73 { 74 PRUint32 tocopy = 0; 75 PRUint32 avail = 0; 76 SECStatus rv = SECSuccess; 77 78 while (inlen) { 79 avail = entropy_buf_len - *entropy_buffered; 80 if (!avail) { 81 /* Buffer is full, time to feed it to the RNG. */ 82 rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len); 83 if (SECSuccess != rv) { 84 break; 85 } 86 *entropy_buffered = 0; 87 avail = entropy_buf_len; 88 } 89 tocopy = PR_MIN(avail, inlen); 90 memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy); 91 *entropy_buffered += tocopy; 92 inlen -= tocopy; 93 inbuf += tocopy; 94 *total_fed += tocopy; 95 } 96 return rv; 97 } 98 99 /* Feed kernel statistics structures and ks_data field to the RNG. 100 * Returns status as well as the number of bytes successfully fed to the RNG. 101 */ 102 static SECStatus 103 RNG_kstat(PRUint32 *fed) 104 { 105 kstat_ctl_t *kc = NULL; 106 kstat_t *ksp = NULL; 107 PRUint32 entropy_buffered = 0; 108 char *entropy_buf = NULL; 109 SECStatus rv = SECSuccess; 110 111 PORT_Assert(fed); 112 if (!fed) { 113 return SECFailure; 114 } 115 *fed = 0; 116 117 kc = kstat_open(); 118 PORT_Assert(kc); 119 if (!kc) { 120 return SECFailure; 121 } 122 entropy_buf = (char *)PORT_Alloc(entropy_buf_len); 123 PORT_Assert(entropy_buf); 124 if (entropy_buf) { 125 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 126 if (-1 == kstat_read(kc, ksp, NULL)) { 127 /* missing data from a single kstat shouldn't be fatal */ 128 continue; 129 } 130 rv = BufferEntropy((char *)ksp, sizeof(kstat_t), 131 entropy_buf, &entropy_buffered, 132 fed); 133 if (SECSuccess != rv) { 134 break; 135 } 136 137 if (ksp->ks_data && ksp->ks_data_size > 0 && ksp->ks_ndata > 0) { 138 rv = BufferEntropy((char *)ksp->ks_data, ksp->ks_data_size, 139 entropy_buf, &entropy_buffered, 140 fed); 141 if (SECSuccess != rv) { 142 break; 143 } 144 } 145 } 146 if (SECSuccess == rv && entropy_buffered) { 147 /* Buffer is not empty, time to feed it to the RNG */ 148 rv = RNG_RandomUpdate(entropy_buf, entropy_buffered); 149 } 150 PORT_Free(entropy_buf); 151 } else { 152 rv = SECFailure; 153 } 154 if (kstat_close(kc)) { 155 PORT_Assert(0); 156 rv = SECFailure; 157 } 158 return rv; 159 } 160 161 #endif 162 163 #if defined(FREEBSD) || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) || defined(NTO) || defined(__riscos__) || defined(__GNU__) || defined(__FreeBSD_kernel__) || defined(__NetBSD_kernel__) 164 #include <sys/times.h> 165 166 static size_t 167 GetHighResClock(void *buf, size_t maxbytes) 168 { 169 int ticks; 170 struct tms buffer; 171 172 ticks = times(&buffer); 173 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); 174 } 175 176 static void 177 GiveSystemInfo(void) 178 { 179 long si; 180 181 /* 182 * Is this really necessary? Why not use rand48 or something? 183 */ 184 si = sysconf(_SC_CHILD_MAX); 185 RNG_RandomUpdate(&si, sizeof(si)); 186 187 si = sysconf(_SC_STREAM_MAX); 188 RNG_RandomUpdate(&si, sizeof(si)); 189 190 si = sysconf(_SC_OPEN_MAX); 191 RNG_RandomUpdate(&si, sizeof(si)); 192 } 193 #endif 194 195 #if defined(__sun) 196 #if defined(__svr4) || defined(SVR4) 197 #include <sys/systeminfo.h> 198 199 static void 200 GiveSystemInfo(void) 201 { 202 int rv; 203 char buf[2000]; 204 205 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 206 if (rv > 0) { 207 RNG_RandomUpdate(buf, rv); 208 } 209 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 210 if (rv > 0) { 211 RNG_RandomUpdate(buf, rv); 212 } 213 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 214 if (rv > 0) { 215 RNG_RandomUpdate(buf, rv); 216 } 217 } 218 219 static size_t 220 GetHighResClock(void *buf, size_t maxbytes) 221 { 222 hrtime_t t; 223 t = gethrtime(); 224 if (t) { 225 return CopyLowBits(buf, maxbytes, &t, sizeof(t)); 226 } 227 return 0; 228 } 229 #else /* SunOS (Sun, but not SVR4) */ 230 231 extern long sysconf(int name); 232 233 static size_t 234 GetHighResClock(void *buf, size_t maxbytes) 235 { 236 return 0; 237 } 238 239 static void 240 GiveSystemInfo(void) 241 { 242 long si; 243 244 /* This is not very good */ 245 si = sysconf(_SC_CHILD_MAX); 246 RNG_RandomUpdate(&si, sizeof(si)); 247 } 248 #endif 249 #endif /* Sun */ 250 251 #if defined(__hpux) 252 #include <sys/unistd.h> 253 254 #if defined(__ia64) 255 #include <ia64/sys/inline.h> 256 257 static size_t 258 GetHighResClock(void *buf, size_t maxbytes) 259 { 260 PRUint64 t; 261 262 t = _Asm_mov_from_ar(_AREG44); 263 return CopyLowBits(buf, maxbytes, &t, sizeof(t)); 264 } 265 #else 266 static size_t 267 GetHighResClock(void *buf, size_t maxbytes) 268 { 269 extern int ret_cr16(); 270 int cr16val; 271 272 cr16val = ret_cr16(); 273 return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)); 274 } 275 #endif 276 277 static void 278 GiveSystemInfo(void) 279 { 280 long si; 281 282 /* This is not very good */ 283 si = sysconf(_AES_OS_VERSION); 284 RNG_RandomUpdate(&si, sizeof(si)); 285 si = sysconf(_SC_CPU_VERSION); 286 RNG_RandomUpdate(&si, sizeof(si)); 287 } 288 #endif /* HPUX */ 289 290 #if defined(_IBMR2) 291 static size_t 292 GetHighResClock(void *buf, size_t maxbytes) 293 { 294 return 0; 295 } 296 297 static void 298 GiveSystemInfo(void) 299 { 300 /* XXX haven't found any yet! */ 301 } 302 #endif /* IBM R2 */ 303 304 #if defined(LINUX) 305 #include <sys/sysinfo.h> 306 307 static size_t 308 GetHighResClock(void *buf, size_t maxbytes) 309 { 310 return 0; 311 } 312 313 static void 314 GiveSystemInfo(void) 315 { 316 #ifndef NO_SYSINFO 317 struct sysinfo si; 318 if (sysinfo(&si) == 0) { 319 RNG_RandomUpdate(&si, sizeof(si)); 320 } 321 #endif 322 } 323 #endif /* LINUX */ 324 325 #if defined(NCR) 326 327 #include <sys/utsname.h> 328 #include <sys/systeminfo.h> 329 330 static size_t 331 GetHighResClock(void *buf, size_t maxbytes) 332 { 333 return 0; 334 } 335 336 static void 337 GiveSystemInfo(void) 338 { 339 int rv; 340 char buf[2000]; 341 342 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 343 if (rv > 0) { 344 RNG_RandomUpdate(buf, rv); 345 } 346 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 347 if (rv > 0) { 348 RNG_RandomUpdate(buf, rv); 349 } 350 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 351 if (rv > 0) { 352 RNG_RandomUpdate(buf, rv); 353 } 354 } 355 356 #endif /* NCR */ 357 358 #if defined(sgi) 359 #include <fcntl.h> 360 #undef PRIVATE 361 #include <sys/mman.h> 362 #include <sys/syssgi.h> 363 #include <sys/immu.h> 364 #include <sys/systeminfo.h> 365 #include <sys/utsname.h> 366 #include <wait.h> 367 368 static void 369 GiveSystemInfo(void) 370 { 371 int rv; 372 char buf[4096]; 373 374 rv = syssgi(SGI_SYSID, &buf[0]); 375 if (rv > 0) { 376 RNG_RandomUpdate(buf, MAXSYSIDSIZE); 377 } 378 #ifdef SGI_RDUBLK 379 rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf)); 380 if (rv > 0) { 381 RNG_RandomUpdate(buf, sizeof(buf)); 382 } 383 #endif /* SGI_RDUBLK */ 384 rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf)); 385 if (rv > 0) { 386 RNG_RandomUpdate(buf, sizeof(buf)); 387 } 388 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 389 if (rv > 0) { 390 RNG_RandomUpdate(buf, rv); 391 } 392 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 393 if (rv > 0) { 394 RNG_RandomUpdate(buf, rv); 395 } 396 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 397 if (rv > 0) { 398 RNG_RandomUpdate(buf, rv); 399 } 400 } 401 402 static size_t 403 GetHighResClock(void *buf, size_t maxbuf) 404 { 405 unsigned phys_addr, raddr, cycleval; 406 static volatile unsigned *iotimer_addr = NULL; 407 static int tries = 0; 408 static int cntr_size; 409 int mfd; 410 long s0[2]; 411 struct timeval tv; 412 413 #ifndef SGI_CYCLECNTR_SIZE 414 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ 415 #endif 416 417 if (iotimer_addr == NULL) { 418 if (tries++ > 1) { 419 /* Don't keep trying if it didn't work */ 420 return 0; 421 } 422 423 /* 424 ** For SGI machines we can use the cycle counter, if it has one, 425 ** to generate some truly random numbers 426 */ 427 phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); 428 if (phys_addr) { 429 int pgsz = getpagesize(); 430 int pgoffmask = pgsz - 1; 431 432 raddr = phys_addr & ~pgoffmask; 433 mfd = open("/dev/mmem", O_RDONLY); 434 if (mfd < 0) { 435 return 0; 436 } 437 iotimer_addr = (unsigned *) 438 mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); 439 if (iotimer_addr == (void *)-1) { 440 close(mfd); 441 iotimer_addr = NULL; 442 return 0; 443 } 444 iotimer_addr = (unsigned *)((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); 445 /* 446 * The file 'mfd' is purposefully not closed. 447 */ 448 cntr_size = syssgi(SGI_CYCLECNTR_SIZE); 449 if (cntr_size < 0) { 450 struct utsname utsinfo; 451 452 /* 453 * We must be executing on a 6.0 or earlier system, since the 454 * SGI_CYCLECNTR_SIZE call is not supported. 455 * 456 * The only pre-6.1 platforms with 64-bit counters are 457 * IP19 and IP21 (Challenge, PowerChallenge, Onyx). 458 */ 459 uname(&utsinfo); 460 if (!strncmp(utsinfo.machine, "IP19", 4) || 461 !strncmp(utsinfo.machine, "IP21", 4)) 462 cntr_size = 64; 463 else 464 cntr_size = 32; 465 } 466 cntr_size /= 8; /* Convert from bits to bytes */ 467 } 468 } 469 470 s0[0] = *iotimer_addr; 471 if (cntr_size > 4) 472 s0[1] = *(iotimer_addr + 1); 473 memcpy(buf, (char *)&s0[0], cntr_size); 474 return CopyLowBits(buf, maxbuf, &s0, cntr_size); 475 } 476 #endif 477 478 #if defined(sony) 479 #include <sys/systeminfo.h> 480 481 static size_t 482 GetHighResClock(void *buf, size_t maxbytes) 483 { 484 return 0; 485 } 486 487 static void 488 GiveSystemInfo(void) 489 { 490 int rv; 491 char buf[2000]; 492 493 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 494 if (rv > 0) { 495 RNG_RandomUpdate(buf, rv); 496 } 497 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 498 if (rv > 0) { 499 RNG_RandomUpdate(buf, rv); 500 } 501 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 502 if (rv > 0) { 503 RNG_RandomUpdate(buf, rv); 504 } 505 } 506 #endif /* sony */ 507 508 #if defined(sinix) 509 #include <sys/systeminfo.h> 510 #include <sys/times.h> 511 512 int gettimeofday(struct timeval *, struct timezone *); 513 int gethostname(char *, int); 514 515 static size_t 516 GetHighResClock(void *buf, size_t maxbytes) 517 { 518 int ticks; 519 struct tms buffer; 520 521 ticks = times(&buffer); 522 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); 523 } 524 525 static void 526 GiveSystemInfo(void) 527 { 528 int rv; 529 char buf[2000]; 530 531 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 532 if (rv > 0) { 533 RNG_RandomUpdate(buf, rv); 534 } 535 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 536 if (rv > 0) { 537 RNG_RandomUpdate(buf, rv); 538 } 539 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 540 if (rv > 0) { 541 RNG_RandomUpdate(buf, rv); 542 } 543 } 544 #endif /* sinix */ 545 546 #if defined(nec_ews) 547 #include <sys/systeminfo.h> 548 549 static size_t 550 GetHighResClock(void *buf, size_t maxbytes) 551 { 552 return 0; 553 } 554 555 static void 556 GiveSystemInfo(void) 557 { 558 int rv; 559 char buf[2000]; 560 561 rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); 562 if (rv > 0) { 563 RNG_RandomUpdate(buf, rv); 564 } 565 rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); 566 if (rv > 0) { 567 RNG_RandomUpdate(buf, rv); 568 } 569 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); 570 if (rv > 0) { 571 RNG_RandomUpdate(buf, rv); 572 } 573 } 574 #endif /* nec_ews */ 575 576 size_t 577 RNG_GetNoise(void *buf, size_t maxbytes) 578 { 579 struct timeval tv; 580 int n = 0; 581 int c; 582 583 n = GetHighResClock(buf, maxbytes); 584 maxbytes -= n; 585 586 (void)gettimeofday(&tv, 0); 587 c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec)); 588 n += c; 589 maxbytes -= c; 590 c = CopyLowBits((char *)buf + n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec)); 591 n += c; 592 return n; 593 } 594 595 #ifdef DARWIN 596 #include <TargetConditionals.h> 597 #if !TARGET_OS_IPHONE 598 #include <crt_externs.h> 599 #endif 600 #endif 601 602 void 603 RNG_SystemInfoForRNG(void) 604 { 605 char buf[BUFSIZ]; 606 size_t bytes; 607 const char *const *cp; 608 char *randfile; 609 #ifdef DARWIN 610 #if TARGET_OS_IPHONE 611 /* iOS does not expose a way to access environ. */ 612 char **environ = NULL; 613 #else 614 char **environ = *_NSGetEnviron(); 615 #endif 616 #else 617 extern char **environ; 618 #endif 619 static const char *const files[] = { 620 "/etc/passwd", 621 "/etc/utmp", 622 "/tmp", 623 "/var/tmp", 624 "/usr/tmp", 625 0 626 }; 627 628 GiveSystemInfo(); 629 630 bytes = RNG_GetNoise(buf, sizeof(buf)); 631 RNG_RandomUpdate(buf, bytes); 632 633 /* 634 * Pass the C environment and the addresses of the pointers to the 635 * hash function. This makes the random number function depend on the 636 * execution environment of the user and on the platform the program 637 * is running on. 638 */ 639 if (environ != NULL) { 640 cp = (const char *const *)environ; 641 while (*cp) { 642 RNG_RandomUpdate(*cp, strlen(*cp)); 643 cp++; 644 } 645 RNG_RandomUpdate(environ, (char *)cp - (char *)environ); 646 } 647 648 /* Give in system information */ 649 if (gethostname(buf, sizeof(buf)) == 0) { 650 RNG_RandomUpdate(buf, strlen(buf)); 651 } 652 653 /* grab some data from system's PRNG before any other files. */ 654 bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); 655 if (!bytes) { 656 PORT_SetError(SEC_ERROR_NEED_RANDOM); 657 } 658 659 /* If the user points us to a random file, pass it through the rng */ 660 randfile = PR_GetEnvSecure("NSRANDFILE"); 661 if ((randfile != NULL) && (randfile[0] != '\0')) { 662 char *randCountString = PR_GetEnvSecure("NSRANDCOUNT"); 663 int randCount = randCountString ? atoi(randCountString) : 0; 664 if (randCount != 0) { 665 RNG_FileUpdate(randfile, randCount); 666 } else { 667 RNG_FileForRNG(randfile); 668 } 669 } 670 671 /* pass other files through */ 672 for (cp = files; *cp; cp++) 673 RNG_FileForRNG(*cp); 674 675 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) || defined(HPUX) 676 if (bytes) 677 return; 678 #endif 679 680 #ifdef SOLARIS 681 if (!bytes) { 682 /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */ 683 PRUint32 kstat_bytes = 0; 684 if (SECSuccess != RNG_kstat(&kstat_bytes)) { 685 PORT_Assert(0); 686 } 687 bytes += kstat_bytes; 688 PORT_Assert(bytes); 689 } 690 #endif 691 } 692 693 #define TOTAL_FILE_LIMIT 1000000 /* one million */ 694 695 size_t 696 RNG_FileUpdate(const char *fileName, size_t limit) 697 { 698 FILE *file; 699 int fd; 700 int bytes; 701 size_t fileBytes = 0; 702 struct stat stat_buf; 703 unsigned char buffer[BUFSIZ]; 704 static size_t totalFileBytes = 0; 705 706 /* suppress valgrind warnings due to holes in struct stat */ 707 memset(&stat_buf, 0, sizeof(stat_buf)); 708 709 if (stat((char *)fileName, &stat_buf) < 0) 710 return fileBytes; 711 RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); 712 713 file = fopen(fileName, "r"); 714 if (file != NULL) { 715 /* Read from the underlying file descriptor directly to bypass stdio 716 * buffering and avoid reading more bytes than we need from 717 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because 718 * fread may return EOF in unbuffered I/O mode on Android. 719 * 720 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O 721 * has no performance advantage. */ 722 fd = fileno(file); 723 /* 'file' was just opened, so this should not fail. */ 724 PORT_Assert(fd != -1); 725 while (limit > fileBytes && fd != -1) { 726 bytes = PR_MIN(sizeof buffer, limit - fileBytes); 727 bytes = read(fd, buffer, bytes); 728 if (bytes <= 0) 729 break; 730 RNG_RandomUpdate(buffer, bytes); 731 fileBytes += bytes; 732 totalFileBytes += bytes; 733 /* after TOTAL_FILE_LIMIT has been reached, only read in first 734 ** buffer of data from each subsequent file. 735 */ 736 if (totalFileBytes > TOTAL_FILE_LIMIT) 737 break; 738 } 739 fclose(file); 740 } 741 /* 742 * Pass yet another snapshot of our highest resolution clock into 743 * the hash function. 744 */ 745 bytes = RNG_GetNoise(buffer, sizeof(buffer)); 746 RNG_RandomUpdate(buffer, bytes); 747 return fileBytes; 748 } 749 750 void 751 RNG_FileForRNG(const char *fileName) 752 { 753 RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT); 754 } 755 756 #define _POSIX_PTHREAD_SEMANTICS 757 #include <dirent.h> 758 759 PRBool 760 ReadFileOK(char *dir, char *file) 761 { 762 struct stat stat_buf; 763 char filename[PATH_MAX]; 764 int count = snprintf(filename, sizeof filename, "%s/%s", dir, file); 765 766 if (count <= 0) { 767 return PR_FALSE; /* name too long, can't read it anyway */ 768 } 769 770 if (stat(filename, &stat_buf) < 0) 771 return PR_FALSE; /* can't stat, probably can't read it then as well */ 772 return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE; 773 } 774 775 size_t 776 RNG_SystemRNG(void *dest, size_t maxLen) 777 { 778 FILE *file; 779 int fd; 780 int bytes; 781 size_t fileBytes = 0; 782 unsigned char *buffer = dest; 783 784 file = fopen("/dev/urandom", "r"); 785 if (file == NULL) { 786 PORT_SetError(SEC_ERROR_NEED_RANDOM); 787 return 0; 788 } 789 /* Read from the underlying file descriptor directly to bypass stdio 790 * buffering and avoid reading more bytes than we need from /dev/urandom. 791 * NOTE: we can't use fread with unbuffered I/O because fread may return 792 * EOF in unbuffered I/O mode on Android. 793 */ 794 fd = fileno(file); 795 /* 'file' was just opened, so this should not fail. */ 796 PORT_Assert(fd != -1); 797 while (maxLen > fileBytes && fd != -1) { 798 bytes = maxLen - fileBytes; 799 bytes = read(fd, buffer, bytes); 800 if (bytes <= 0) 801 break; 802 fileBytes += bytes; 803 buffer += bytes; 804 } 805 fclose(file); 806 if (fileBytes != maxLen) { 807 PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ 808 fileBytes = 0; 809 } 810 return fileBytes; 811 }