random.c revision 1.2
1/* $NetBSD: random.c,v 1.2 2018/08/12 13:02:37 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14/*% 15 * ChaCha based random number generator derived from OpenBSD. 16 * 17 * The original copyright follows: 18 * Copyright (c) 1996, David Mazieres <dm@uun.org> 19 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 20 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 21 * 22 * Permission to use, copy, modify, and distribute this software for any 23 * purpose with or without fee is hereby granted, provided that the above 24 * copyright notice and this permission notice appear in all copies. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 27 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 28 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 29 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 30 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 31 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 32 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 33 */ 34 35/*! \file */ 36 37#include <config.h> 38 39#include <stdlib.h> 40#include <time.h> /* Required for time(). */ 41#ifdef HAVE_SYS_TYPES_H 42#include <sys/types.h> 43#endif 44#ifdef HAVE_UNISTD_H 45#include <unistd.h> 46#endif 47 48#include <isc/magic.h> 49#include <isc/mutex.h> 50#include <isc/once.h> 51#include <isc/mem.h> 52#include <isc/entropy.h> 53#include <isc/random.h> 54#include <isc/safe.h> 55#include <isc/string.h> 56#include <isc/util.h> 57 58#define RNG_MAGIC ISC_MAGIC('R', 'N', 'G', 'x') 59#define VALID_RNG(r) ISC_MAGIC_VALID(r, RNG_MAGIC) 60 61#define KEYSTREAM_ONLY 62#include "chacha_private.h" 63 64#define CHACHA_KEYSIZE 32U 65#define CHACHA_IVSIZE 8U 66#define CHACHA_BLOCKSIZE 64 67#define CHACHA_BUFFERSIZE (16 * CHACHA_BLOCKSIZE) 68#define CHACHA_MAXHAVE (CHACHA_BUFFERSIZE - CHACHA_KEYSIZE - CHACHA_IVSIZE) 69/* 70 * Derived from OpenBSD's implementation. The rationale is not clear, 71 * but should be conservative enough in safety, and reasonably large for 72 * efficiency. 73 */ 74#define CHACHA_MAXLENGTH 1600000 75 76/* ChaCha RNG state */ 77struct isc_rng { 78 unsigned int magic; 79 isc_mem_t *mctx; 80 chacha_ctx cpctx; 81 isc_uint8_t buffer[CHACHA_BUFFERSIZE]; 82 size_t have; 83 unsigned int references; 84 int count; 85 isc_entropy_t *entropy; /*%< entropy source */ 86 isc_mutex_t lock; 87}; 88 89static isc_once_t once = ISC_ONCE_INIT; 90 91static void 92initialize_rand(void) { 93#ifndef HAVE_ARC4RANDOM 94 unsigned int pid = getpid(); 95 96 /* 97 * The low bits of pid generally change faster. 98 * Xor them with the high bits of time which change slowly. 99 */ 100 pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff); 101 102 srand((unsigned)time(NULL) ^ pid); 103#endif 104} 105 106static void 107initialize(void) { 108 RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS); 109} 110 111void 112isc_random_seed(isc_uint32_t seed) { 113 initialize(); 114 115#ifndef HAVE_ARC4RANDOM 116 srand(seed); 117#elif defined(HAVE_ARC4RANDOM_STIR) 118 /* Formally not necessary... */ 119 UNUSED(seed); 120 arc4random_stir(); 121#elif defined(HAVE_ARC4RANDOM_ADDRANDOM) 122 arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t)); 123#else 124 /* 125 * If arc4random() is available and no corresponding seeding 126 * function arc4random_addrandom() is available, no seeding is 127 * done on such platforms (e.g., OpenBSD 5.5). This is because 128 * the OS itself is supposed to seed the RNG and it is assumed 129 * that no explicit seeding is required. 130 */ 131 UNUSED(seed); 132#endif 133} 134 135void 136isc_random_get(isc_uint32_t *val) { 137 REQUIRE(val != NULL); 138 139 initialize(); 140 141#ifndef HAVE_ARC4RANDOM 142 /* 143 * rand()'s lower bits are not random. 144 * rand()'s upper bit is zero. 145 */ 146#if RAND_MAX >= 0xfffff 147 /* We have at least 20 bits. Use lower 16 excluding lower most 4 */ 148 *val = ((((unsigned int)rand()) & 0xffff0) >> 4) | 149 ((((unsigned int)rand()) & 0xffff0) << 12); 150#elif RAND_MAX >= 0x7fff 151 /* We have at least 15 bits. Use lower 10/11 excluding lower most 4 */ 152 *val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) | 153 ((rand() << 18) & 0xffc00000); 154#else 155#error RAND_MAX is too small 156#endif 157#else 158 *val = arc4random(); 159#endif 160} 161 162isc_uint32_t 163isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) { 164 isc_uint32_t rnd; 165 166 REQUIRE(jitter < max || (jitter == 0 && max == 0)); 167 168 if (jitter == 0) 169 return (max); 170 171 isc_random_get(&rnd); 172 return (max - rnd % jitter); 173} 174 175static void 176chacha_reinit(isc_rng_t *rng, isc_uint8_t *buffer, size_t n) { 177 REQUIRE(rng != NULL); 178 179 if (n < CHACHA_KEYSIZE + CHACHA_IVSIZE) 180 return; 181 182 chacha_keysetup(&rng->cpctx, buffer, CHACHA_KEYSIZE * 8, 0); 183 chacha_ivsetup(&rng->cpctx, buffer + CHACHA_KEYSIZE); 184} 185 186isc_result_t 187isc_rng_create(isc_mem_t *mctx, isc_entropy_t *entropy, isc_rng_t **rngp) { 188 union { 189 unsigned char rnd[128]; 190 isc_uint32_t rnd32[32]; 191 } rnd; 192 isc_result_t result; 193 isc_rng_t *rng; 194 195 REQUIRE(mctx != NULL); 196 REQUIRE(rngp != NULL && *rngp == NULL); 197 198 if (entropy != NULL) { 199 /* 200 * We accept any quality of random data to avoid blocking. 201 */ 202 result = isc_entropy_getdata(entropy, rnd.rnd, 203 sizeof(rnd), NULL, 0); 204 RUNTIME_CHECK(result == ISC_R_SUCCESS); 205 } else { 206 int i; 207 for (i = 0; i < 32; i++) 208 isc_random_get(&rnd.rnd32[i]); 209 } 210 211 rng = isc_mem_get(mctx, sizeof(*rng)); 212 if (rng == NULL) 213 return (ISC_R_NOMEMORY); 214 215 chacha_reinit(rng, rnd.rnd, sizeof(rnd.rnd)); 216 217 rng->have = 0; 218 memset(rng->buffer, 0, CHACHA_BUFFERSIZE); 219 220 /* Create lock */ 221 result = isc_mutex_init(&rng->lock); 222 if (result != ISC_R_SUCCESS) { 223 isc_mem_put(mctx, rng, sizeof(*rng)); 224 return (result); 225 } 226 227 /* Attach to memory context */ 228 rng->mctx = NULL; 229 isc_mem_attach(mctx, &rng->mctx); 230 231 /* Local non-algorithm initializations. */ 232 rng->count = 0; 233 rng->entropy = entropy; /* don't have to attach */ 234 rng->references = 1; 235 rng->magic = RNG_MAGIC; 236 237 *rngp = rng; 238 239 return (ISC_R_SUCCESS); 240} 241 242void 243isc_rng_attach(isc_rng_t *source, isc_rng_t **targetp) { 244 245 REQUIRE(VALID_RNG(source)); 246 REQUIRE(targetp != NULL && *targetp == NULL); 247 248 LOCK(&source->lock); 249 source->references++; 250 UNLOCK(&source->lock); 251 252 *targetp = (isc_rng_t *)source; 253} 254 255static void 256destroy(isc_rng_t *rng) { 257 258 REQUIRE(VALID_RNG(rng)); 259 260 rng->magic = 0; 261 isc_mutex_destroy(&rng->lock); 262 isc_mem_putanddetach(&rng->mctx, rng, sizeof(isc_rng_t)); 263} 264 265void 266isc_rng_detach(isc_rng_t **rngp) { 267 isc_rng_t *rng; 268 isc_boolean_t dest = ISC_FALSE; 269 270 REQUIRE(rngp != NULL && VALID_RNG(*rngp)); 271 272 rng = *rngp; 273 *rngp = NULL; 274 275 LOCK(&rng->lock); 276 277 INSIST(rng->references > 0); 278 rng->references--; 279 if (rng->references == 0) 280 dest = ISC_TRUE; 281 UNLOCK(&rng->lock); 282 283 if (dest) 284 destroy(rng); 285} 286 287static void 288chacha_rekey(isc_rng_t *rng, u_char *dat, size_t datlen) { 289 REQUIRE(VALID_RNG(rng)); 290 291#ifndef KEYSTREAM_ONLY 292 memset(rng->buffer, 0, CHACHA_BUFFERSIZE); 293#endif 294 295 /* Fill buffer with the keystream. */ 296 chacha_encrypt_bytes(&rng->cpctx, rng->buffer, rng->buffer, 297 CHACHA_BUFFERSIZE); 298 299 /* Mix in optional user provided data. */ 300 if (dat != NULL) { 301 size_t i, m; 302 303 m = ISC_MIN(datlen, CHACHA_KEYSIZE + CHACHA_IVSIZE); 304 for (i = 0; i < m; i++) 305 rng->buffer[i] ^= dat[i]; 306 } 307 308 /* Immediately reinit for backtracking resistance. */ 309 chacha_reinit(rng, rng->buffer, 310 CHACHA_KEYSIZE + CHACHA_IVSIZE); 311 memset(rng->buffer, 0, CHACHA_KEYSIZE + CHACHA_IVSIZE); 312 rng->have = CHACHA_MAXHAVE; 313} 314 315static void 316chacha_getbytes(isc_rng_t *rng, isc_uint8_t *output, size_t length) { 317 REQUIRE(VALID_RNG(rng)); 318 319 while (ISC_UNLIKELY(length > CHACHA_MAXHAVE)) { 320 chacha_rekey(rng, NULL, 0); 321 memmove(output, rng->buffer + CHACHA_BUFFERSIZE - rng->have, 322 CHACHA_MAXHAVE); 323 output += CHACHA_MAXHAVE; 324 length -= CHACHA_MAXHAVE; 325 rng->have = 0; 326 } 327 328 if (rng->have < length) 329 chacha_rekey(rng, NULL, 0); 330 331 memmove(output, rng->buffer + CHACHA_BUFFERSIZE - rng->have, length); 332 /* Clear the copied region. */ 333 memset(rng->buffer + CHACHA_BUFFERSIZE - rng->have, 0, length); 334 rng->have -= length; 335} 336 337static void 338chacha_stir(isc_rng_t *rng) { 339 union { 340 unsigned char rnd[128]; 341 isc_uint32_t rnd32[32]; 342 } rnd; 343 isc_result_t result; 344 345 REQUIRE(VALID_RNG(rng)); 346 347 if (rng->entropy != NULL) { 348 /* 349 * We accept any quality of random data to avoid blocking. 350 */ 351 result = isc_entropy_getdata(rng->entropy, rnd.rnd, 352 sizeof(rnd), NULL, 0); 353 RUNTIME_CHECK(result == ISC_R_SUCCESS); 354 } else { 355 int i; 356 for (i = 0; i < 32; i++) 357 isc_random_get(&rnd.rnd32[i]); 358 } 359 360 chacha_rekey(rng, rnd.rnd, sizeof(rnd.rnd)); 361 362 isc_safe_memwipe(rnd.rnd, sizeof(rnd.rnd)); 363 364 /* Invalidate the buffer too. */ 365 rng->have = 0; 366 memset(rng->buffer, 0, CHACHA_BUFFERSIZE); 367 368 /* 369 * Derived from OpenBSD's implementation. The rationale is not clear, 370 * but should be conservative enough in safety, and reasonably large 371 * for efficiency. 372 */ 373 rng->count = CHACHA_MAXLENGTH; 374} 375 376void 377isc_rng_randombytes(isc_rng_t *rng, void *output, size_t length) { 378 isc_uint8_t *ptr = output; 379 380 REQUIRE(VALID_RNG(rng)); 381 REQUIRE(output != NULL && length > 0); 382 383 LOCK(&rng->lock); 384 385 while (ISC_UNLIKELY(length > CHACHA_MAXLENGTH)) { 386 chacha_stir(rng); 387 chacha_getbytes(rng, ptr, CHACHA_MAXLENGTH); 388 ptr += CHACHA_MAXLENGTH; 389 length -= CHACHA_MAXLENGTH; 390 rng->count = 0; 391 } 392 393 rng->count -= length; 394 if (rng->count <= 0) 395 chacha_stir(rng); 396 397 chacha_getbytes(rng, ptr, length); 398 399 UNLOCK(&rng->lock); 400} 401 402isc_uint16_t 403isc_rng_random(isc_rng_t *rng) { 404 isc_uint16_t result; 405 406 isc_rng_randombytes(rng, &result, sizeof(result)); 407 408 return (result); 409} 410 411isc_uint16_t 412isc_rng_uniformrandom(isc_rng_t *rng, isc_uint16_t upper_bound) { 413 isc_uint16_t min, r; 414 415 REQUIRE(VALID_RNG(rng)); 416 417 if (upper_bound < 2) 418 return (0); 419 420 /* 421 * Ensure the range of random numbers [min, 0xffff] be a multiple of 422 * upper_bound and contain at least a half of the 16 bit range. 423 */ 424 425 if (upper_bound > 0x8000) 426 min = 1 + ~upper_bound; /* 0x8000 - upper_bound */ 427 else 428 min = (isc_uint16_t)(0x10000 % (isc_uint32_t)upper_bound); 429 430 /* 431 * This could theoretically loop forever but each retry has 432 * p > 0.5 (worst case, usually far better) of selecting a 433 * number inside the range we need, so it should rarely need 434 * to re-roll. 435 */ 436 for (;;) { 437 isc_rng_randombytes(rng, &r, sizeof(r)); 438 if (r >= min) 439 break; 440 } 441 442 return (r % upper_bound); 443} 444