mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
Replace all random functions with isc_random, isc_random_buf and isc_random_uniform API.
The three functions has been modeled after the arc4random family of functions, and they will always return random bytes. The isc_random family of functions internally use these CSPRNG (if available): 1. getrandom() libc call (might be available on Linux and Solaris) 2. SYS_getrandom syscall (might be available on Linux, detected at runtime) 3. arc4random(), arc4random_buf() and arc4random_uniform() (available on BSDs and Mac OS X) 4. crypto library function: 4a. RAND_bytes in case OpenSSL 4b. pkcs_C_GenerateRandom() in case PKCS#11 library
This commit is contained in:
committed by
Witold Kręcicki
parent
74dd289a1c
commit
3a4f820d62
518
lib/isc/random.c
518
lib/isc/random.c
@@ -9,13 +9,11 @@
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
/*%
|
||||
* ChaCha based random number generator derived from OpenBSD.
|
||||
/*
|
||||
* Portions of isc_random_uniform():
|
||||
*
|
||||
* The original copyright follows:
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -30,400 +28,174 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h> /* Required for time(). */
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/once.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/entropy.h>
|
||||
#ifdef OPENSSL
|
||||
#include <openssl/rand.h>
|
||||
#endif /* ifdef OPENSSL */
|
||||
|
||||
#ifdef PKCS11CRYPTO
|
||||
#include <pk11/pk11.h>
|
||||
#endif /* ifdef PKCS11CRYPTO */
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <errno.h>
|
||||
# ifdef HAVE_GETRANDOM
|
||||
# include <sys/random.h>
|
||||
# else /* HAVE_GETRANDOM */
|
||||
# include <sys/syscall.h>
|
||||
# endif /* HAVE_GETRANDOM */
|
||||
#endif /* defined(__linux__) */
|
||||
|
||||
#include <isc/random.h>
|
||||
#include <isc/safe.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#define RNG_MAGIC ISC_MAGIC('R', 'N', 'G', 'x')
|
||||
#define VALID_RNG(r) ISC_MAGIC_VALID(r, RNG_MAGIC)
|
||||
#if defined(__linux__)
|
||||
# ifdef HAVE_GETRANDOM
|
||||
# define have_getrandom() 1
|
||||
# else /* ifdef HAVE_GETRANDOM */
|
||||
# undef getrandom
|
||||
# if defined(SYS_getrandom)
|
||||
# define getrandom(dst,s,flags) syscall(SYS_getrandom, \
|
||||
(void*)dst, \
|
||||
(size_t)s, \
|
||||
(unsigned int)flags)
|
||||
|
||||
#define KEYSTREAM_ONLY
|
||||
#include "chacha_private.h"
|
||||
static unsigned
|
||||
have_getrandom(void)
|
||||
{
|
||||
uint16_t buf;
|
||||
ssize_t ret;
|
||||
ret = getrandom(&buf, sizeof(buf), 1 /*GRND_NONBLOCK*/);
|
||||
return (ret == sizeof(buf) ||
|
||||
(ret == -1 && errno == EAGAIN));
|
||||
}
|
||||
|
||||
# else /* defined(SYS_getrandom) */
|
||||
# define have_getrandom() 0
|
||||
# define getrandom(dst,s,flags) -1
|
||||
# endif /* defined(SYS_getrandom) */
|
||||
# endif /* ifdef HAVE_GETRANDOM */
|
||||
|
||||
static int
|
||||
getrandom_buf(void *buf, size_t buflen)
|
||||
{
|
||||
size_t left = buflen;
|
||||
ssize_t ret;
|
||||
uint8_t *p = buf;
|
||||
|
||||
while (left > 0) {
|
||||
ret = getrandom(p, left, 0);
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RUNTIME_CHECK(ret >= 0);
|
||||
|
||||
if (ret > 0) {
|
||||
left -= ret;
|
||||
p += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
static isc_once_t isc_random_once = ISC_ONCE_INIT;
|
||||
|
||||
static HCRYPTPROV isc_random_hcryptprov;
|
||||
|
||||
static void isc_random_initialize(void) {
|
||||
RUNTIME_CHECK(CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT|CRYPT_SILENT));
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) || defined(_WIN64) */
|
||||
|
||||
uint32_t
|
||||
isc_random(void)
|
||||
{
|
||||
#if defined(HAVE_ARC4RANDOM)
|
||||
return(arc4random());
|
||||
#else /* HAVE_ARC4RANDOM */
|
||||
uint32_t ret;
|
||||
isc_random_buf(&ret, sizeof(ret));
|
||||
return (ret);
|
||||
#endif /* HAVE_ARC4RANDOM */
|
||||
}
|
||||
|
||||
#define CHACHA_KEYSIZE 32U
|
||||
#define CHACHA_IVSIZE 8U
|
||||
#define CHACHA_BLOCKSIZE 64
|
||||
#define CHACHA_BUFFERSIZE (16 * CHACHA_BLOCKSIZE)
|
||||
#define CHACHA_MAXHAVE (CHACHA_BUFFERSIZE - CHACHA_KEYSIZE - CHACHA_IVSIZE)
|
||||
/*
|
||||
* Derived from OpenBSD's implementation. The rationale is not clear,
|
||||
* but should be conservative enough in safety, and reasonably large for
|
||||
* efficiency.
|
||||
* Fill the region buf of length buflen with random data.
|
||||
*/
|
||||
#define CHACHA_MAXLENGTH 1600000
|
||||
void
|
||||
isc_random_buf(void *buf, size_t buflen)
|
||||
{
|
||||
REQUIRE(buf);
|
||||
REQUIRE(buflen > 0);
|
||||
|
||||
/* ChaCha RNG state */
|
||||
struct isc_rng {
|
||||
unsigned int magic;
|
||||
isc_mem_t *mctx;
|
||||
chacha_ctx cpctx;
|
||||
isc_uint8_t buffer[CHACHA_BUFFERSIZE];
|
||||
size_t have;
|
||||
unsigned int references;
|
||||
int count;
|
||||
isc_entropy_t *entropy; /*%< entropy source */
|
||||
isc_mutex_t lock;
|
||||
};
|
||||
|
||||
static isc_once_t once = ISC_ONCE_INIT;
|
||||
|
||||
static void
|
||||
initialize_rand(void) {
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
unsigned int pid = getpid();
|
||||
|
||||
/*
|
||||
* The low bits of pid generally change faster.
|
||||
* Xor them with the high bits of time which change slowly.
|
||||
*/
|
||||
pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
|
||||
|
||||
srand((unsigned)time(NULL) ^ pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
initialize(void) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc_random_seed(isc_uint32_t seed) {
|
||||
initialize();
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
srand(seed);
|
||||
#elif defined(HAVE_ARC4RANDOM_STIR)
|
||||
/* Formally not necessary... */
|
||||
UNUSED(seed);
|
||||
arc4random_stir();
|
||||
#elif defined(HAVE_ARC4RANDOM_ADDRANDOM)
|
||||
arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
|
||||
RUNTIME_CHECK(CryptGenRandom(isc_random_hcryptprov, (DWORD)buflen, buf));
|
||||
return;
|
||||
#elif defined(HAVE_ARC4RANDOM_BUF)
|
||||
arc4random_buf(buf, buflen);
|
||||
return;
|
||||
#else
|
||||
/*
|
||||
* If arc4random() is available and no corresponding seeding
|
||||
* function arc4random_addrandom() is available, no seeding is
|
||||
* done on such platforms (e.g., OpenBSD 5.5). This is because
|
||||
* the OS itself is supposed to seed the RNG and it is assumed
|
||||
* that no explicit seeding is required.
|
||||
*/
|
||||
UNUSED(seed);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
isc_random_get(isc_uint32_t *val) {
|
||||
REQUIRE(val != NULL);
|
||||
|
||||
initialize();
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
/*
|
||||
* rand()'s lower bits are not random.
|
||||
* rand()'s upper bit is zero.
|
||||
# if defined(__linux__)
|
||||
/* We need to check the availability of the SYS_getrandom syscall at runtime
|
||||
* and fall back to crypto library provider if not available
|
||||
*/
|
||||
#if RAND_MAX >= 0xfffff
|
||||
/* We have at least 20 bits. Use lower 16 excluding lower most 4 */
|
||||
*val = ((((unsigned int)rand()) & 0xffff0) >> 4) |
|
||||
((((unsigned int)rand()) & 0xffff0) << 12);
|
||||
#elif RAND_MAX >= 0x7fff
|
||||
/* We have at least 15 bits. Use lower 10/11 excluding lower most 4 */
|
||||
*val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) |
|
||||
((rand() << 18) & 0xffc00000);
|
||||
#else
|
||||
#error RAND_MAX is too small
|
||||
#endif
|
||||
#else
|
||||
*val = arc4random();
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_uint32_t
|
||||
isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
|
||||
isc_uint32_t rnd;
|
||||
|
||||
REQUIRE(jitter < max || (jitter == 0 && max == 0));
|
||||
|
||||
if (jitter == 0)
|
||||
return (max);
|
||||
|
||||
isc_random_get(&rnd);
|
||||
return (max - rnd % jitter);
|
||||
}
|
||||
|
||||
static void
|
||||
chacha_reinit(isc_rng_t *rng, isc_uint8_t *buffer, size_t n) {
|
||||
REQUIRE(rng != NULL);
|
||||
|
||||
if (n < CHACHA_KEYSIZE + CHACHA_IVSIZE)
|
||||
if (have_getrandom()) {
|
||||
getrandom_buf(buf, buflen);
|
||||
return;
|
||||
|
||||
chacha_keysetup(&rng->cpctx, buffer, CHACHA_KEYSIZE * 8, 0);
|
||||
chacha_ivsetup(&rng->cpctx, buffer + CHACHA_KEYSIZE);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_rng_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_rng_t **rngp) {
|
||||
union {
|
||||
unsigned char rnd[128];
|
||||
isc_uint32_t rnd32[32];
|
||||
} rnd;
|
||||
isc_result_t result;
|
||||
isc_rng_t *rng;
|
||||
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(rngp != NULL && *rngp == NULL);
|
||||
|
||||
if (entropy != NULL) {
|
||||
/*
|
||||
* We accept any quality of random data to avoid blocking.
|
||||
*/
|
||||
result = isc_entropy_getdata(entropy, rnd.rnd,
|
||||
sizeof(rnd), NULL, 0);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
isc_random_get(&rnd.rnd32[i]);
|
||||
}
|
||||
|
||||
rng = isc_mem_get(mctx, sizeof(*rng));
|
||||
if (rng == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
# endif /* defined(__linux__) */
|
||||
|
||||
chacha_reinit(rng, rnd.rnd, sizeof(rnd.rnd));
|
||||
/* Use crypto library as fallback when no other CSPRNG is available */
|
||||
# if defined(OPENSSL)
|
||||
RUNTIME_CHECK(RAND_bytes(buf, buflen) < 1);
|
||||
# elif defined(PKCS11CRYPTO)
|
||||
RUNTIME_CHECK(pk11_rand_bytes(buf, buflen) == ISC_R_SUCCESS);
|
||||
# endif /* if defined(HAVE_ARC4RANDOM_BUF) */
|
||||
|
||||
rng->have = 0;
|
||||
memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
|
||||
|
||||
/* Create lock */
|
||||
result = isc_mutex_init(&rng->lock);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
isc_mem_put(mctx, rng, sizeof(*rng));
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Attach to memory context */
|
||||
rng->mctx = NULL;
|
||||
isc_mem_attach(mctx, &rng->mctx);
|
||||
|
||||
/* Local non-algorithm initializations. */
|
||||
rng->count = 0;
|
||||
rng->entropy = entropy; /* don't have to attach */
|
||||
rng->references = 1;
|
||||
rng->magic = RNG_MAGIC;
|
||||
|
||||
*rngp = rng;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
isc_rng_attach(isc_rng_t *source, isc_rng_t **targetp) {
|
||||
|
||||
REQUIRE(VALID_RNG(source));
|
||||
REQUIRE(targetp != NULL && *targetp == NULL);
|
||||
|
||||
LOCK(&source->lock);
|
||||
source->references++;
|
||||
UNLOCK(&source->lock);
|
||||
|
||||
*targetp = (isc_rng_t *)source;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(isc_rng_t *rng) {
|
||||
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
|
||||
rng->magic = 0;
|
||||
isc_mutex_destroy(&rng->lock);
|
||||
isc_mem_putanddetach(&rng->mctx, rng, sizeof(isc_rng_t));
|
||||
}
|
||||
|
||||
void
|
||||
isc_rng_detach(isc_rng_t **rngp) {
|
||||
isc_rng_t *rng;
|
||||
isc_boolean_t dest = ISC_FALSE;
|
||||
|
||||
REQUIRE(rngp != NULL && VALID_RNG(*rngp));
|
||||
|
||||
rng = *rngp;
|
||||
*rngp = NULL;
|
||||
|
||||
LOCK(&rng->lock);
|
||||
|
||||
INSIST(rng->references > 0);
|
||||
rng->references--;
|
||||
if (rng->references == 0)
|
||||
dest = ISC_TRUE;
|
||||
UNLOCK(&rng->lock);
|
||||
|
||||
if (dest)
|
||||
destroy(rng);
|
||||
}
|
||||
|
||||
static void
|
||||
chacha_rekey(isc_rng_t *rng, u_char *dat, size_t datlen) {
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
|
||||
#ifndef KEYSTREAM_ONLY
|
||||
memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
|
||||
#endif
|
||||
|
||||
/* Fill buffer with the keystream. */
|
||||
chacha_encrypt_bytes(&rng->cpctx, rng->buffer, rng->buffer,
|
||||
CHACHA_BUFFERSIZE);
|
||||
|
||||
/* Mix in optional user provided data. */
|
||||
if (dat != NULL) {
|
||||
size_t i, m;
|
||||
|
||||
m = ISC_MIN(datlen, CHACHA_KEYSIZE + CHACHA_IVSIZE);
|
||||
for (i = 0; i < m; i++)
|
||||
rng->buffer[i] ^= dat[i];
|
||||
}
|
||||
|
||||
/* Immediately reinit for backtracking resistance. */
|
||||
chacha_reinit(rng, rng->buffer,
|
||||
CHACHA_KEYSIZE + CHACHA_IVSIZE);
|
||||
memset(rng->buffer, 0, CHACHA_KEYSIZE + CHACHA_IVSIZE);
|
||||
rng->have = CHACHA_MAXHAVE;
|
||||
}
|
||||
|
||||
static void
|
||||
chacha_getbytes(isc_rng_t *rng, isc_uint8_t *output, size_t length) {
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
uint32_t
|
||||
isc_random_uniform(uint32_t upper_bound)
|
||||
{
|
||||
#if defined(HAVE_ARC4RANDOM_UNIFORM)
|
||||
return(arc4random_uniform(upper_bound));
|
||||
#else /* if defined(HAVE_ARC4RANDOM_UNIFORM) */
|
||||
/* Copy of arc4random_uniform from OpenBSD */
|
||||
u_int32_t r, min;
|
||||
|
||||
while (ISC_UNLIKELY(length > CHACHA_MAXHAVE)) {
|
||||
chacha_rekey(rng, NULL, 0);
|
||||
memmove(output, rng->buffer + CHACHA_BUFFERSIZE - rng->have,
|
||||
CHACHA_MAXHAVE);
|
||||
output += CHACHA_MAXHAVE;
|
||||
length -= CHACHA_MAXHAVE;
|
||||
rng->have = 0;
|
||||
}
|
||||
|
||||
if (rng->have < length)
|
||||
chacha_rekey(rng, NULL, 0);
|
||||
|
||||
memmove(output, rng->buffer + CHACHA_BUFFERSIZE - rng->have, length);
|
||||
/* Clear the copied region. */
|
||||
memset(rng->buffer + CHACHA_BUFFERSIZE - rng->have, 0, length);
|
||||
rng->have -= length;
|
||||
}
|
||||
|
||||
static void
|
||||
chacha_stir(isc_rng_t *rng) {
|
||||
union {
|
||||
unsigned char rnd[128];
|
||||
isc_uint32_t rnd32[32];
|
||||
} rnd;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
|
||||
if (rng->entropy != NULL) {
|
||||
/*
|
||||
* We accept any quality of random data to avoid blocking.
|
||||
*/
|
||||
result = isc_entropy_getdata(rng->entropy, rnd.rnd,
|
||||
sizeof(rnd), NULL, 0);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++)
|
||||
isc_random_get(&rnd.rnd32[i]);
|
||||
}
|
||||
|
||||
chacha_rekey(rng, rnd.rnd, sizeof(rnd.rnd));
|
||||
|
||||
isc_safe_memwipe(rnd.rnd, sizeof(rnd.rnd));
|
||||
|
||||
/* Invalidate the buffer too. */
|
||||
rng->have = 0;
|
||||
memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
|
||||
|
||||
/*
|
||||
* Derived from OpenBSD's implementation. The rationale is not clear,
|
||||
* but should be conservative enough in safety, and reasonably large
|
||||
* for efficiency.
|
||||
*/
|
||||
rng->count = CHACHA_MAXLENGTH;
|
||||
}
|
||||
|
||||
void
|
||||
isc_rng_randombytes(isc_rng_t *rng, void *output, size_t length) {
|
||||
isc_uint8_t *ptr = output;
|
||||
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
REQUIRE(output != NULL && length > 0);
|
||||
|
||||
LOCK(&rng->lock);
|
||||
|
||||
while (ISC_UNLIKELY(length > CHACHA_MAXLENGTH)) {
|
||||
chacha_stir(rng);
|
||||
chacha_getbytes(rng, ptr, CHACHA_MAXLENGTH);
|
||||
ptr += CHACHA_MAXLENGTH;
|
||||
length -= CHACHA_MAXLENGTH;
|
||||
rng->count = 0;
|
||||
}
|
||||
|
||||
rng->count -= length;
|
||||
if (rng->count <= 0)
|
||||
chacha_stir(rng);
|
||||
|
||||
chacha_getbytes(rng, ptr, length);
|
||||
|
||||
UNLOCK(&rng->lock);
|
||||
}
|
||||
|
||||
isc_uint16_t
|
||||
isc_rng_random(isc_rng_t *rng) {
|
||||
isc_uint16_t result;
|
||||
|
||||
isc_rng_randombytes(rng, &result, sizeof(result));
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_uint16_t
|
||||
isc_rng_uniformrandom(isc_rng_t *rng, isc_uint16_t upper_bound) {
|
||||
isc_uint16_t min, r;
|
||||
|
||||
REQUIRE(VALID_RNG(rng));
|
||||
|
||||
if (upper_bound < 2)
|
||||
if (upper_bound < 2) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the range of random numbers [min, 0xffff] be a multiple of
|
||||
* upper_bound and contain at least a half of the 16 bit range.
|
||||
*/
|
||||
|
||||
if (upper_bound > 0x8000)
|
||||
min = 1 + ~upper_bound; /* 0x8000 - upper_bound */
|
||||
else
|
||||
min = (isc_uint16_t)(0x10000 % (isc_uint32_t)upper_bound);
|
||||
#if (ULONG_MAX > 0xffffffffUL)
|
||||
min = 0x100000000UL % upper_bound;
|
||||
#else /* if (ULONG_MAX > 0xffffffffUL) */
|
||||
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
|
||||
if (upper_bound > 0x80000000) {
|
||||
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
|
||||
} else {
|
||||
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
|
||||
min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
|
||||
}
|
||||
#endif /* if (ULONG_MAX > 0xffffffffUL) */
|
||||
|
||||
/*
|
||||
* This could theoretically loop forever but each retry has
|
||||
@@ -432,10 +204,12 @@ isc_rng_uniformrandom(isc_rng_t *rng, isc_uint16_t upper_bound) {
|
||||
* to re-roll.
|
||||
*/
|
||||
for (;;) {
|
||||
isc_rng_randombytes(rng, &r, sizeof(r));
|
||||
if (r >= min)
|
||||
r = isc_random();
|
||||
if (r >= min) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (r % upper_bound);
|
||||
#endif /* if defined(HAVE_ARC4RANDOM_UNIFORM) */
|
||||
}
|
||||
|
Reference in New Issue
Block a user