1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
51 size_t RNG_FileUpdate(const char *fileName
, size_t limit
);
54 * When copying data to the buffer we want the least signicant bytes
55 * from the input since those bits are changing the fastest. The address
56 * of least significant byte depends upon whether we are running on
57 * a big-endian or little-endian machine.
59 * Does this mean the least signicant bytes are the most significant
63 static size_t CopyLowBits(void *dst
, size_t dstlen
, void *src
, size_t srclen
)
70 if (srclen
<= dstlen
) {
71 memcpy(dst
, src
, srclen
);
77 memcpy(dst
, (char*)src
+ (srclen
- dstlen
), dstlen
);
79 /* little-endian case */
80 memcpy(dst
, src
, dstlen
);
89 static const PRUint32 entropy_buf_len
= 4096; /* buffer up to 4 KB */
91 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
92 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
93 * by the number of bytes successfully buffered.
95 static SECStatus
BufferEntropy(char* inbuf
, PRUint32 inlen
,
96 char* entropy_buf
, PRUint32
* entropy_buffered
,
101 SECStatus rv
= SECSuccess
;
104 avail
= entropy_buf_len
- *entropy_buffered
;
106 /* Buffer is full, time to feed it to the RNG. */
107 rv
= RNG_RandomUpdate(entropy_buf
, entropy_buf_len
);
108 if (SECSuccess
!= rv
) {
111 *entropy_buffered
= 0;
112 avail
= entropy_buf_len
;
114 tocopy
= PR_MIN(avail
, inlen
);
115 memcpy(entropy_buf
+ *entropy_buffered
, inbuf
, tocopy
);
116 *entropy_buffered
+= tocopy
;
119 *total_fed
+= tocopy
;
124 /* Feed kernel statistics structures and ks_data field to the RNG.
125 * Returns status as well as the number of bytes successfully fed to the RNG.
127 static SECStatus
RNG_kstat(PRUint32
* fed
)
129 kstat_ctl_t
* kc
= NULL
;
131 PRUint32 entropy_buffered
= 0;
132 char* entropy_buf
= NULL
;
133 SECStatus rv
= SECSuccess
;
146 entropy_buf
= (char*) PORT_Alloc(entropy_buf_len
);
147 PORT_Assert(entropy_buf
);
149 for (ksp
= kc
->kc_chain
; ksp
!= NULL
; ksp
= ksp
->ks_next
) {
150 if (-1 == kstat_read(kc
, ksp
, NULL
)) {
151 /* missing data from a single kstat shouldn't be fatal */
154 rv
= BufferEntropy((char*)ksp
, sizeof(kstat_t
),
155 entropy_buf
, &entropy_buffered
,
157 if (SECSuccess
!= rv
) {
161 if (ksp
->ks_data
&& ksp
->ks_data_size
>0 && ksp
->ks_ndata
>0) {
162 rv
= BufferEntropy((char*)ksp
->ks_data
, ksp
->ks_data_size
,
163 entropy_buf
, &entropy_buffered
,
165 if (SECSuccess
!= rv
) {
170 if (SECSuccess
== rv
&& entropy_buffered
) {
171 /* Buffer is not empty, time to feed it to the RNG */
172 rv
= RNG_RandomUpdate(entropy_buf
, entropy_buffered
);
174 PORT_Free(entropy_buf
);
178 if (kstat_close(kc
)) {
187 #if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
188 || defined(NETBSD) || defined(NTO) || defined(DARWIN) || defined(OPENBSD)
189 #include <sys/times.h>
191 #define getdtablesize() sysconf(_SC_OPEN_MAX)
194 GetHighResClock(void *buf
, size_t maxbytes
)
199 ticks
=times(&buffer
);
200 return CopyLowBits(buf
, maxbytes
, &ticks
, sizeof(ticks
));
209 * Is this really necessary? Why not use rand48 or something?
211 si
= sysconf(_SC_CHILD_MAX
);
212 RNG_RandomUpdate(&si
, sizeof(si
));
214 si
= sysconf(_SC_STREAM_MAX
);
215 RNG_RandomUpdate(&si
, sizeof(si
));
217 si
= sysconf(_SC_OPEN_MAX
);
218 RNG_RandomUpdate(&si
, sizeof(si
));
223 #if defined(__svr4) || defined(SVR4)
224 #include <sys/systeminfo.h>
225 #include <sys/times.h>
228 int gettimeofday(struct timeval
*);
229 int gethostname(char *, int);
231 #define getdtablesize() sysconf(_SC_OPEN_MAX)
239 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
241 RNG_RandomUpdate(buf
, rv
);
243 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
245 RNG_RandomUpdate(buf
, rv
);
247 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
249 RNG_RandomUpdate(buf
, rv
);
254 GetHighResClock(void *buf
, size_t maxbytes
)
259 return CopyLowBits(buf
, maxbytes
, &t
, sizeof(t
));
263 #else /* SunOS (Sun, but not SVR4) */
265 extern long sysconf(int name
);
268 GetHighResClock(void *buf
, size_t maxbytes
)
278 /* This is not very good */
279 si
= sysconf(_SC_CHILD_MAX
);
280 RNG_RandomUpdate(&si
, sizeof(si
));
286 #include <sys/unistd.h>
288 #define getdtablesize() sysconf(_SC_OPEN_MAX)
291 #include <ia64/sys/inline.h>
294 GetHighResClock(void *buf
, size_t maxbytes
)
298 t
= _Asm_mov_from_ar(_AREG44
);
299 return CopyLowBits(buf
, maxbytes
, &t
, sizeof(t
));
303 GetHighResClock(void *buf
, size_t maxbytes
)
305 extern int ret_cr16();
308 cr16val
= ret_cr16();
309 return CopyLowBits(buf
, maxbytes
, &cr16val
, sizeof(cr16val
));
318 /* This is not very good */
319 si
= sysconf(_AES_OS_VERSION
);
320 RNG_RandomUpdate(&si
, sizeof(si
));
321 si
= sysconf(_SC_CPU_VERSION
);
322 RNG_RandomUpdate(&si
, sizeof(si
));
327 #include <sys/types.h>
328 #include <sys/sysinfo.h>
329 #include <sys/systeminfo.h>
339 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
341 RNG_RandomUpdate(buf
, rv
);
343 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
345 RNG_RandomUpdate(buf
, rv
);
347 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
349 RNG_RandomUpdate(buf
, rv
);
354 * Use the "get the cycle counter" instruction on the alpha.
355 * The low 32 bits completely turn over in less than a minute.
356 * The high 32 bits are some non-counter gunk that changes sometimes.
359 GetHighResClock(void *buf
, size_t maxbytes
)
364 return CopyLowBits(buf
, maxbytes
, &t
, sizeof(t
));
371 GetHighResClock(void *buf
, size_t maxbytes
)
379 /* XXX haven't found any yet! */
384 #include <sys/sysinfo.h>
387 GetHighResClock(void *buf
, size_t maxbytes
)
396 if (sysinfo(&si
) == 0) {
397 RNG_RandomUpdate(&si
, sizeof(si
));
404 #include <sys/utsname.h>
405 #include <sys/systeminfo.h>
407 #define getdtablesize() sysconf(_SC_OPEN_MAX)
410 GetHighResClock(void *buf
, size_t maxbytes
)
421 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
423 RNG_RandomUpdate(buf
, rv
);
425 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
427 RNG_RandomUpdate(buf
, rv
);
429 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
431 RNG_RandomUpdate(buf
, rv
);
441 #include <sys/mman.h>
442 #include <sys/syssgi.h>
443 #include <sys/immu.h>
444 #include <sys/systeminfo.h>
445 #include <sys/utsname.h>
454 rv
= syssgi(SGI_SYSID
, &buf
[0]);
456 RNG_RandomUpdate(buf
, MAXSYSIDSIZE
);
459 rv
= syssgi(SGI_RDUBLK
, getpid(), &buf
[0], sizeof(buf
));
461 RNG_RandomUpdate(buf
, sizeof(buf
));
463 #endif /* SGI_RDUBLK */
464 rv
= syssgi(SGI_INVENT
, SGI_INV_READ
, buf
, sizeof(buf
));
466 RNG_RandomUpdate(buf
, sizeof(buf
));
468 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
470 RNG_RandomUpdate(buf
, rv
);
472 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
474 RNG_RandomUpdate(buf
, rv
);
476 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
478 RNG_RandomUpdate(buf
, rv
);
482 static size_t GetHighResClock(void *buf
, size_t maxbuf
)
484 unsigned phys_addr
, raddr
, cycleval
;
485 static volatile unsigned *iotimer_addr
= NULL
;
486 static int tries
= 0;
487 static int cntr_size
;
492 #ifndef SGI_CYCLECNTR_SIZE
493 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
496 if (iotimer_addr
== NULL
) {
498 /* Don't keep trying if it didn't work */
503 ** For SGI machines we can use the cycle counter, if it has one,
504 ** to generate some truly random numbers
506 phys_addr
= syssgi(SGI_QUERY_CYCLECNTR
, &cycleval
);
508 int pgsz
= getpagesize();
509 int pgoffmask
= pgsz
- 1;
511 raddr
= phys_addr
& ~pgoffmask
;
512 mfd
= open("/dev/mmem", O_RDONLY
);
516 iotimer_addr
= (unsigned *)
517 mmap(0, pgoffmask
, PROT_READ
, MAP_PRIVATE
, mfd
, (int)raddr
);
518 if (iotimer_addr
== (void*)-1) {
523 iotimer_addr
= (unsigned*)
524 ((__psint_t
)iotimer_addr
| (phys_addr
& pgoffmask
));
526 * The file 'mfd' is purposefully not closed.
528 cntr_size
= syssgi(SGI_CYCLECNTR_SIZE
);
530 struct utsname utsinfo
;
533 * We must be executing on a 6.0 or earlier system, since the
534 * SGI_CYCLECNTR_SIZE call is not supported.
536 * The only pre-6.1 platforms with 64-bit counters are
537 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
540 if (!strncmp(utsinfo
.machine
, "IP19", 4) ||
541 !strncmp(utsinfo
.machine
, "IP21", 4))
546 cntr_size
/= 8; /* Convert from bits to bytes */
550 s0
[0] = *iotimer_addr
;
552 s0
[1] = *(iotimer_addr
+ 1);
553 memcpy(buf
, (char *)&s0
[0], cntr_size
);
554 return CopyLowBits(buf
, maxbuf
, &s0
, cntr_size
);
559 #include <sys/systeminfo.h>
561 #define getdtablesize() sysconf(_SC_OPEN_MAX)
564 GetHighResClock(void *buf
, size_t maxbytes
)
575 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
577 RNG_RandomUpdate(buf
, rv
);
579 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
581 RNG_RandomUpdate(buf
, rv
);
583 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
585 RNG_RandomUpdate(buf
, rv
);
591 #include <sys/systeminfo.h>
592 #include <sys/times.h>
594 int gettimeofday(struct timeval
*, struct timezone
*);
595 int gethostname(char *, int);
597 #define getdtablesize() sysconf(_SC_OPEN_MAX)
600 GetHighResClock(void *buf
, size_t maxbytes
)
605 ticks
=times(&buffer
);
606 return CopyLowBits(buf
, maxbytes
, &ticks
, sizeof(ticks
));
615 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
617 RNG_RandomUpdate(buf
, rv
);
619 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
621 RNG_RandomUpdate(buf
, rv
);
623 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
625 RNG_RandomUpdate(buf
, rv
);
639 * This is copied from the SCO/UNIXWARE etc section. And like the comment
640 * there says, what's the point? This isn't random, it generates the same
641 * stuff every time its run!
643 si
= sysconf(_SC_CHILD_MAX
);
644 RNG_RandomUpdate(&si
, sizeof(si
));
646 si
= sysconf(_SC_STREAM_MAX
);
647 RNG_RandomUpdate(&si
, sizeof(si
));
649 si
= sysconf(_SC_OPEN_MAX
);
650 RNG_RandomUpdate(&si
, sizeof(si
));
654 * Use the "get the cycle counter" instruction on the alpha.
655 * The low 32 bits completely turn over in less than a minute.
656 * The high 32 bits are some non-counter gunk that changes sometimes.
659 GetHighResClock(void *buf
, size_t maxbytes
)
664 return CopyLowBits(buf
, maxbytes
, &t
, sizeof(t
));
670 #include <be/kernel/OS.h>
673 GetHighResClock(void *buf
, size_t maxbytes
)
675 bigtime_t bigtime
; /* Actually an int64 */
677 bigtime
= real_time_clock_usecs();
678 return CopyLowBits(buf
, maxbytes
, &bigtime
, sizeof(bigtime
));
684 system_info
*info
= NULL
;
686 get_system_info(info
);
688 val
= info
->boot_time
;
689 RNG_RandomUpdate(&val
, sizeof(val
));
690 val
= info
->used_pages
;
691 RNG_RandomUpdate(&val
, sizeof(val
));
692 val
= info
->used_ports
;
693 RNG_RandomUpdate(&val
, sizeof(val
));
694 val
= info
->used_threads
;
695 RNG_RandomUpdate(&val
, sizeof(val
));
696 val
= info
->used_teams
;
697 RNG_RandomUpdate(&val
, sizeof(val
));
703 #include <sys/systeminfo.h>
705 #define getdtablesize() sysconf(_SC_OPEN_MAX)
708 GetHighResClock(void *buf
, size_t maxbytes
)
719 rv
= sysinfo(SI_MACHINE
, buf
, sizeof(buf
));
721 RNG_RandomUpdate(buf
, rv
);
723 rv
= sysinfo(SI_RELEASE
, buf
, sizeof(buf
));
725 RNG_RandomUpdate(buf
, rv
);
727 rv
= sysinfo(SI_HW_SERIAL
, buf
, sizeof(buf
));
729 RNG_RandomUpdate(buf
, rv
);
734 size_t RNG_GetNoise(void *buf
, size_t maxbytes
)
740 n
= GetHighResClock(buf
, maxbytes
);
743 #if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony)
744 (void)gettimeofday(&tv
);
746 (void)gettimeofday(&tv
, 0);
748 c
= CopyLowBits((char*)buf
+n
, maxbytes
, &tv
.tv_usec
, sizeof(tv
.tv_usec
));
751 c
= CopyLowBits((char*)buf
+n
, maxbytes
, &tv
.tv_sec
, sizeof(tv
.tv_sec
));
756 #define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
759 * safe_popen is static to this module and we know what arguments it is
760 * called with. Note that this version only supports a single open child
761 * process at any time.
763 static pid_t safe_popen_pid
;
764 static struct sigaction oldact
;
767 safe_popen(char *cmd
)
771 char *argv
[SAFE_POPEN_MAXARGS
+ 1];
773 static char blank
[] = " \t";
774 static struct sigaction newact
;
779 fp
= fdopen(p
[0], "r");
786 /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
787 newact
.sa_handler
= SIG_DFL
;
789 sigfillset(&newact
.sa_mask
);
790 sigaction (SIGCHLD
, &newact
, &oldact
);
797 fclose(fp
); /* this closes p[0], the fd associated with fp */
799 sigaction (SIGCHLD
, &oldact
, NULL
);
803 /* dup write-side of pipe to stderr and stdout */
804 if (p
[1] != 1) dup2(p
[1], 1);
805 if (p
[1] != 2) dup2(p
[1], 2);
808 * close the other file descriptors, except stdin which we
809 * try reassociating with /dev/null, first (bug 174993)
811 if (!freopen("/dev/null", "r", stdin
))
813 ndesc
= getdtablesize();
814 for (fd
= PR_MIN(65536, ndesc
); --fd
> 2; close(fd
));
816 /* clean up environment in the child process */
817 putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
818 putenv("SHELL=/bin/sh");
822 * The caller may have passed us a string that is in text
823 * space. It may be illegal to modify the string
827 argv
[0] = strtok(cmd
, blank
);
829 while ((argv
[argc
] = strtok(0, blank
)) != 0) {
830 if (++argc
== SAFE_POPEN_MAXARGS
) {
837 execvp(argv
[0], argv
);
846 /* non-zero means there's a cmd running */
847 safe_popen_pid
= pid
;
852 safe_pclose(FILE *fp
)
857 if ((pid
= safe_popen_pid
) == 0)
863 /* yield the processor so the child gets some time to exit normally */
864 PR_Sleep(PR_INTERVAL_NO_WAIT
);
866 /* if the child hasn't exited, kill it -- we're done with its output */
867 while ((rv
= waitpid(pid
, &status
, WNOHANG
)) == -1 && errno
== EINTR
)
871 while ((rv
= waitpid(pid
, &status
, 0)) == -1 && errno
== EINTR
)
875 /* Reset SIGCHLD signal hander before returning */
876 sigaction(SIGCHLD
, &oldact
, NULL
);
885 #include <crt_externs.h>
888 /* Fork netstat to collect its output by default. Do not unset this unless
889 * another source of entropy is available
893 void RNG_SystemInfoForRNG(void)
898 const char * const *cp
;
901 char **environ
= *_NSGetEnviron();
903 extern char **environ
;
906 static const char * const files
[] = {
908 "/boot/var/log/syslog",
910 "/boot/home/config/settings",
915 static const char * const files
[] = {
926 static char netstat_ni_cmd
[] = "netstat -nis";
928 static char netstat_ni_cmd
[] = "netstat -ni";
933 bytes
= RNG_GetNoise(buf
, sizeof(buf
));
934 RNG_RandomUpdate(buf
, bytes
);
937 * Pass the C environment and the addresses of the pointers to the
938 * hash function. This makes the random number function depend on the
939 * execution environment of the user and on the platform the program
942 if (environ
!= NULL
) {
943 cp
= (const char * const *) environ
;
945 RNG_RandomUpdate(*cp
, strlen(*cp
));
948 RNG_RandomUpdate(environ
, (char*)cp
- (char*)environ
);
951 /* Give in system information */
952 if (gethostname(buf
, sizeof(buf
)) == 0) {
953 RNG_RandomUpdate(buf
, strlen(buf
));
957 /* grab some data from system's PRNG before any other files. */
958 bytes
= RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT
);
960 /* If the user points us to a random file, pass it through the rng */
961 randfile
= getenv("NSRANDFILE");
962 if ( ( randfile
!= NULL
) && ( randfile
[0] != '\0') ) {
963 RNG_FileForRNG(randfile
);
966 /* pass other files through */
967 for (cp
= files
; *cp
; cp
++)
971 * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
972 * in a pthreads environment. Therefore, we call safe_popen last and on
973 * BSD/OS we do not call safe_popen when we succeeded in getting data
976 * Bug 174993: LINUX provides /dev/urandom, don't fork netstat
977 * if data has been gathered successfully
980 #if defined(BSDI) || defined(LINUX)
988 * On Solaris, NSS may be initialized automatically from libldap in
989 * applications that are unaware of the use of NSS. safe_popen forks, and
990 * sometimes creates issues with some applications' pthread_atfork handlers.
991 * We always have /dev/urandom on Solaris 9 and above as an entropy source,
992 * and for Solaris 8 we have the libkstat interface, so we don't need to
998 /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
999 PRUint32 kstat_bytes
= 0;
1000 if (SECSuccess
!= RNG_kstat(&kstat_bytes
)) {
1003 bytes
+= kstat_bytes
;
1009 fp
= safe_popen(netstat_ni_cmd
);
1011 while ((bytes
= fread(buf
, 1, sizeof(buf
), fp
)) > 0)
1012 RNG_RandomUpdate(buf
, bytes
);
1019 void RNG_SystemInfoForRNG(void)
1026 extern char **environ
;
1031 bytes
= RNG_GetNoise(buf
, sizeof(buf
));
1032 RNG_RandomUpdate(buf
, bytes
);
1035 * Pass the C environment and the addresses of the pointers to the
1036 * hash function. This makes the random number function depend on the
1037 * execution environment of the user and on the platform the program
1042 RNG_RandomUpdate(*cp
, strlen(*cp
));
1045 RNG_RandomUpdate(environ
, (char*)cp
- (char*)environ
);
1047 /* Give in system information */
1048 if (gethostname(buf
, sizeof(buf
)) > 0) {
1049 RNG_RandomUpdate(buf
, strlen(buf
));
1053 /* If the user points us to a random file, pass it through the rng */
1054 randfile
= getenv("NSRANDFILE");
1055 if ( ( randfile
!= NULL
) && ( randfile
[0] != '\0') ) {
1056 RNG_FileForRNG(randfile
);
1060 ** We need to generate at least 1024 bytes of seed data. Since we don't
1061 ** do the file stuff for VMS, and because the environ list is so short
1062 ** on VMS, we need to make sure we generate enough. So do another 1000
1063 ** bytes to be sure.
1069 int n
= strlen(*cp
);
1070 RNG_RandomUpdate(*cp
, n
);
1078 #define TOTAL_FILE_LIMIT 1000000 /* one million */
1080 size_t RNG_FileUpdate(const char *fileName
, size_t limit
)
1084 size_t fileBytes
= 0;
1085 struct stat stat_buf
;
1086 unsigned char buffer
[BUFSIZ
];
1087 static size_t totalFileBytes
= 0;
1089 /* suppress valgrind warnings due to holes in struct stat */
1090 memset(&stat_buf
, 0, sizeof(stat_buf
));
1092 if (stat((char *)fileName
, &stat_buf
) < 0)
1094 RNG_RandomUpdate(&stat_buf
, sizeof(stat_buf
));
1096 file
= fopen((char *)fileName
, "r");
1098 while (limit
> fileBytes
) {
1099 bytes
= PR_MIN(sizeof buffer
, limit
- fileBytes
);
1100 bytes
= fread(buffer
, 1, bytes
, file
);
1103 RNG_RandomUpdate(buffer
, bytes
);
1105 totalFileBytes
+= bytes
;
1106 /* after TOTAL_FILE_LIMIT has been reached, only read in first
1107 ** buffer of data from each subsequent file.
1109 if (totalFileBytes
> TOTAL_FILE_LIMIT
)
1115 * Pass yet another snapshot of our highest resolution clock into
1116 * the hash function.
1118 bytes
= RNG_GetNoise(buffer
, sizeof(buffer
));
1119 RNG_RandomUpdate(buffer
, bytes
);
1123 void RNG_FileForRNG(const char *fileName
)
1125 RNG_FileUpdate(fileName
, TOTAL_FILE_LIMIT
);
1128 size_t RNG_SystemRNG(void *dest
, size_t maxLen
)
1132 size_t fileBytes
= 0;
1133 unsigned char *buffer
= dest
;
1135 file
= fopen("/dev/urandom", "r");
1137 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
1140 while (maxLen
> fileBytes
) {
1141 bytes
= maxLen
- fileBytes
;
1142 bytes
= fread(buffer
, 1, bytes
, file
);
1149 if (fileBytes
!= maxLen
) {
1150 PORT_SetError(SEC_ERROR_NEED_RANDOM
); /* system RNG failed */