"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/isc/random.c" (4 Sep 2020, 4589 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "random.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*
   13  * Portions of isc_random_uniform():
   14  *
   15  * Copyright (c) 1996, David Mazieres <dm@uun.org>
   16  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
   17  *
   18  * Permission to use, copy, modify, and distribute this software for any
   19  * purpose with or without fee is hereby granted, provided that the above
   20  * copyright notice and this permission notice appear in all copies.
   21  *
   22  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   23  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   24  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   25  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   26  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   27  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   28  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   29  */
   30 
   31 #include <inttypes.h>
   32 #include <stdlib.h>
   33 #include <string.h>
   34 #include <unistd.h>
   35 
   36 #include <isc/once.h>
   37 #include <isc/platform.h>
   38 #include <isc/random.h>
   39 #include <isc/result.h>
   40 #include <isc/thread.h>
   41 #include <isc/types.h>
   42 #include <isc/util.h>
   43 
   44 #include "entropy_private.h"
   45 
   46 /*
   47  * The specific implementation for PRNG is included as a C file
   48  * that has to provide a static variable named seed, and a function
   49  * uint32_t next(void) that provides next random number.
   50  *
   51  * The implementation must be thread-safe.
   52  */
   53 
   54 /*
   55  * Two contestants have been considered: the xoroshiro family of the
   56  * functions by Villa&Blackman, and PCG by O'Neill.  After
   57  * consideration, the xoshiro128starstar function has been chosen as
   58  * the uint32_t random number provider because it is very fast and has
   59  * good enough properties for our usage pattern.
   60  */
   61 #include "xoshiro128starstar.c"
   62 
   63 ISC_THREAD_LOCAL isc_once_t isc_random_once = ISC_ONCE_INIT;
   64 
   65 static void
   66 isc_random_initialize(void) {
   67     int useed[4] = { 0, 0, 0, 1 };
   68 #if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
   69     /*
   70      * Set a constant seed to help in problem reproduction should fuzzing
   71      * find a crash or a hang.  The seed array must be non-zero else
   72      * xoshiro128starstar will generate an infinite series of zeroes.
   73      */
   74 #else  /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
   75     isc_entropy_get(useed, sizeof(useed));
   76 #endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
   77     memmove(seed, useed, sizeof(seed));
   78 }
   79 
   80 uint8_t
   81 isc_random8(void) {
   82     RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) ==
   83               ISC_R_SUCCESS);
   84     return (next() & 0xff);
   85 }
   86 
   87 uint16_t
   88 isc_random16(void) {
   89     RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) ==
   90               ISC_R_SUCCESS);
   91     return (next() & 0xffff);
   92 }
   93 
   94 uint32_t
   95 isc_random32(void) {
   96     RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) ==
   97               ISC_R_SUCCESS);
   98     return (next());
   99 }
  100 
  101 void
  102 isc_random_buf(void *buf, size_t buflen) {
  103     int i;
  104     uint32_t r;
  105 
  106     REQUIRE(buf != NULL);
  107     REQUIRE(buflen > 0);
  108 
  109     RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) ==
  110               ISC_R_SUCCESS);
  111 
  112     for (i = 0; i + sizeof(r) <= buflen; i += sizeof(r)) {
  113         r = next();
  114         memmove((uint8_t *)buf + i, &r, sizeof(r));
  115     }
  116     r = next();
  117     memmove((uint8_t *)buf + i, &r, buflen % sizeof(r));
  118     return;
  119 }
  120 
  121 uint32_t
  122 isc_random_uniform(uint32_t upper_bound) {
  123     /* Copy of arc4random_uniform from OpenBSD */
  124     uint32_t r, min;
  125 
  126     RUNTIME_CHECK(isc_once_do(&isc_random_once, isc_random_initialize) ==
  127               ISC_R_SUCCESS);
  128 
  129     if (upper_bound < 2) {
  130         return (0);
  131     }
  132 
  133 #if (ULONG_MAX > 0xffffffffUL)
  134     min = 0x100000000UL % upper_bound;
  135 #else  /* if (ULONG_MAX > 0xffffffffUL) */
  136     /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
  137     if (upper_bound > 0x80000000) {
  138         min = 1 + ~upper_bound; /* 2**32 - upper_bound */
  139     } else {
  140         /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
  141         min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
  142     }
  143 #endif /* if (ULONG_MAX > 0xffffffffUL) */
  144 
  145     /*
  146      * This could theoretically loop forever but each retry has
  147      * p > 0.5 (worst case, usually far better) of selecting a
  148      * number inside the range we need, so it should rarely need
  149      * to re-roll.
  150      */
  151     for (;;) {
  152         r = next();
  153         if (r >= min) {
  154             break;
  155         }
  156     }
  157 
  158     return (r % upper_bound);
  159 }