tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

unix_urandom.c (2554B)


      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 <fcntl.h>
      6 #include <unistd.h>
      7 #include <errno.h>
      8 #include "secerr.h"
      9 #include "secrng.h"
     10 #include "prprf.h"
     11 
     12 /* syscall getentropy() is limited to retrieving 256 bytes */
     13 #define GETENTROPY_MAX_BYTES 256
     14 
     15 void
     16 RNG_SystemInfoForRNG(void)
     17 {
     18    PRUint8 bytes[SYSTEM_RNG_SEED_COUNT];
     19    size_t numBytes = RNG_SystemRNG(bytes, SYSTEM_RNG_SEED_COUNT);
     20    if (!numBytes) {
     21        /* error is set */
     22        return;
     23    }
     24    RNG_RandomUpdate(bytes, numBytes);
     25    PORT_SafeZero(bytes, sizeof bytes);
     26 }
     27 
     28 size_t
     29 RNG_SystemRNG(void *dest, size_t maxLen)
     30 {
     31    int fd;
     32    int bytes;
     33    size_t fileBytes = 0;
     34    unsigned char *buffer = dest;
     35 
     36 #if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))))
     37    int result;
     38 
     39    while (fileBytes < maxLen) {
     40        size_t getBytes = maxLen - fileBytes;
     41        if (getBytes > GETENTROPY_MAX_BYTES) {
     42            getBytes = GETENTROPY_MAX_BYTES;
     43        }
     44 
     45        /* get entropy returns 0 on success and always return
     46         * getBytes on success */
     47        result = getentropy(buffer, getBytes);
     48        if (result == 0) { /* success */
     49            fileBytes += getBytes;
     50            buffer += getBytes;
     51        } else {
     52            break;
     53        }
     54    }
     55    if (fileBytes == maxLen) { /* success */
     56        return maxLen;
     57    }
     58    /* If we failed with an error other than ENOSYS, it means the destination
     59     * buffer is not writeable. We don't need to try writing to it again. */
     60    if (errno != ENOSYS) {
     61        PORT_SetError(SEC_ERROR_NEED_RANDOM);
     62        return 0;
     63    }
     64    /* ENOSYS means the kernel doesn't support getentropy()/getrandom().
     65     * Reset the number of bytes to get and fall back to /dev/urandom. */
     66    fileBytes = 0;
     67 #endif /* platorm has getentropy */
     68    fd = open("/dev/urandom", O_RDONLY);
     69    if (fd < 0) {
     70        PORT_SetError(SEC_ERROR_NEED_RANDOM);
     71        return 0;
     72    }
     73    while (fileBytes < maxLen) {
     74        bytes = read(fd, buffer, maxLen - fileBytes);
     75        if (bytes <= 0) {
     76            break;
     77        }
     78        fileBytes += bytes;
     79        buffer += bytes;
     80    }
     81    (void)close(fd);
     82    if (fileBytes != maxLen) {
     83        PORT_SetError(SEC_ERROR_NEED_RANDOM);
     84        return 0;
     85    }
     86    return fileBytes;
     87 }