/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* * 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? :-)
*/
staticconst PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time. * Returns error if RNG_RandomUpdate fails. Also increments *total_fed * by the number of bytes successfully buffered.
*/ static SECStatus
BufferEntropy(char *inbuf, PRUint32 inlen, char *entropy_buf, PRUint32 *entropy_buffered,
PRUint32 *total_fed)
{
PRUint32 tocopy = 0;
PRUint32 avail = 0;
SECStatus rv = SECSuccess;
while (inlen) {
avail = entropy_buf_len - *entropy_buffered; if (!avail) { /* Buffer is full, time to feed it to the RNG. */
rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len); if (SECSuccess != rv) { break;
}
*entropy_buffered = 0;
avail = entropy_buf_len;
}
tocopy = PR_MIN(avail, inlen);
memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
*entropy_buffered += tocopy;
inlen -= tocopy;
inbuf += tocopy;
*total_fed += tocopy;
} return rv;
}
/* Feed kernel statistics structures and ks_data field to the RNG. * Returns status as well as the number of bytes successfully fed to the RNG.
*/ static SECStatus
RNG_kstat(PRUint32 *fed)
{
kstat_ctl_t *kc = NULL;
kstat_t *ksp = NULL;
PRUint32 entropy_buffered = 0; char *entropy_buf = NULL;
SECStatus rv = SECSuccess;
PORT_Assert(fed); if (!fed) { return SECFailure;
}
*fed = 0;
kc = kstat_open();
PORT_Assert(kc); if (!kc) { return SECFailure;
}
entropy_buf = (char *)PORT_Alloc(entropy_buf_len);
PORT_Assert(entropy_buf); if (entropy_buf) { for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { if (-1 == kstat_read(kc, ksp, NULL)) { /* missing data from a single kstat shouldn't be fatal */ continue;
}
rv = BufferEntropy((char *)ksp, sizeof(kstat_t),
entropy_buf, &entropy_buffered,
fed); if (SECSuccess != rv) { break;
}
if (ksp->ks_data && ksp->ks_data_size > 0 && ksp->ks_ndata > 0) {
rv = BufferEntropy((char *)ksp->ks_data, ksp->ks_data_size,
entropy_buf, &entropy_buffered,
fed); if (SECSuccess != rv) { break;
}
}
} if (SECSuccess == rv && entropy_buffered) { /* Buffer is not empty, time to feed it to the RNG */
rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
}
PORT_Free(entropy_buf);
} else {
rv = SECFailure;
} if (kstat_close(kc)) {
PORT_Assert(0);
rv = SECFailure;
} return rv;
}
/* 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 */
#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;
/* * 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 */
}
}
/* * 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.
*/ if (environ != NULL) {
cp = (constchar *const *)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));
}
/* grab some data from system's PRNG before any other files. */
bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); if (!bytes) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
}
/* If the user points us to a random file, pass it through the rng */
randfile = PR_GetEnvSecure("NSRANDFILE"); if ((randfile != NULL) && (randfile[0] != '\0')) { char *randCountString = PR_GetEnvSecure("NSRANDCOUNT"); int randCount = randCountString ? atoi(randCountString) : 0; if (randCount != 0) {
RNG_FileUpdate(randfile, randCount);
} else {
RNG_FileForRNG(randfile);
}
}
/* pass other files through */ for (cp = files; *cp; cp++)
RNG_FileForRNG(*cp);
#ifdef SOLARIS if (!bytes) { /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
PRUint32 kstat_bytes = 0; if (SECSuccess != RNG_kstat(&kstat_bytes)) {
PORT_Assert(0);
}
bytes += kstat_bytes;
PORT_Assert(bytes);
} #endif
}
#define TOTAL_FILE_LIMIT 1000000 /* one million */
size_t
RNG_FileUpdate(constchar *fileName, size_t limit)
{
FILE *file; int fd; int bytes;
size_t fileBytes = 0; struct stat stat_buf; unsignedchar buffer[BUFSIZ]; static size_t totalFileBytes = 0;
/* suppress valgrind warnings due to holes in struct stat */
memset(&stat_buf, 0, sizeof(stat_buf));
if (stat((char *)fileName, &stat_buf) < 0) return fileBytes;
RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
file = fopen(fileName, "r"); if (file != NULL) { /* Read from the underlying file descriptor directly to bypass stdio * buffering and avoid reading more bytes than we need from * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because * fread may return EOF in unbuffered I/O mode on Android. * * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
* has no performance advantage. */
fd = fileno(file); /* 'file' was just opened, so this should not fail. */
PORT_Assert(fd != -1); while (limit > fileBytes && fd != -1) {
bytes = PR_MIN(sizeof buffer, limit - fileBytes);
bytes = read(fd, buffer, bytes); if (bytes <= 0) break;
RNG_RandomUpdate(buffer, bytes);
fileBytes += bytes;
totalFileBytes += bytes; /* after TOTAL_FILE_LIMIT has been reached, only read in first ** buffer of data from each subsequent file.
*/ if (totalFileBytes > TOTAL_FILE_LIMIT) 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); return fileBytes;
}
PRBool
ReadFileOK(char *dir, char *file)
{ struct stat stat_buf; char filename[PATH_MAX]; int count = snprintf(filename, sizeof filename, "%s/%s", dir, file);
if (count <= 0) { return PR_FALSE; /* name too long, can't read it anyway */
}
if (stat(filename, &stat_buf) < 0) return PR_FALSE; /* can't stat, probably can't read it then as well */ return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
}
size_t
RNG_SystemRNG(void *dest, size_t maxLen)
{
FILE *file; int fd; int bytes;
size_t fileBytes = 0; unsignedchar *buffer = dest;
file = fopen("/dev/urandom", "r"); if (file == NULL) {
PORT_SetError(SEC_ERROR_NEED_RANDOM); return 0;
} /* Read from the underlying file descriptor directly to bypass stdio * buffering and avoid reading more bytes than we need from /dev/urandom. * NOTE: we can't use fread with unbuffered I/O because fread may return * EOF in unbuffered I/O mode on Android.
*/
fd = fileno(file); /* 'file' was just opened, so this should not fail. */
PORT_Assert(fd != -1); while (maxLen > fileBytes && fd != -1) {
bytes = maxLen - fileBytes;
bytes = read(fd, buffer, bytes); if (bytes <= 0) break;
fileBytes += bytes;
buffer += bytes;
}
fclose(file); if (fileBytes != maxLen) {
PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */
fileBytes = 0;
} return fileBytes;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.