File arc4random.c.1.30 of Package rdate
static const char __vcsid[] = "@(#) MirOS contributed arc4random.c (old)"
"\n @(#)rcsid_master: $MirOS: contrib/code/Snippets/arc4random.c,v 1.30 2014/12/20 21:38:07 tg Exp $"
;
/*-
* Arc4 random number generator for OpenBSD.
* Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project by leaving this copyright notice intact.
*/
/*-
* This code is derived from section 17.1 of Applied Cryptography,
* second edition, which describes a stream cipher allegedly
* compatible with RSA Labs "RC4" cipher (the actual description of
* which is a trade secret). The same algorithm is used as a stream
* cipher called "arcfour" in Tatu Ylonen's ssh package.
*
* Here the stream cipher has been modified always to include the time
* when initializing the state. That makes it impossible to
* regenerate the same random sequence twice, so this can't be used
* for encryption, but will generate good random numbers.
*
* RC4 is a registered trademark of RSA Laboratories.
*/
/*-
* Modified by Robert Connolly from OpenBSD lib/libc/crypt/arc4random.c v1.11.
* This is arc4random(3) using urandom.
*/
/*-
* Copyright (c) 2008, 2009, 2010, 2012, 2014
* Thorsten Glaser <tg@mirbsd.org>
* This is arc4random(3) made more portable,
* as well as arc4random_pushb(3) for Cygwin.
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
* is granted to deal in this work without restriction, including un-
* limited rights to use, publicly perform, distribute, sell, modify,
* merge, give away, or sublicence.
*
* This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
* the utmost extent permitted by applicable law, neither express nor
* implied; without malicious intent or gross negligence. In no event
* may a licensor, author or contributor be held liable for indirect,
* direct, other damage, loss, or other issues arising in any way out
* of dealing in the work, even if advised of the possibility of such
* damage or existence of a defect, except proven that it results out
* of said person's immediate fault when using the work as intended.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#if defined(__linux__) && defined(__x86_64__) && defined(__ILP32__)
/* no sysctl on Linux/x32 */
#undef HAVE_SYS_SYSCTL_H
#endif
#if defined(HAVE_SYS_SYSCTL_H) && HAVE_SYS_SYSCTL_H
#include <sys/sysctl.h>
#endif
#include <fcntl.h>
#if defined(HAVE_STDINT_H) && HAVE_STDINT_H
#include <stdint.h>
#elif defined(USE_INTTYPES)
#include <inttypes.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(__CYGWIN__) || defined(WIN32)
#define USE_MS_CRYPTOAPI
#define REDEF_USCORETYPES
#endif
#ifdef USE_MS_CRYPTOAPI
#define WIN32_WINNT 0x400
#define _WIN32_WINNT 0x400
#include <windows.h>
#include <wincrypt.h>
static uint8_t w32_buf[16*16384]; /* force reseed */
static uint8_t w32_hklm[80]; /* registry key (MS, Admin) */
static uint8_t w32_hkcu[256]; /* registry key (per user) */
static struct timeval w32_last; /* last time CGR was used */
static char w32_subkey[] = "SOFTWARE\\Microsoft\\Cryptography\\RNG";
#endif
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef MAX
#define MAX(a,b) (((a)>(b))?(a):(b))
#endif
#ifdef REDEF_USCORETYPES
#define u_int32_t uint32_t
#endif
#ifndef _PATH_URANDOM
#define _PATH_URANDOM "/dev/urandom"
#endif
static struct arc4_stream {
uint8_t i;
uint8_t j;
uint8_t s[256];
} arc4_ctx;
static int rs_initialized;
static pid_t arc4_stir_pid;
static int arc4_count;
static const char __randomdev[] = _PATH_URANDOM;
static uint8_t arc4_getbyte(void);
static void stir_finish(uint8_t);
static void arc4_atexit(void);
static char arc4_writeback(uint8_t *, size_t, char);
#ifndef arc4random_pushk
u_int32_t arc4random(void);
void arc4random_addrandom(u_char *, int);
void arc4random_stir(void);
#if defined(USE_MS_CRYPTOAPI) || defined(OPPORTUNISTIC_ROOT_PUSHB)
uint32_t arc4random_pushb(const void *, size_t);
#endif
#endif
#define NEED_UNIFORM_BUF_PROTO
#if defined(__OpenBSD__) && defined(OpenBSD) && (OpenBSD > 200805)
#undef NEED_UNIFORM_BUF_PROTO
#elif defined(__MirBSD__) && defined(MirBSD) && (MirBSD > 0x0AA4)
#undef NEED_UNIFORM_BUF_PROTO
#endif
#ifdef NEED_UNIFORM_BUF_PROTO
u_int32_t arc4random_uniform(u_int32_t);
void arc4random_buf(void *, size_t);
#endif
static void
arc4_init(void)
{
int n;
for (n = 0; n < 256; n++)
arc4_ctx.s[n] = (uint8_t)n;
arc4_ctx.i = 0;
arc4_ctx.j = 0;
}
static void
arc4_addrandom(const u_char *dat, size_t datlen)
{
size_t n = 0;
uint8_t si;
arc4_ctx.i--;
while (n < 256) {
arc4_ctx.i++;
si = arc4_ctx.s[arc4_ctx.i];
arc4_ctx.j = (uint8_t)(arc4_ctx.j + si + dat[n++ % datlen]);
arc4_ctx.s[arc4_ctx.i] = arc4_ctx.s[arc4_ctx.j];
arc4_ctx.s[arc4_ctx.j] = si;
}
arc4_ctx.i++;
arc4_ctx.j = arc4_ctx.i;
}
#if defined(USE_MS_CRYPTOAPI)
#define RNDEV_BYTES 128
#elif defined(__INTERIX)
#define RNDEV_BYTES 4 /* slow /dev/urandom */
#elif defined(__OpenBSD__)
#define RNDEV_BYTES (256 - (sizeof(struct timeval) + sizeof(pid_t)))
#elif defined(__CYGWIN__)
#define RNDEV_BYTES 64 /* /dev/urandom probably CryptoAPI */
#elif defined(__FreeBSD__)
#define RNDEV_BYTES 16 /* Yarrow has few state */
#elif defined(__GLIBC__)
#define RNDEV_BYTES 16 /* requested by maintainers */
#else
#define RNDEV_BYTES 8 /* unknown OS? */
#endif
static void
arc4_stir(void)
{
int fd;
struct {
struct timeval tv;
pid_t pid;
u_int rnd[(RNDEV_BYTES + sizeof(u_int) - 1) / sizeof(u_int)];
} rdat;
size_t sz = 0;
gettimeofday(&rdat.tv, NULL);
rdat.pid = getpid();
memcpy(rdat.rnd, __vcsid, MIN(sizeof(__vcsid), sizeof(rdat.rnd)));
#ifdef USE_MS_CRYPTOAPI
if (arc4_writeback((char *)rdat.rnd, sizeof(rdat.rnd), 1))
goto stir_okay;
#endif
/* /dev/urandom is a multithread interface, sysctl is not. */
/* Try to use /dev/urandom before sysctl. */
fd = open(__randomdev, O_RDONLY);
if (fd != -1) {
sz = (size_t)read(fd, rdat.rnd, sizeof(rdat.rnd));
close(fd);
}
if (sz > sizeof(rdat.rnd))
sz = 0;
if (fd == -1 || sz != sizeof(rdat.rnd)) {
/* /dev/urandom failed? Maybe we're in a chroot. */
#if /* Linux */ defined(_LINUX_SYSCTL_H) || \
/* OpenBSD */ (defined(CTL_KERN) && defined(KERN_ARND))
int mib[3], nmib = 3;
size_t i = sz / sizeof(u_int), len;
#ifdef _LINUX_SYSCTL_H
mib[0] = CTL_KERN;
mib[1] = KERN_RANDOM;
mib[2] = RANDOM_UUID;
#else
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
nmib = 2;
#endif
while (i < sizeof(rdat.rnd) / sizeof(u_int)) {
len = sizeof(u_int);
if (sysctl(mib, nmib, &rdat.rnd[i++], &len,
NULL, 0) == -1) {
fputs("warning: no entropy source\n", stderr);
break;
}
}
#else
/* XXX kFreeBSD doesn't seem to have KERN_ARND or so */
;
#endif
}
#ifdef USE_MS_CRYPTOAPI
stir_okay:
#endif
fd = arc4_getbyte();
/*
* Time to give up. If no entropy could be found then we will just
* use gettimeofday and getpid.
*/
arc4_addrandom((u_char *)&rdat, sizeof(rdat));
stir_finish(fd);
}
static void
stir_finish(uint8_t av)
{
size_t n;
uint8_t tb[16];
arc4_stir_pid = getpid();
/*
* Discard early keystream, as per recommendations in:
* http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
* "(Not So) Random Shuffles of RC4" by Ilya Mironov says to
* drop at least 256 * 2 bytes, with 256 * 12 being suggested.
* We also discard a randomly fuzzed amount.
*/
n = 256 * 12 + (arc4_getbyte() & 0x0FU) + (av & 0xF0U);
av &= 0x0FU;
while (n--)
arc4_getbyte();
while (++n < sizeof(tb))
tb[n] = arc4_getbyte();
if (arc4_writeback(tb, sizeof(tb), 0))
arc4_getbyte();
while (av--)
arc4_getbyte();
arc4_count = 1600000;
}
static uint8_t
arc4_getbyte(void)
{
uint8_t si, sj;
arc4_ctx.i++;
si = arc4_ctx.s[arc4_ctx.i];
arc4_ctx.j = (uint8_t)(arc4_ctx.j + si);
sj = arc4_ctx.s[arc4_ctx.j];
arc4_ctx.s[arc4_ctx.i] = sj;
arc4_ctx.s[arc4_ctx.j] = si;
return (arc4_ctx.s[(si + sj) & 0xff]);
}
static uint32_t
arc4_getword(void)
{
uint32_t val;
val = (uint32_t)arc4_getbyte() << 24;
val |= (uint32_t)arc4_getbyte() << 16;
val |= (uint32_t)arc4_getbyte() << 8;
val |= (uint32_t)arc4_getbyte();
return (val);
}
void
arc4random_stir(void)
{
if (!rs_initialized) {
arc4_init();
rs_initialized = 1;
atexit(arc4_atexit);
}
arc4_stir();
}
void
arc4random_addrandom(u_char *dat, int datlen)
{
if (!rs_initialized)
arc4random_stir();
arc4_addrandom(dat, datlen);
}
u_int32_t
arc4random(void)
{
arc4_count -= 4;
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid())
arc4random_stir();
return arc4_getword();
}
/*
* Returns 0 if write error; 0 if do_rd and read error;
* 1 if !do_rd and read error but not write error;
* 1 if no error occured.
*/
static char
arc4_writeback(uint8_t *buf, size_t len, char do_rd)
{
#ifdef USE_MS_CRYPTOAPI
static char has_provider = 0;
static HCRYPTPROV p;
HKEY hKeyLM, hKeyCU;
DWORD ksz;
char rc = 6, has_rkey = 0, w32_a4b[16];
size_t i, j, xlen;
struct timeval tv;
for (i = 0; i < sizeof(w32_a4b); ++i)
w32_a4b[i] = arc4_getbyte();
for (i = arc4_getbyte() & 15; i; --i)
arc4_getbyte();
ksz = sizeof(w32_buf);
if ((/* read-write */ RegOpenKeyEx(HKEY_LOCAL_MACHINE, w32_subkey,
0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKeyLM) == ERROR_SUCCESS ||
/* try read-only */ RegOpenKeyEx(HKEY_LOCAL_MACHINE, w32_subkey,
0, KEY_QUERY_VALUE, &hKeyLM) == ERROR_SUCCESS) && /* get value */
(RegQueryValueEx(hKeyLM, "Seed", NULL, NULL, w32_buf, &ksz) ==
ERROR_SUCCESS) && /* got any content? */ ksz) {
/* we got HKLM key, read-write or read-only */
has_rkey |= 1;
/* move content to destination */
memset(w32_hklm, '\0', sizeof(w32_hklm));
for (i = 0; i < MAX(ksz, sizeof(w32_hklm)); ++i)
w32_hklm[i % sizeof(w32_hklm)] ^= w32_buf[i % ksz];
}
ksz = sizeof(w32_buf);
if ((/* read-write */ RegCreateKeyEx(HKEY_CURRENT_USER, w32_subkey,
0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hKeyCU,
NULL) == ERROR_SUCCESS || /* R/O */ RegOpenKeyEx(HKEY_CURRENT_USER,
w32_subkey, 0, KEY_QUERY_VALUE, &hKeyLM) == ERROR_SUCCESS) &&
/* get value */ (RegQueryValueEx(hKeyLM, "Seed", NULL, NULL,
w32_buf, &ksz) == ERROR_SUCCESS) && /* got any content? */ ksz) {
/* we got HKCU key, created, read-write or read-only */
has_rkey |= 2;
/* move content to destination */
memset(w32_hkcu, '\0', sizeof(w32_hkcu));
for (i = 0; i < MAX(ksz, sizeof(w32_hkcu)); ++i)
w32_hkcu[i % sizeof(w32_hkcu)] ^= w32_buf[i % ksz];
}
if (!do_rd)
goto nogen_out;
if (has_rkey && gettimeofday(&tv, NULL) == 0) {
/* we have registry key; rate-limit CryptGenRandom */
if (tv.tv_sec - w32_last.tv_sec < 128 + (arc4_getbyte() & 127))
goto nogen_out;
/* nope, more than 2-4 minutes, call it */
w32_last.tv_sec = tv.tv_sec;
}
if (!has_provider) {
if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL, 0)) {
if ((HRESULT)GetLastError() != NTE_BAD_KEYSET)
goto nogen_out;
if (!CryptAcquireContext(&p, NULL, NULL, PROV_RSA_FULL,
CRYPT_NEWKEYSET))
goto nogen_out;
}
has_provider = 1;
}
i = 0;
while (i < 256)
w32_buf[i++] = arc4_getbyte();
if (!CryptGenRandom(p, sizeof(w32_buf), w32_buf)) {
w32_last.tv_sec = 0;
nogen_out:
rc |= 1;
memset(w32_buf, '\0', 256);
}
xlen = MIN(sizeof(w32_buf) - sizeof(w32_hklm) - sizeof(w32_hkcu) -
sizeof(w32_a4b), len);
j = xlen + sizeof(w32_hklm) + sizeof(w32_hkcu) + sizeof(w32_a4b);
for (i = 0; i < MAX(j, len); ++i)
w32_buf[i % j] ^= w32_hklm[i % sizeof(w32_hklm)] ^
w32_hkcu[i % sizeof(w32_hkcu)] ^ buf[i % len] ^
arc4_getbyte();
if (has_rkey & 1) {
if (RegSetValueEx(hKeyLM, "Seed", 0, REG_BINARY,
w32_buf, sizeof(w32_hklm)) == ERROR_SUCCESS)
rc &= ~2;
RegCloseKey(hKeyLM);
}
if (has_rkey & 2) {
if (RegSetValueEx(hKeyCU, "Seed", 0, REG_BINARY,
w32_buf + sizeof(w32_hklm), sizeof(w32_hkcu)) ==
ERROR_SUCCESS)
rc &= ~4;
RegCloseKey(hKeyCU);
}
for (i = 0; i < sizeof(w32_a4b); ++i)
w32_a4b[i] ^= w32_buf[sizeof(w32_hklm) + sizeof(w32_hkcu) + i];
arc4_addrandom(w32_a4b, sizeof(w32_a4b));
i = sizeof(w32_hklm) + sizeof(w32_hkcu) + sizeof(w32_a4b);
while (len) {
j = MIN(len, xlen);
memcpy(buf, w32_buf + i, j);
buf += j;
len -= j;
}
memset(w32_buf, '\0', sizeof(w32_buf));
return (
/* read error occured */
(!has_rkey && (rc & 1)) ? 0 :
/* don't care about write errors */
!do_rd ? 1 :
/* couldn't write */
(rc & 6) == 6 ? 0 :
/* at least one RegSetValueEx succeeded */
1);
#elif defined(arc4random_pushk)
uint32_t num;
num = arc4random_pushk(buf, len);
memcpy(buf, &num, sizeof(num));
return (do_rd ? 0 : 1);
#else
int fd;
if ((fd = open(__randomdev, O_WRONLY)) != -1) {
if (write(fd, buf, len) < 4)
do_rd = 1;
close(fd);
}
return (do_rd || fd == -1 ? 0 : 1);
#endif
}
#if defined(USE_MS_CRYPTOAPI) || defined(arc4random_pushk) || \
defined(OPPORTUNISTIC_ROOT_PUSHB)
uint32_t
arc4random_pushb(const void *src, size_t len)
{
size_t rlen;
union {
uint8_t buf[256];
struct {
struct timeval tv;
const void *sp, *dp;
size_t sz;
uint32_t vu;
} s;
uint32_t xbuf;
} idat;
uint32_t res = 1;
if (!rs_initialized) {
arc4_init();
rs_initialized = 1;
}
idat.s.sp = &idat;
idat.s.dp = src;
idat.s.sz = len;
idat.s.vu = arc4_getword();
gettimeofday(&idat.s.tv, NULL);
rlen = MAX(sizeof(idat.s), len);
while (rlen--)
idat.buf[rlen % sizeof(idat.buf)] ^=
((const uint8_t *)src)[rlen % len];
rlen = MIN(sizeof(idat), MAX(sizeof(idat.s), len));
if (arc4_writeback((void *)&idat, rlen, 1))
res = 0;
arc4_addrandom((void *)&idat, rlen);
rlen = arc4_getbyte() & 1;
if (res)
res = idat.xbuf;
else
/* we got entropy from the kernel, so consider us stirred */
stir_finish(idat.buf[5]);
if (rlen)
(void)arc4_getbyte();
return (res ^ arc4_getword());
}
#endif
static void
arc4_atexit(void)
{
struct {
pid_t spid;
int cnt;
uint8_t carr[240];
} buf;
int i = 0;
while (i < 240)
buf.carr[i++] = arc4_getbyte();
buf.spid = arc4_stir_pid;
buf.cnt = arc4_count;
arc4_writeback((uint8_t *)&buf, sizeof(buf), 0);
}
void
arc4random_buf(void *_buf, size_t n)
{
uint8_t *buf = (uint8_t *)_buf;
if (!rs_initialized || arc4_stir_pid != getpid())
arc4random_stir();
buf[0] = arc4_getbyte() % 3;
while (buf[0]--)
(void)arc4_getbyte();
while (n--) {
if (--arc4_count <= 0)
arc4_stir();
buf[n] = arc4_getbyte();
}
}
/*-
* Written by Damien Miller.
* With simplifications by Jinmei Tatuya.
*/
/*
* Calculate a uniformly distributed random number less than
* upper_bound avoiding "modulo bias".
*
* Uniformity is achieved by generating new random numbers
* until the one returned is outside the range
* [0, 2^32 % upper_bound[. This guarantees the selected
* random number will be inside the range
* [2^32 % upper_bound, 2^32[ which maps back to
* [0, upper_bound[ after reduction modulo upper_bound.
*/
uint32_t
arc4random_uniform(uint32_t upper_bound)
{
uint32_t r, min;
if (upper_bound < 2)
return (0);
#if defined(ULONG_MAX) && (ULONG_MAX > 0xFFFFFFFFUL)
min = 0x100000000UL % upper_bound;
#else
/* calculate (2^32 % upper_bound) avoiding 64-bit math */
if (upper_bound > 0x80000000U)
/* 2^32 - upper_bound (only one "value area") */
min = 1 + ~upper_bound;
else
/* ((2^32 - x) % x) == (2^32 % x) when x <= 2^31 */
min = (0xFFFFFFFFU - upper_bound + 1) % upper_bound;
#endif
/*
* 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 (at all).
*/
arc4_count -= 4;
if (!rs_initialized || arc4_stir_pid != getpid() || arc4_count <= 0)
arc4random_stir();
if (arc4_getbyte() & 1)
(void)arc4_getbyte();
do {
r = arc4_getword();
} while (r < min);
return (r % upper_bound);
}