summaryrefslogtreecommitdiff
path: root/security/nss/lib/util/unix_rand.c
diff options
context:
space:
mode:
authorrelyea%netscape.com <devnull@localhost>2000-03-31 20:13:40 +0000
committerrelyea%netscape.com <devnull@localhost>2000-03-31 20:13:40 +0000
commit9502869e82d4f3ce26b292263e1c626dca3a34f3 (patch)
tree4d0f8ab157505b57c13a5e2bdf979560ab751527 /security/nss/lib/util/unix_rand.c
parent222a52dab759085f56dcb6588b69a6a937d82aa2 (diff)
downloadnss-hg-9502869e82d4f3ce26b292263e1c626dca3a34f3.tar.gz
Initial NSS Open Source checkin
Diffstat (limited to 'security/nss/lib/util/unix_rand.c')
-rw-r--r--security/nss/lib/util/unix_rand.c792
1 files changed, 792 insertions, 0 deletions
diff --git a/security/nss/lib/util/unix_rand.c b/security/nss/lib/util/unix_rand.c
new file mode 100644
index 000000000..6e9c34dbb
--- /dev/null
+++ b/security/nss/lib/util/unix_rand.c
@@ -0,0 +1,792 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include "secrng.h"
+
+
+/*
+ * When copying data to the buffer we want the least signicant bytes
+ * from the input since those bits are changing the fastest. The address
+ * of least significant byte depends upon whether we are running on
+ * a big-endian or little-endian machine.
+ *
+ * Does this mean the least signicant bytes are the most significant
+ * to us? :-)
+ */
+
+static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
+{
+ union endianness {
+ int32 i;
+ char c[4];
+ } u;
+
+ if (srclen <= dstlen) {
+ memcpy(dst, src, srclen);
+ return srclen;
+ }
+ u.i = 0x01020304;
+ if (u.c[0] == 0x01) {
+ /* big-endian case */
+ memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
+ } else {
+ /* little-endian case */
+ memcpy(dst, src, dstlen);
+ }
+ return dstlen;
+}
+
+#if defined(SCO) || defined(UNIXWARE) || defined(BSDI)
+#include <sys/times.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ int ticks;
+ struct tms buffer;
+
+ ticks=times(&buffer);
+ return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+
+static void
+GiveSystemInfo(void)
+{
+ long si;
+
+ /*
+ * Is this really necessary? Why not use rand48 or something?
+ */
+ si = sysconf(_SC_CHILD_MAX);
+ RNG_RandomUpdate(&si, sizeof(si));
+
+ si = sysconf(_SC_STREAM_MAX);
+ RNG_RandomUpdate(&si, sizeof(si));
+
+ si = sysconf(_SC_OPEN_MAX);
+ RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif
+
+#if defined(__sun)
+#if defined(__svr4) || defined(SVR4)
+#include <sys/systeminfo.h>
+#include <sys/times.h>
+#include <wait.h>
+
+int gettimeofday(struct timeval *);
+int gethostname(char *, int);
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[2000];
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ hrtime_t t;
+ t = gethrtime();
+ if (t) {
+ return CopyLowBits(buf, maxbytes, &t, sizeof(t));
+ }
+ return 0;
+}
+#else /* SunOS (Sun, but not SVR4) */
+
+#include <sys/wait.h>
+extern long sysconf(int name);
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ long si;
+
+ /* This is not very good */
+ si = sysconf(_SC_CHILD_MAX);
+ RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif
+#endif /* Sun */
+
+#if defined(__hpux)
+#include <sys/unistd.h>
+#include <sys/wait.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ extern int ret_cr16();
+ int cr16val;
+
+ cr16val = ret_cr16();
+ return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
+}
+
+static void
+GiveSystemInfo(void)
+{
+ long si;
+
+ /* This is not very good */
+ si = sysconf(_AES_OS_VERSION);
+ RNG_RandomUpdate(&si, sizeof(si));
+ si = sysconf(_SC_CPU_VERSION);
+ RNG_RandomUpdate(&si, sizeof(si));
+}
+#endif /* HPUX */
+
+#if defined(OSF1)
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+#include <sys/wait.h>
+#include <sys/systeminfo.h>
+#include <c_asm.h>
+
+static void
+GiveSystemInfo(void)
+{
+ char buf[BUFSIZ];
+ int rv;
+ int off = 0;
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+
+/*
+ * Use the "get the cycle counter" instruction on the alpha.
+ * The low 32 bits completely turn over in less than a minute.
+ * The high 32 bits are some non-counter gunk that changes sometimes.
+ */
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ unsigned long t;
+
+ t = asm("rpcc %v0");
+ return CopyLowBits(buf, maxbytes, &t, sizeof(t));
+}
+
+#endif /* Alpha */
+
+#if defined(_IBMR2)
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ /* XXX haven't found any yet! */
+}
+#endif /* IBM R2 */
+
+#if defined(__linux)
+#include <linux/kernel.h>
+
+int putenv(const char *);
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ /* XXX sysinfo() does not seem be implemented anywhwere */
+#if 0
+ struct sysinfo si;
+ char hn[2000];
+ if (sysinfo(&si) == 0) {
+ RNG_RandomUpdate(&si, sizeof(si));
+ }
+#endif
+}
+#endif /* __linux */
+
+#if defined(NCR)
+
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[2000];
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+
+#endif /* NCR */
+
+
+#if defined(sgi)
+#include <fcntl.h>
+#undef PRIVATE
+#include <sys/mman.h>
+#include <sys/syssgi.h>
+#include <sys/immu.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+#include <wait.h>
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[4096];
+
+ rv = syssgi(SGI_SYSID, &buf[0]);
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, MAXSYSIDSIZE);
+ }
+#ifdef SGI_RDUBLK
+ rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, sizeof(buf));
+ }
+#endif /* SGI_RDUBLK */
+ rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, sizeof(buf));
+ }
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+
+static size_t GetHighResClock(void *buf, size_t maxbuf)
+{
+ unsigned phys_addr, raddr, cycleval;
+ static volatile unsigned *iotimer_addr = NULL;
+ static int tries = 0;
+ static int cntr_size;
+ int mfd;
+ long s0[2];
+ struct timeval tv;
+
+#ifndef SGI_CYCLECNTR_SIZE
+#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
+#endif
+
+ if (iotimer_addr == NULL) {
+ if (tries++ > 1) {
+ /* Don't keep trying if it didn't work */
+ return 0;
+ }
+
+ /*
+ ** For SGI machines we can use the cycle counter, if it has one,
+ ** to generate some truly random numbers
+ */
+ phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
+ if (phys_addr) {
+ int pgsz = getpagesize();
+ int pgoffmask = pgsz - 1;
+
+ raddr = phys_addr & ~pgoffmask;
+ mfd = open("/dev/mmem", O_RDONLY);
+ if (mfd < 0) {
+ return 0;
+ }
+ iotimer_addr = (unsigned *)
+ mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
+ if (iotimer_addr == (void*)-1) {
+ close(mfd);
+ iotimer_addr = NULL;
+ return 0;
+ }
+ iotimer_addr = (unsigned*)
+ ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
+ /*
+ * The file 'mfd' is purposefully not closed.
+ */
+ cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
+ if (cntr_size < 0) {
+ struct utsname utsinfo;
+
+ /*
+ * We must be executing on a 6.0 or earlier system, since the
+ * SGI_CYCLECNTR_SIZE call is not supported.
+ *
+ * The only pre-6.1 platforms with 64-bit counters are
+ * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
+ */
+ uname(&utsinfo);
+ if (!strncmp(utsinfo.machine, "IP19", 4) ||
+ !strncmp(utsinfo.machine, "IP21", 4))
+ cntr_size = 64;
+ else
+ cntr_size = 32;
+ }
+ cntr_size /= 8; /* Convert from bits to bytes */
+ }
+ }
+
+ s0[0] = *iotimer_addr;
+ if (cntr_size > 4)
+ s0[1] = *(iotimer_addr + 1);
+ memcpy(buf, (char *)&s0[0], cntr_size);
+ return CopyLowBits(buf, maxbuf, &s0, cntr_size);
+}
+#endif
+
+#if defined(sony)
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[2000];
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+#endif /* sony */
+
+#if defined(sinix)
+#include <unistd.h>
+#include <sys/systeminfo.h>
+#include <sys/times.h>
+
+int gettimeofday(struct timeval *, struct timezone *);
+int gethostname(char *, int);
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ int ticks;
+ struct tms buffer;
+
+ ticks=times(&buffer);
+ return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
+}
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[2000];
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+#endif /* sinix */
+
+#if defined(nec_ews)
+#include <sys/systeminfo.h>
+
+#define getdtablesize() sysconf(_SC_OPEN_MAX)
+
+static size_t
+GetHighResClock(void *buf, size_t maxbytes)
+{
+ return 0;
+}
+
+static void
+GiveSystemInfo(void)
+{
+ int rv;
+ char buf[2000];
+
+ rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+ rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
+ if (rv > 0) {
+ RNG_RandomUpdate(buf, rv);
+ }
+}
+#endif /* nec_ews */
+
+size_t RNG_GetNoise(void *buf, size_t maxbytes)
+{
+ struct timeval tv;
+ int n = 0;
+ int c;
+
+ n = GetHighResClock(buf, maxbytes);
+ maxbytes -= n;
+
+#if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony)
+ (void)gettimeofday(&tv);
+#else
+ (void)gettimeofday(&tv, 0);
+#endif
+ c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
+ n += c;
+ maxbytes -= c;
+ c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
+ n += c;
+ return n;
+}
+
+#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
+
+/*
+ * safe_popen is static to this module and we know what arguments it is
+ * called with. Note that this version only supports a single open child
+ * process at any time.
+ */
+static pid_t safe_popen_pid;
+static struct sigaction oldact;
+
+static FILE *
+safe_popen(char *cmd)
+{
+ int p[2], fd, argc;
+ pid_t pid;
+ char *argv[SAFE_POPEN_MAXARGS + 1];
+ FILE *fp;
+ static char blank[] = " \t";
+ static struct sigaction newact;
+
+ if (pipe(p) < 0)
+ return 0;
+
+ /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
+ newact.sa_handler = SIG_DFL;
+ newact.sa_flags = 0;
+ sigfillset(&newact.sa_mask);
+ sigaction (SIGCHLD, &newact, &oldact);
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ close(p[0]);
+ close(p[1]);
+ sigaction (SIGCHLD, &oldact, NULL);
+ return 0;
+
+ case 0:
+ /* dup write-side of pipe to stderr and stdout */
+ if (p[1] != 1) dup2(p[1], 1);
+ if (p[1] != 2) dup2(p[1], 2);
+ close(0);
+ for (fd = getdtablesize(); --fd > 2; close(fd))
+ ;
+
+ /* clean up environment in the child process */
+ putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
+ putenv("SHELL=/bin/sh");
+ putenv("IFS= \t");
+
+ /*
+ * The caller may have passed us a string that is in text
+ * space. It may be illegal to modify the string
+ */
+ cmd = strdup(cmd);
+ /* format argv */
+ argv[0] = strtok(cmd, blank);
+ argc = 1;
+ while ((argv[argc] = strtok(0, blank)) != 0) {
+ if (++argc == SAFE_POPEN_MAXARGS) {
+ argv[argc] = 0;
+ break;
+ }
+ }
+
+ /* and away we go */
+ execvp(argv[0], argv);
+ exit(127);
+ break;
+
+ default:
+ close(p[1]);
+ fp = fdopen(p[0], "r");
+ if (fp == 0) {
+ close(p[0]);
+ sigaction (SIGCHLD, &oldact, NULL);
+ return 0;
+ }
+ break;
+ }
+
+ /* non-zero means there's a cmd running */
+ safe_popen_pid = pid;
+ return fp;
+}
+
+static int
+safe_pclose(FILE *fp)
+{
+ pid_t pid;
+ int count, status;
+
+ if ((pid = safe_popen_pid) == 0)
+ return -1;
+ safe_popen_pid = 0;
+
+ /* if the child hasn't exited, kill it -- we're done with its output */
+ count = 0;
+ while (waitpid(pid, &status, WNOHANG) == 0) {
+ if (kill(pid, SIGKILL) < 0 && errno == ESRCH)
+ break;
+ if (++count == 1000)
+ break;
+ }
+
+ /* Reset SIGCHLD signal hander before returning */
+ sigaction(SIGCHLD, &oldact, NULL);
+
+ fclose(fp);
+ return status;
+}
+
+void RNG_SystemInfoForRNG(void)
+{
+ FILE *fp;
+ char buf[BUFSIZ];
+ size_t bytes;
+ extern char **environ;
+ char **cp;
+ char *randfile;
+ char *files[] = {
+ "/etc/passwd",
+ "/etc/utmp",
+ "/tmp",
+ "/var/tmp",
+ "/usr/tmp",
+ 0
+ };
+
+#ifdef DO_PS
+For now it is considered that it is too expensive to run the ps command
+for the small amount of entropy it provides.
+#if defined(__sun) && (!defined(__svr4) && !defined(SVR4)) || defined(bsdi) || defined(__linux)
+ static char ps_cmd[] = "ps aux";
+#else
+ static char ps_cmd[] = "ps -el";
+#endif
+#endif /* DO_PS */
+ static char netstat_ni_cmd[] = "netstat -ni";
+
+ GiveSystemInfo();
+
+ bytes = RNG_GetNoise(buf, sizeof(buf));
+ RNG_RandomUpdate(buf, bytes);
+
+#ifdef DO_PS
+ fp = safe_popen(ps_cmd);
+ if (fp != NULL) {
+ while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
+ RNG_RandomUpdate(buf, bytes);
+ safe_pclose(fp);
+ }
+#endif
+ fp = safe_popen(netstat_ni_cmd);
+ if (fp != NULL) {
+ while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
+ RNG_RandomUpdate(buf, bytes);
+ safe_pclose(fp);
+ }
+
+ /*
+ * Pass the C environment and the addresses of the pointers to the
+ * hash function. This makes the random number function depend on the
+ * execution environment of the user and on the platform the program
+ * is running on.
+ */
+ cp = environ;
+ while (*cp) {
+ RNG_RandomUpdate(*cp, strlen(*cp));
+ cp++;
+ }
+ RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
+
+ /* Give in system information */
+ if (gethostname(buf, sizeof(buf)) > 0) {
+ RNG_RandomUpdate(buf, strlen(buf));
+ }
+ GiveSystemInfo();
+
+ /* If the user points us to a random file, pass it through the rng */
+ randfile = getenv("NSRANDFILE");
+ if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
+ RNG_FileForRNG(randfile);
+ }
+
+ /* pass other files through */
+ for (cp = files; *cp; cp++)
+ RNG_FileForRNG(*cp);
+
+}
+
+void RNG_FileForRNG(char *fileName)
+{
+ struct stat stat_buf;
+ unsigned char buffer[BUFSIZ];
+ size_t bytes;
+ FILE *file;
+ static size_t totalFileBytes = 0;
+
+ if (stat((char *)fileName, &stat_buf) < 0)
+ return;
+ RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
+
+ file = fopen((char *)fileName, "r");
+ if (file != NULL) {
+ for (;;) {
+ bytes = fread(buffer, 1, sizeof(buffer), file);
+ if (bytes == 0) break;
+ RNG_RandomUpdate(buffer, bytes);
+ totalFileBytes += bytes;
+ if (totalFileBytes > 1024*1024) break;
+ }
+ fclose(file);
+ }
+ /*
+ * Pass yet another snapshot of our highest resolution clock into
+ * the hash function.
+ */
+ bytes = RNG_GetNoise(buffer, sizeof(buffer));
+ RNG_RandomUpdate(buffer, bytes);
+}