random.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*%
00019  * ChaCha based random number generator derived from OpenBSD.
00020  *
00021  * The original copyright follows:
00022  * Copyright (c) 1996, David Mazieres <dm@uun.org>
00023  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
00024  * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
00025  *
00026  * Permission to use, copy, modify, and distribute this software for any
00027  * purpose with or without fee is hereby granted, provided that the above
00028  * copyright notice and this permission notice appear in all copies.
00029  *
00030  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00031  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00032  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00033  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00034  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00035  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00036  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00037  */
00038 
00039 /*! \file */
00040 
00041 #include <config.h>
00042 
00043 #include <stdlib.h>
00044 #include <time.h>               /* Required for time(). */
00045 #ifdef HAVE_SYS_TYPES_H
00046 #include <sys/types.h>
00047 #endif
00048 #ifdef HAVE_UNISTD_H
00049 #include <unistd.h>
00050 #endif
00051 
00052 #include <isc/magic.h>
00053 #include <isc/mutex.h>
00054 #include <isc/once.h>
00055 #include <isc/mem.h>
00056 #include <isc/entropy.h>
00057 #include <isc/random.h>
00058 #include <isc/string.h>
00059 #include <isc/util.h>
00060 
00061 #define RNG_MAGIC                       ISC_MAGIC('R', 'N', 'G', 'x')
00062 #define VALID_RNG(r)                    ISC_MAGIC_VALID(r, RNG_MAGIC)
00063 
00064 #define KEYSTREAM_ONLY
00065 #include "chacha_private.h"
00066 
00067 #define CHACHA_KEYSIZE 32U
00068 #define CHACHA_IVSIZE 8U
00069 #define CHACHA_BLOCKSIZE 64
00070 #define CHACHA_BUFFERSIZE (16 * CHACHA_BLOCKSIZE)
00071 
00072 /* ChaCha RNG state */
00073 struct isc_rng {
00074         unsigned int    magic;
00075         isc_mem_t       *mctx;
00076         chacha_ctx      cpctx;
00077         isc_uint8_t     buffer[CHACHA_BUFFERSIZE];
00078         size_t          have;
00079         unsigned int    references;
00080         int             count;
00081         isc_entropy_t   *entropy;       /*%< entropy source */
00082         isc_mutex_t     lock;
00083 };
00084 
00085 static isc_once_t once = ISC_ONCE_INIT;
00086 
00087 static void
00088 initialize_rand(void) {
00089 #ifndef HAVE_ARC4RANDOM
00090         unsigned int pid = getpid();
00091 
00092         /*
00093          * The low bits of pid generally change faster.
00094          * Xor them with the high bits of time which change slowly.
00095          */
00096         pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff);
00097 
00098         srand((unsigned)time(NULL) ^ pid);
00099 #endif
00100 }
00101 
00102 static void
00103 initialize(void) {
00104         RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS);
00105 }
00106 
00107 void
00108 isc_random_seed(isc_uint32_t seed) {
00109         initialize();
00110 
00111 #ifndef HAVE_ARC4RANDOM
00112         srand(seed);
00113 #elif defined(HAVE_ARC4RANDOM_ADDRANDOM)
00114         arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
00115 #else
00116         /*
00117          * If arcrandom() is available and no corresponding seeding
00118          * function arc4random_addrandom() is available, no seeding is
00119          * done on such platforms (e.g., OpenBSD 5.5). This is because
00120          * the OS itself is supposed to seed the RNG and it is assumed
00121          * that no explicit seeding is required.
00122          */
00123 #endif
00124 }
00125 
00126 void
00127 isc_random_get(isc_uint32_t *val) {
00128         REQUIRE(val != NULL);
00129 
00130         initialize();
00131 
00132 #ifndef HAVE_ARC4RANDOM
00133         /*
00134          * rand()'s lower bits are not random.
00135          * rand()'s upper bit is zero.
00136          */
00137 #if RAND_MAX >= 0xfffff
00138         /* We have at least 20 bits.  Use lower 16 excluding lower most 4 */
00139         *val = ((rand() >> 4) & 0xffff) | ((rand() << 12) & 0xffff0000);
00140 #elif RAND_MAX >= 0x7fff
00141         /* We have at least 15 bits.  Use lower 10/11 excluding lower most 4 */
00142         *val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) |
00143                 ((rand() << 18) & 0xffc00000);
00144 #else
00145 #error RAND_MAX is too small
00146 #endif
00147 #else
00148         *val = arc4random();
00149 #endif
00150 }
00151 
00152 isc_uint32_t
00153 isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) {
00154         isc_uint32_t rnd;
00155 
00156         REQUIRE(jitter < max || (jitter == 0 && max == 0));
00157 
00158         if (jitter == 0)
00159                 return (max);
00160 
00161         isc_random_get(&rnd);
00162         return (max - rnd % jitter);
00163 }
00164 
00165 static void
00166 chacha_reinit(isc_rng_t *rng, isc_uint8_t *buffer, size_t n) {
00167         REQUIRE(rng != NULL);
00168 
00169         if (n < CHACHA_KEYSIZE + CHACHA_IVSIZE)
00170                 return;
00171 
00172         chacha_keysetup(&rng->cpctx, buffer, CHACHA_KEYSIZE * 8, 0);
00173         chacha_ivsetup(&rng->cpctx, buffer + CHACHA_KEYSIZE);
00174 }
00175 
00176 isc_result_t
00177 isc_rng_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_rng_t **rngp) {
00178         union {
00179                 unsigned char rnd[128];
00180                 isc_uint32_t rnd32[32];
00181         } rnd;
00182         isc_result_t result;
00183         isc_rng_t *rng;
00184 
00185         REQUIRE(mctx != NULL);
00186         REQUIRE(rngp != NULL && *rngp == NULL);
00187 
00188         if (entropy != NULL) {
00189                 /*
00190                  * We accept any quality of random data to avoid blocking.
00191                  */
00192                 result = isc_entropy_getdata(entropy, rnd.rnd,
00193                                              sizeof(rnd), NULL, 0);
00194                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00195         } else {
00196                 int i;
00197                 for (i = 0; i < 32; i++)
00198                         isc_random_get(&rnd.rnd32[i]);
00199         }
00200 
00201         rng = isc_mem_get(mctx, sizeof(*rng));
00202         if (rng == NULL)
00203                 return (ISC_R_NOMEMORY);
00204 
00205         chacha_reinit(rng, rnd.rnd, sizeof(rnd.rnd));
00206 
00207         rng->have = 0;
00208         memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
00209 
00210         /* Create lock */
00211         result = isc_mutex_init(&rng->lock);
00212         if (result != ISC_R_SUCCESS) {
00213                 isc_mem_put(mctx, rng, sizeof(*rng));
00214                 return (result);
00215         }
00216 
00217         /* Attach to memory context */
00218         rng->mctx = NULL;
00219         isc_mem_attach(mctx, &rng->mctx);
00220 
00221         /* Local non-algorithm initializations. */
00222         rng->count = 0;
00223         rng->entropy = entropy; /* don't have to attach */
00224         rng->references = 1;
00225         rng->magic = RNG_MAGIC;
00226 
00227         *rngp = rng;
00228 
00229         return (ISC_R_SUCCESS);
00230 }
00231 
00232 void
00233 isc_rng_attach(isc_rng_t *source, isc_rng_t **targetp) {
00234 
00235         REQUIRE(VALID_RNG(source));
00236         REQUIRE(targetp != NULL && *targetp == NULL);
00237 
00238         LOCK(&source->lock);
00239         source->references++;
00240         UNLOCK(&source->lock);
00241 
00242         *targetp = (isc_rng_t *)source;
00243 }
00244 
00245 static void
00246 destroy(isc_rng_t *rng) {
00247 
00248         REQUIRE(VALID_RNG(rng));
00249 
00250         rng->magic = 0;
00251         isc_mutex_destroy(&rng->lock);
00252         isc_mem_putanddetach(&rng->mctx, rng, sizeof(isc_rng_t));
00253 }
00254 
00255 void
00256 isc_rng_detach(isc_rng_t **rngp) {
00257         isc_rng_t *rng;
00258         isc_boolean_t dest = ISC_FALSE;
00259 
00260         REQUIRE(rngp != NULL && VALID_RNG(*rngp));
00261 
00262         rng = *rngp;
00263         *rngp = NULL;
00264 
00265         LOCK(&rng->lock);
00266 
00267         INSIST(rng->references > 0);
00268         rng->references--;
00269         if (rng->references == 0)
00270                 dest = ISC_TRUE;
00271         UNLOCK(&rng->lock);
00272 
00273         if (dest)
00274                 destroy(rng);
00275 }
00276 
00277 static void
00278 chacha_rekey(isc_rng_t *rng, u_char *dat, size_t datlen) {
00279         REQUIRE(VALID_RNG(rng));
00280 
00281 #ifndef KEYSTREAM_ONLY
00282         memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
00283 #endif
00284 
00285         /* Fill buffer with the keystream. */
00286         chacha_encrypt_bytes(&rng->cpctx, rng->buffer, rng->buffer,
00287                              CHACHA_BUFFERSIZE);
00288 
00289         /* Mix in optional user provided data. */
00290         if (dat != NULL) {
00291                 size_t i, m;
00292 
00293                 m = ISC_MIN(datlen, CHACHA_KEYSIZE + CHACHA_IVSIZE);
00294                 for (i = 0; i < m; i++)
00295                         rng->buffer[i] ^= dat[i];
00296         }
00297 
00298         /* Immediately reinit for backtracking resistance. */
00299         chacha_reinit(rng, rng->buffer,
00300                       CHACHA_KEYSIZE + CHACHA_IVSIZE);
00301         memset(rng->buffer, 0, CHACHA_KEYSIZE + CHACHA_IVSIZE);
00302         rng->have = CHACHA_BUFFERSIZE - CHACHA_KEYSIZE - CHACHA_IVSIZE;
00303 }
00304 
00305 static inline isc_uint16_t
00306 chacha_getuint16(isc_rng_t *rng) {
00307         isc_uint16_t val;
00308 
00309         REQUIRE(VALID_RNG(rng));
00310 
00311         if (rng->have < sizeof(val))
00312                 chacha_rekey(rng, NULL, 0);
00313 
00314         memmove(&val, rng->buffer + CHACHA_BUFFERSIZE - rng->have,
00315                 sizeof(val));
00316         /* Clear the copied region. */
00317         memset(rng->buffer + CHACHA_BUFFERSIZE - rng->have,
00318                0, sizeof(val));
00319         rng->have -= sizeof(val);
00320 
00321         return (val);
00322 }
00323 
00324 static void
00325 chacha_stir(isc_rng_t *rng) {
00326         union {
00327                 unsigned char rnd[128];
00328                 isc_uint32_t rnd32[32];
00329         } rnd;
00330         isc_result_t result;
00331 
00332         REQUIRE(VALID_RNG(rng));
00333 
00334         if (rng->entropy != NULL) {
00335                 /*
00336                  * We accept any quality of random data to avoid blocking.
00337                  */
00338                 result = isc_entropy_getdata(rng->entropy, rnd.rnd,
00339                                              sizeof(rnd), NULL, 0);
00340                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00341         } else {
00342                 int i;
00343                 for (i = 0; i < 32; i++)
00344                         isc_random_get(&rnd.rnd32[i]);
00345         }
00346 
00347         chacha_rekey(rng, rnd.rnd, sizeof(rnd.rnd));
00348 
00349         /*
00350          * The OpenBSD implementation explicit_bzero()s the random seed
00351          * rnd.rnd at this point, but it may not be required here. This
00352          * memset() may also be optimized away by the compiler as
00353          * rnd.rnd is not used further.
00354          */
00355         memset(rnd.rnd, 0, sizeof(rnd.rnd));
00356 
00357         /* Invalidate the buffer too. */
00358         rng->have = 0;
00359         memset(rng->buffer, 0, CHACHA_BUFFERSIZE);
00360 
00361         /*
00362          * Derived from OpenBSD's implementation.  The rationale is not clear,
00363          * but should be conservative enough in safety, and reasonably large
00364          * for efficiency.
00365          */
00366         rng->count = 1600000;
00367 }
00368 
00369 isc_uint16_t
00370 isc_rng_random(isc_rng_t *rng) {
00371         isc_uint16_t result;
00372 
00373         REQUIRE(VALID_RNG(rng));
00374 
00375         LOCK(&rng->lock);
00376 
00377         rng->count -= sizeof(isc_uint16_t);
00378         if (rng->count <= 0)
00379                 chacha_stir(rng);
00380         result = chacha_getuint16(rng);
00381 
00382         UNLOCK(&rng->lock);
00383 
00384         return (result);
00385 }
00386 
00387 isc_uint16_t
00388 isc_rng_uniformrandom(isc_rng_t *rng, isc_uint16_t upper_bound) {
00389         isc_uint16_t min, r;
00390 
00391         REQUIRE(VALID_RNG(rng));
00392 
00393         if (upper_bound < 2)
00394                 return (0);
00395 
00396         /*
00397          * Ensure the range of random numbers [min, 0xffff] be a multiple of
00398          * upper_bound and contain at least a half of the 16 bit range.
00399          */
00400 
00401         if (upper_bound > 0x8000)
00402                 min = 1 + ~upper_bound; /* 0x8000 - upper_bound */
00403         else
00404                 min = (isc_uint16_t)(0x10000 % (isc_uint32_t)upper_bound);
00405 
00406         /*
00407          * This could theoretically loop forever but each retry has
00408          * p > 0.5 (worst case, usually far better) of selecting a
00409          * number inside the range we need, so it should rarely need
00410          * to re-roll.
00411          */
00412         for (;;) {
00413                 r = isc_rng_random(rng);
00414                 if (r >= min)
00415                         break;
00416         }
00417 
00418         return (r % upper_bound);
00419 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha