random.c revision 0c27b3fe77ac1d5094ba3521e8142d9e7973133f
/*
* Copyright (C) 1999-2005, 2007, 2009, 2013, 2014, 2016 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/*%
* ChaCha based random number generator derived from OpenBSD.
*
* 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*! \file */
#include <config.h>
#include <stdlib.h>
#include <time.h> /* Required for time(). */
#ifdef HAVE_SYS_TYPES_H
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#define KEYSTREAM_ONLY
#include "chacha_private.h"
#define CHACHA_KEYSIZE 32U
#define CHACHA_IVSIZE 8U
#define CHACHA_BLOCKSIZE 64
/* ChaCha RNG state */
struct isc_rng {
unsigned int magic;
unsigned int references;
int count;
};
static void
initialize_rand(void) {
#ifndef HAVE_ARC4RANDOM
/*
* The low bits of pid generally change faster.
* Xor them with the high bits of time which change slowly.
*/
#endif
}
static void
initialize(void) {
}
void
initialize();
#ifndef HAVE_ARC4RANDOM
#elif defined(HAVE_ARC4RANDOM_ADDRANDOM)
#else
/*
* If arcrandom() 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.
*/
#endif
}
void
initialize();
#ifndef HAVE_ARC4RANDOM
/*
* rand()'s lower bits are not random.
* rand()'s upper bit is zero.
*/
#if RAND_MAX >= 0xfffff
/* We have at least 20 bits. Use lower 16 excluding lower most 4 */
/* We have at least 15 bits. Use lower 10/11 excluding lower most 4 */
#else
#endif
#else
*val = arc4random();
#endif
}
if (jitter == 0)
return (max);
}
static void
if (n < CHACHA_KEYSIZE + CHACHA_IVSIZE)
return;
}
union {
unsigned char rnd[128];
} rnd;
/*
* We accept any quality of random data to avoid blocking.
*/
} else {
int i;
for (i = 0; i < 32; i++)
}
return (ISC_R_NOMEMORY);
/* Create lock */
if (result != ISC_R_SUCCESS) {
return (result);
}
/* Attach to memory context */
/* Local non-algorithm initializations. */
return (ISC_R_SUCCESS);
}
void
source->references++;
}
static void
}
void
rng->references--;
if (rng->references == 0)
if (dest)
}
static void
#ifndef KEYSTREAM_ONLY
#endif
/* Fill buffer with the keystream. */
/* Mix in optional user provided data. */
size_t i, m;
for (i = 0; i < m; i++)
}
/* Immediately reinit for backtracking resistance. */
}
static inline isc_uint16_t
sizeof(val));
/* Clear the copied region. */
0, sizeof(val));
return (val);
}
static void
union {
unsigned char rnd[128];
} rnd;
/*
* We accept any quality of random data to avoid blocking.
*/
} else {
int i;
for (i = 0; i < 32; i++)
}
/*
* The OpenBSD implementation explicit_bzero()s the random seed
* rnd.rnd at this point, but it may not be required here. This
* memset() may also be optimized away by the compiler as
* rnd.rnd is not used further.
*/
/* Invalidate the buffer too. */
/*
* Derived from OpenBSD's implementation. The rationale is not clear,
* but should be conservative enough in safety, and reasonably large
* for efficiency.
*/
}
return (result);
}
isc_uint16_t min, r;
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)
else
/*
* This could theoretically loop forever but each retry has
* p > 0.5 (worst case, usually far better) of selecting a
* number inside the range we need, so it should rarely need
* to re-roll.
*/
for (;;) {
r = isc_rng_random(rng);
if (r >= min)
break;
}
return (r % upper_bound);
}