Update userland arc4random() with OpenBSD's Chacha20 based arc4random().
ObsoleteFiles.inc: Remove manual pages for arc4random_addrandom(3) and arc4random_stir(3). contrib/ntp/lib/isc/random.c: contrib/ntp/sntp/libevent/evutil_rand.c: Eliminate in-tree usage of arc4random_addrandom(). crypto/heimdal/lib/roken/rand.c: crypto/openssh/config.h: Eliminate in-tree usage of arc4random_stir(). include/stdlib.h: Remove arc4random_stir() and arc4random_addrandom() prototypes, provide temporary shims for transistion period. lib/libc/gen/Makefile.inc: Hook arc4random-compat.c to build, add hint for Chacha20 source for kernel, and remove arc4random_addrandom(3) and arc4random_stir(3) links. lib/libc/gen/arc4random.c: Adopt OpenBSD arc4random.c,v 1.54 with bare minimum changes, use the sys/crypto/chacha20 implementation of keystream. lib/libc/gen/Symbol.map: Remove arc4random_stir and arc4random_addrandom interfaces. lib/libc/gen/arc4random.h: Adopt OpenBSD arc4random.h,v 1.4 but provide _ARC4_LOCK of our own. lib/libc/gen/arc4random.3: Adopt OpenBSD arc4random.3,v 1.35 but keep FreeBSD r114444 and r118247. lib/libc/gen/arc4random-compat.c: Compatibility shims for arc4random_stir and arc4random_addrandom functions to preserve ABI. Log once when called but do nothing otherwise. lib/libc/gen/getentropy.c: lib/libc/include/libc_private.h: Fold __arc4_sysctl into getentropy.c (renamed to arnd_sysctl). Remove from libc_private.h as a result. sys/crypto/chacha20/chacha.c: sys/crypto/chacha20/chacha.h: Make it possible to use the kernel implementation in libc. PR: 182610 Reviewed by: cem, markm Obtained from: OpenBSD Relnotes: yes Differential Revision: https://reviews.freebsd.org/D16760
This commit is contained in:
parent
38a13e9002
commit
c1e80940f3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=338059
@ -38,6 +38,9 @@
|
||||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20180819: Remove deprecated arc4random(3) stir/addrandom interfaces
|
||||
OLD_FILES+=usr/share/man/man3/arc4random_addrandom.3.gz
|
||||
OLD_FILES+=usr/share/man/man3/arc4random_stir.3.gz
|
||||
# 20180819: send-pr(1) placeholder removal
|
||||
OLD_FILES+=usr/bin/send-pr
|
||||
# 20180725: Cleanup old libcasper.so.0
|
||||
|
@ -67,8 +67,6 @@ isc_random_seed(isc_uint32_t seed)
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
srand(seed);
|
||||
#else
|
||||
arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -195,8 +195,6 @@ evutil_secure_rng_get_bytes(void *buf, size_t n)
|
||||
void
|
||||
evutil_secure_rng_add_bytes(const char *buf, size_t n)
|
||||
{
|
||||
arc4random_addrandom((unsigned char*)buf,
|
||||
n>(size_t)INT_MAX ? INT_MAX : (int)n);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -37,7 +37,6 @@ void ROKEN_LIB_FUNCTION
|
||||
rk_random_init(void)
|
||||
{
|
||||
#if defined(HAVE_ARC4RANDOM)
|
||||
arc4random_stir();
|
||||
#elif defined(HAVE_SRANDOMDEV)
|
||||
srandomdev();
|
||||
#elif defined(HAVE_RANDOM)
|
||||
|
@ -191,7 +191,7 @@
|
||||
#define HAVE_ARC4RANDOM_BUF 1
|
||||
|
||||
/* Define to 1 if you have the `arc4random_stir' function. */
|
||||
#define HAVE_ARC4RANDOM_STIR 1
|
||||
/* #undef HAVE_ARC4RANDOM_STIR */
|
||||
|
||||
/* Define to 1 if you have the `arc4random_uniform' function. */
|
||||
#define HAVE_ARC4RANDOM_UNIFORM 1
|
||||
|
@ -250,11 +250,16 @@ extern void (*malloc_message)(void *, const char *);
|
||||
void abort2(const char *, int, void **) __dead2;
|
||||
__uint32_t
|
||||
arc4random(void);
|
||||
void arc4random_addrandom(unsigned char *, int);
|
||||
void arc4random_buf(void *, size_t);
|
||||
void arc4random_stir(void);
|
||||
__uint32_t
|
||||
arc4random_uniform(__uint32_t);
|
||||
|
||||
#if !defined(BURN_BRIDGES)
|
||||
/* Deprecated arc4random() functions */
|
||||
#define arc4random_stir()
|
||||
#define arc4random_addrandom(a,b)
|
||||
#endif
|
||||
|
||||
#ifdef __BLOCKS__
|
||||
int atexit_b(void (^ _Nonnull)(void));
|
||||
void *bsearch_b(const void *, const void *, size_t,
|
||||
|
@ -16,6 +16,7 @@ SRCS+= __getosreldate.c \
|
||||
_thread_init.c \
|
||||
alarm.c \
|
||||
arc4random.c \
|
||||
arc4random-compat.c \
|
||||
arc4random_uniform.c \
|
||||
assert.c \
|
||||
auxv.c \
|
||||
@ -166,6 +167,8 @@ SRCS+= devname-compat11.c \
|
||||
unvis-compat.c
|
||||
.endif
|
||||
|
||||
CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20
|
||||
|
||||
.PATH: ${SRCTOP}/contrib/libc-pwcache
|
||||
SRCS+= pwcache.c pwcache.h
|
||||
|
||||
@ -316,9 +319,7 @@ MAN+= alarm.3 \
|
||||
vis.3 \
|
||||
wordexp.3
|
||||
|
||||
MLINKS+=arc4random.3 arc4random_addrandom.3 \
|
||||
arc4random.3 arc4random_stir.3 \
|
||||
arc4random.3 arc4random_buf.3 \
|
||||
MLINKS+=arc4random.3 arc4random_buf.3 \
|
||||
arc4random.3 arc4random_uniform.3
|
||||
MLINKS+=ctermid.3 ctermid_r.3
|
||||
MLINKS+=devname.3 devname_r.3
|
||||
|
@ -65,8 +65,6 @@ FBSD_1.0 {
|
||||
pthread_testcancel;
|
||||
alarm;
|
||||
arc4random;
|
||||
arc4random_addrandom;
|
||||
arc4random_stir;
|
||||
__assert;
|
||||
check_utility_compat;
|
||||
clock;
|
||||
|
72
lib/libc/gen/arc4random-compat.c
Normal file
72
lib/libc/gen/arc4random-compat.c
Normal file
@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2018 Google LLC
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <syslog.h>
|
||||
|
||||
/*
|
||||
* The following functions were removed from OpenBSD for good reasons:
|
||||
*
|
||||
* - arc4random_stir()
|
||||
* - arc4random_addrandom()
|
||||
*
|
||||
* On FreeBSD, for backward ABI compatibility, we provide two wrapper which
|
||||
* logs this event and returns.
|
||||
*/
|
||||
|
||||
void __arc4random_stir_fbsd11(void);
|
||||
void __arc4random_addrandom_fbsd11(u_char *, int);
|
||||
|
||||
void
|
||||
__arc4random_stir_fbsd11(void)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
syslog(LOG_DEBUG, "Deprecated function arc4random_stir() called");
|
||||
warned = true;
|
||||
}
|
||||
|
||||
void
|
||||
__arc4random_addrandom_fbsd11(u_char * dummy1 __unused, int dummy2 __unused)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
syslog(LOG_DEBUG, "Deprecated function arc4random_addrandom() called");
|
||||
warned = true;
|
||||
}
|
||||
|
||||
__sym_compat(arc4random_stir, __arc4random_stir_fbsd11, FBSD_1.0);
|
||||
__sym_compat(arc4random_addrandom, __arc4random_addrandom_fbsd11, FBSD_1.0);
|
@ -1,4 +1,5 @@
|
||||
.\" $OpenBSD: arc4random.3,v 1.2 1997/04/27 22:40:25 angelos Exp $
|
||||
.\" $OpenBSD: arc4random.3,v 1.35 2014/11/25 16:45:24 millert Exp $
|
||||
.\"
|
||||
.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
@ -30,16 +31,14 @@
|
||||
.\" Manual page, using -mandoc macros
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd April 15, 1997
|
||||
.Dd July 19, 2014
|
||||
.Dt ARC4RANDOM 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm arc4random ,
|
||||
.Nm arc4random_buf ,
|
||||
.Nm arc4random_uniform ,
|
||||
.Nm arc4random_stir ,
|
||||
.Nm arc4random_addrandom
|
||||
.Nd arc4 random number generator
|
||||
.Nm arc4random_uniform
|
||||
.Nd random number generator
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
@ -50,20 +49,36 @@
|
||||
.Fn arc4random_buf "void *buf" "size_t nbytes"
|
||||
.Ft uint32_t
|
||||
.Fn arc4random_uniform "uint32_t upper_bound"
|
||||
.Ft void
|
||||
.Fn arc4random_stir "void"
|
||||
.Ft void
|
||||
.Fn arc4random_addrandom "unsigned char *dat" "int datlen"
|
||||
.Sh DESCRIPTION
|
||||
This family of functions provides higher quality data than those
|
||||
described in
|
||||
.Xr rand 3 ,
|
||||
.Xr random 3 ,
|
||||
and
|
||||
.Xr rand48 3 .
|
||||
.Pp
|
||||
Use of these functions is encouraged for almost all random number
|
||||
consumption because the other interfaces are deficient in either
|
||||
quality, portability, standardization, or availability.
|
||||
These functions can be called in almost all coding environments,
|
||||
including
|
||||
.Xr pthreads 3
|
||||
and
|
||||
.Xr chroot 2 .
|
||||
.Pp
|
||||
High quality 32-bit pseudo-random numbers are generated very quickly.
|
||||
On each call, a cryptographic pseudo-random number generator is used
|
||||
to generate a new result.
|
||||
One data pool is used for all consumers in a process, so that consumption
|
||||
under program flow can act as additional stirring.
|
||||
The subsystem is re-seeded from the kernel random number subsystem using
|
||||
.Xr getentropy 2
|
||||
on a regular basis, and also upon
|
||||
.Xr fork 2 .
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4random
|
||||
function uses the key stream generator employed by the
|
||||
arc4 cipher, which uses 8*8 8 bit S-Boxes.
|
||||
The S-Boxes
|
||||
can be in about
|
||||
.if t 2\u\s71700\s10\d
|
||||
.if n (2**1700)
|
||||
states.
|
||||
function returns a single 32-bit value.
|
||||
The
|
||||
.Fn arc4random
|
||||
function returns pseudo-random numbers in the range of 0 to
|
||||
@ -75,33 +90,24 @@ and
|
||||
.Xr random 3 .
|
||||
.Pp
|
||||
.Fn arc4random_buf
|
||||
function fills the region
|
||||
fills the region
|
||||
.Fa buf
|
||||
of length
|
||||
.Fa nbytes
|
||||
with ARC4-derived random data.
|
||||
with random data.
|
||||
.Pp
|
||||
.Fn arc4random_uniform
|
||||
will return a uniformly distributed random number less than
|
||||
will return a single 32-bit value, uniformly distributed but less than
|
||||
.Fa upper_bound .
|
||||
.Fn arc4random_uniform
|
||||
is recommended over constructions like
|
||||
This is recommended over constructions like
|
||||
.Dq Li arc4random() % upper_bound
|
||||
as it avoids "modulo bias" when the upper bound is not a power of two.
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4random_stir
|
||||
function reads data from
|
||||
.Pa /dev/urandom
|
||||
and uses it to permute the S-Boxes via
|
||||
.Fn arc4random_addrandom .
|
||||
.Pp
|
||||
There is no need to call
|
||||
.Fn arc4random_stir
|
||||
before using
|
||||
.Fn arc4random
|
||||
functions family, since
|
||||
they automatically initialize themselves.
|
||||
In the worst case, this function may consume multiple iterations
|
||||
to ensure uniformity; see the source code to understand the problem
|
||||
and solution.
|
||||
.Sh RETURN VALUES
|
||||
These functions are always successful, and no return value is
|
||||
reserved to indicate an error.
|
||||
.Sh EXAMPLES
|
||||
The following produces a drop-in replacement for the traditional
|
||||
.Fn rand
|
||||
@ -113,15 +119,25 @@ functions using
|
||||
.Dl "#define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))"
|
||||
.Sh SEE ALSO
|
||||
.Xr rand 3 ,
|
||||
.Xr random 3 ,
|
||||
.Xr srandomdev 3
|
||||
.Xr rand48 3 ,
|
||||
.Xr random 3
|
||||
.Sh HISTORY
|
||||
.Pa RC4
|
||||
has been designed by RSA Data Security, Inc.
|
||||
It was posted anonymously
|
||||
to the USENET and was confirmed to be equivalent by several sources who
|
||||
had access to the original cipher.
|
||||
Since
|
||||
.Pa RC4
|
||||
used to be a trade secret, the cipher is now referred to as
|
||||
.Pa ARC4 .
|
||||
These functions first appeared in
|
||||
.Ox 2.1 .
|
||||
.Pp
|
||||
The original version of this random number generator used the
|
||||
RC4 (also known as ARC4) algorithm.
|
||||
In
|
||||
.Ox 5.5
|
||||
it was replaced with the ChaCha20 cipher, and it may be replaced
|
||||
again in the future as cryptographic techniques advance.
|
||||
A good mnemonic is
|
||||
.Dq A Replacement Call for Random .
|
||||
.Pp
|
||||
The
|
||||
.Fn arc4random
|
||||
random number generator was first introduced in
|
||||
.Fx 2.2.6 .
|
||||
The ChaCha20 based implementation was introduced in
|
||||
.Fx 12.0 ,
|
||||
with obsolete stir and addrandom interfaces removed at the same time.
|
||||
|
@ -1,8 +1,10 @@
|
||||
/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
|
||||
/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
|
||||
* Copyright (c) 2014, Theo de Raadt <deraadt@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
|
||||
@ -18,15 +20,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Arc4 random number generator for OpenBSD.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* RC4 is a registered trademark of RSA Laboratories.
|
||||
* ChaCha based random number generator for OpenBSD.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
@ -35,232 +29,176 @@ __FBSDID("$FreeBSD$");
|
||||
#include "namespace.h"
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "libc_private.h"
|
||||
#include "un-namespace.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define KEYSTREAM_ONLY
|
||||
#include "chacha.c"
|
||||
|
||||
#define minimum(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
#define inline __inline
|
||||
#else /* !__GNUC__ */
|
||||
#else /* __GNUC__ || _MSC_VER */
|
||||
#define inline
|
||||
#endif /* !__GNUC__ */
|
||||
#endif /* !__GNUC__ && !_MSC_VER */
|
||||
|
||||
struct arc4_stream {
|
||||
u_int8_t i;
|
||||
u_int8_t j;
|
||||
u_int8_t s[256];
|
||||
};
|
||||
#define KEYSZ 32
|
||||
#define IVSZ 8
|
||||
#define BLOCKSZ 64
|
||||
#define RSBUFSZ (16*BLOCKSZ)
|
||||
|
||||
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Marked INHERIT_ZERO, so zero'd out in fork children. */
|
||||
static struct _rs {
|
||||
size_t rs_have; /* valid bytes at end of rs_buf */
|
||||
size_t rs_count; /* bytes till reseed */
|
||||
} *rs;
|
||||
|
||||
#define KEYSIZE 128
|
||||
#define _ARC4_LOCK() \
|
||||
do { \
|
||||
if (__isthreaded) \
|
||||
_pthread_mutex_lock(&arc4random_mtx); \
|
||||
} while (0)
|
||||
/* Maybe be preserved in fork children, if _rs_allocate() decides. */
|
||||
static struct _rsx {
|
||||
chacha_ctx rs_chacha; /* chacha context for random keystream */
|
||||
u_char rs_buf[RSBUFSZ]; /* keystream blocks */
|
||||
} *rsx;
|
||||
|
||||
#define _ARC4_UNLOCK() \
|
||||
do { \
|
||||
if (__isthreaded) \
|
||||
_pthread_mutex_unlock(&arc4random_mtx); \
|
||||
} while (0)
|
||||
static inline int _rs_allocate(struct _rs **, struct _rsx **);
|
||||
static inline void _rs_forkdetect(void);
|
||||
#include "arc4random.h"
|
||||
|
||||
static int rs_initialized;
|
||||
static struct arc4_stream rs;
|
||||
static pid_t arc4_stir_pid;
|
||||
static int arc4_count;
|
||||
|
||||
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
|
||||
static inline u_int8_t arc4_getbyte(void);
|
||||
static void arc4_stir(void);
|
||||
static inline void _rs_rekey(u_char *dat, size_t datlen);
|
||||
|
||||
static inline void
|
||||
arc4_init(void)
|
||||
_rs_init(u_char *buf, size_t n)
|
||||
{
|
||||
int n;
|
||||
if (n < KEYSZ + IVSZ)
|
||||
return;
|
||||
|
||||
for (n = 0; n < 256; n++)
|
||||
rs.s[n] = n;
|
||||
rs.i = 0;
|
||||
rs.j = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
arc4_addrandom(u_char *dat, int datlen)
|
||||
{
|
||||
int n;
|
||||
u_int8_t si;
|
||||
|
||||
rs.i--;
|
||||
for (n = 0; n < 256; n++) {
|
||||
rs.i = (rs.i + 1);
|
||||
si = rs.s[rs.i];
|
||||
rs.j = (rs.j + si + dat[n % datlen]);
|
||||
rs.s[rs.i] = rs.s[rs.j];
|
||||
rs.s[rs.j] = si;
|
||||
if (rs == NULL) {
|
||||
if (_rs_allocate(&rs, &rsx) == -1)
|
||||
abort();
|
||||
}
|
||||
rs.j = rs.i;
|
||||
}
|
||||
|
||||
size_t
|
||||
__arc4_sysctl(u_char *buf, size_t size)
|
||||
{
|
||||
int mib[2];
|
||||
size_t len, done;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARND;
|
||||
done = 0;
|
||||
|
||||
do {
|
||||
len = size;
|
||||
if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1)
|
||||
return (done);
|
||||
done += len;
|
||||
buf += len;
|
||||
size -= len;
|
||||
} while (size > 0);
|
||||
|
||||
return (done);
|
||||
chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
|
||||
chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
arc4_stir(void)
|
||||
_rs_stir(void)
|
||||
{
|
||||
u_char rdat[KEYSIZE];
|
||||
int i;
|
||||
u_char rnd[KEYSZ + IVSZ];
|
||||
|
||||
if (!rs_initialized) {
|
||||
arc4_init();
|
||||
rs_initialized = 1;
|
||||
if (getentropy(rnd, sizeof rnd) == -1)
|
||||
_getentropy_fail();
|
||||
|
||||
if (!rs)
|
||||
_rs_init(rnd, sizeof(rnd));
|
||||
else
|
||||
_rs_rekey(rnd, sizeof(rnd));
|
||||
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
|
||||
|
||||
/* invalidate rs_buf */
|
||||
rs->rs_have = 0;
|
||||
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
|
||||
|
||||
rs->rs_count = 1600000;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_rs_stir_if_needed(size_t len)
|
||||
{
|
||||
_rs_forkdetect();
|
||||
if (!rs || rs->rs_count <= len)
|
||||
_rs_stir();
|
||||
if (rs->rs_count <= len)
|
||||
rs->rs_count = 0;
|
||||
else
|
||||
rs->rs_count -= len;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_rs_rekey(u_char *dat, size_t datlen)
|
||||
{
|
||||
#ifndef KEYSTREAM_ONLY
|
||||
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
|
||||
#endif
|
||||
/* fill rs_buf with the keystream */
|
||||
chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
|
||||
rsx->rs_buf, sizeof(rsx->rs_buf));
|
||||
/* mix in optional user provided data */
|
||||
if (dat) {
|
||||
size_t i, m;
|
||||
|
||||
m = minimum(datlen, KEYSZ + IVSZ);
|
||||
for (i = 0; i < m; i++)
|
||||
rsx->rs_buf[i] ^= dat[i];
|
||||
}
|
||||
if (__arc4_sysctl(rdat, KEYSIZE) != KEYSIZE) {
|
||||
/*
|
||||
* The sysctl cannot fail. If it does fail on some FreeBSD
|
||||
* derivative or after some future change, just abort so that
|
||||
* the problem will be found and fixed. abort is not normally
|
||||
* suitable for a library but makes sense here.
|
||||
*/
|
||||
abort();
|
||||
}
|
||||
|
||||
arc4_addrandom(rdat, KEYSIZE);
|
||||
|
||||
/*
|
||||
* Discard early keystream, as per recommendations in:
|
||||
* "(Not So) Random Shuffles of RC4" by Ilya Mironov.
|
||||
*/
|
||||
for (i = 0; i < 3072; i++)
|
||||
(void)arc4_getbyte();
|
||||
arc4_count = 1600000;
|
||||
/* immediately reinit for backtracking resistance */
|
||||
_rs_init(rsx->rs_buf, KEYSZ + IVSZ);
|
||||
memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
|
||||
rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
|
||||
}
|
||||
|
||||
static void
|
||||
arc4_stir_if_needed(void)
|
||||
{
|
||||
pid_t pid = getpid();
|
||||
|
||||
if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
|
||||
arc4_stir_pid = pid;
|
||||
arc4_stir();
|
||||
}
|
||||
}
|
||||
|
||||
static inline u_int8_t
|
||||
arc4_getbyte(void)
|
||||
{
|
||||
u_int8_t si, sj;
|
||||
|
||||
rs.i = (rs.i + 1);
|
||||
si = rs.s[rs.i];
|
||||
rs.j = (rs.j + si);
|
||||
sj = rs.s[rs.j];
|
||||
rs.s[rs.i] = sj;
|
||||
rs.s[rs.j] = si;
|
||||
return (rs.s[(si + sj) & 0xff]);
|
||||
}
|
||||
|
||||
static inline u_int32_t
|
||||
arc4_getword(void)
|
||||
{
|
||||
u_int32_t val;
|
||||
val = arc4_getbyte() << 24;
|
||||
val |= arc4_getbyte() << 16;
|
||||
val |= arc4_getbyte() << 8;
|
||||
val |= arc4_getbyte();
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_stir(void)
|
||||
{
|
||||
_ARC4_LOCK();
|
||||
arc4_stir();
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_addrandom(u_char *dat, int datlen)
|
||||
{
|
||||
_ARC4_LOCK();
|
||||
if (!rs_initialized)
|
||||
arc4_stir();
|
||||
arc4_addrandom(dat, datlen);
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
arc4random(void)
|
||||
{
|
||||
u_int32_t val;
|
||||
_ARC4_LOCK();
|
||||
arc4_count -= 4;
|
||||
arc4_stir_if_needed();
|
||||
val = arc4_getword();
|
||||
_ARC4_UNLOCK();
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_buf(void *_buf, size_t n)
|
||||
static inline void
|
||||
_rs_random_buf(void *_buf, size_t n)
|
||||
{
|
||||
u_char *buf = (u_char *)_buf;
|
||||
_ARC4_LOCK();
|
||||
arc4_stir_if_needed();
|
||||
while (n--) {
|
||||
if (--arc4_count <= 0)
|
||||
arc4_stir();
|
||||
buf[n] = arc4_getbyte();
|
||||
u_char *keystream;
|
||||
size_t m;
|
||||
|
||||
_rs_stir_if_needed(n);
|
||||
while (n > 0) {
|
||||
if (rs->rs_have > 0) {
|
||||
m = minimum(n, rs->rs_have);
|
||||
keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
|
||||
- rs->rs_have;
|
||||
memcpy(buf, keystream, m);
|
||||
memset(keystream, 0, m);
|
||||
buf += m;
|
||||
n -= m;
|
||||
rs->rs_have -= m;
|
||||
}
|
||||
if (rs->rs_have == 0)
|
||||
_rs_rekey(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_rs_random_u32(uint32_t *val)
|
||||
{
|
||||
u_char *keystream;
|
||||
|
||||
_rs_stir_if_needed(sizeof(*val));
|
||||
if (rs->rs_have < sizeof(*val))
|
||||
_rs_rekey(NULL, 0);
|
||||
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
|
||||
memcpy(val, keystream, sizeof(*val));
|
||||
memset(keystream, 0, sizeof(*val));
|
||||
rs->rs_have -= sizeof(*val);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
arc4random(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
_ARC4_LOCK();
|
||||
_rs_random_u32(&val);
|
||||
_ARC4_UNLOCK();
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
arc4random_buf(void *buf, size_t n)
|
||||
{
|
||||
_ARC4_LOCK();
|
||||
_rs_random_buf(buf, n);
|
||||
_ARC4_UNLOCK();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*-------- Test code for i386 --------*/
|
||||
#include <stdio.h>
|
||||
#include <machine/pctr.h>
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
const int iter = 1000000;
|
||||
int i;
|
||||
pctrval v;
|
||||
|
||||
v = rdtsc();
|
||||
for (i = 0; i < iter; i++)
|
||||
arc4random();
|
||||
v = rdtsc() - v;
|
||||
v /= iter;
|
||||
|
||||
printf("%qd cycles\n", v);
|
||||
}
|
||||
#endif
|
||||
|
74
lib/libc/gen/arc4random.h
Normal file
74
lib/libc/gen/arc4random.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996, David Mazieres <dm@uun.org>
|
||||
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
|
||||
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
|
||||
* Copyright (c) 2014, Theo de Raadt <deraadt@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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stub functions for portability.
|
||||
*/
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||
#define _ARC4_LOCK() \
|
||||
do { \
|
||||
if (__isthreaded) \
|
||||
_pthread_mutex_lock(&arc4random_mtx); \
|
||||
} while (0)
|
||||
|
||||
#define _ARC4_UNLOCK() \
|
||||
do { \
|
||||
if (__isthreaded) \
|
||||
_pthread_mutex_unlock(&arc4random_mtx); \
|
||||
} while (0)
|
||||
|
||||
static inline void
|
||||
_getentropy_fail(void)
|
||||
{
|
||||
raise(SIGKILL);
|
||||
}
|
||||
|
||||
static inline int
|
||||
_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
|
||||
{
|
||||
struct {
|
||||
struct _rs rs;
|
||||
struct _rsx rsx;
|
||||
} *p;
|
||||
|
||||
if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
|
||||
return (-1);
|
||||
if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) {
|
||||
munmap(p, sizeof(*p));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*rsp = &p->rs;
|
||||
*rsxp = &p->rsx;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_rs_forkdetect(void)
|
||||
{
|
||||
}
|
@ -31,12 +31,37 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libc_private.h"
|
||||
|
||||
extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t);
|
||||
|
||||
static size_t
|
||||
arnd_sysctl(u_char *buf, size_t size)
|
||||
{
|
||||
int mib[2];
|
||||
size_t len, done;
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_ARND;
|
||||
done = 0;
|
||||
|
||||
do {
|
||||
len = size;
|
||||
if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1)
|
||||
return (done);
|
||||
done += len;
|
||||
buf += len;
|
||||
size -= len;
|
||||
} while (size > 0);
|
||||
|
||||
return (done);
|
||||
}
|
||||
|
||||
/*
|
||||
* If a newer libc is accidentally installed on an older kernel, provide high
|
||||
* quality random data anyway. The sysctl interface is not as fast and does
|
||||
@ -54,7 +79,7 @@ getentropy_fallback(void *buf, size_t buflen)
|
||||
errno = EFAULT;
|
||||
return (-1);
|
||||
}
|
||||
if (__arc4_sysctl(buf, buflen) != buflen) {
|
||||
if (arnd_sysctl(buf, buflen) != buflen) {
|
||||
if (errno == EFAULT)
|
||||
return (-1);
|
||||
/*
|
||||
|
@ -405,8 +405,6 @@ int __sys_futimens(int fd, const struct timespec *times) __hidden;
|
||||
int __sys_utimensat(int fd, const char *path,
|
||||
const struct timespec *times, int flag) __hidden;
|
||||
|
||||
__size_t __arc4_sysctl(unsigned char *, __size_t);
|
||||
|
||||
/* execve() with PATH processing to implement posix_spawnp() */
|
||||
int _execvpe(const char *, char * const *, char * const *);
|
||||
|
||||
|
@ -14,7 +14,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <crypto/chacha20/chacha.h>
|
||||
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint32_t u32;
|
||||
|
||||
@ -57,7 +56,7 @@ typedef struct chacha_ctx chacha_ctx;
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
|
||||
void
|
||||
LOCAL void
|
||||
chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
|
||||
{
|
||||
const char *constants;
|
||||
@ -82,7 +81,7 @@ chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits)
|
||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
||||
}
|
||||
|
||||
void
|
||||
LOCAL void
|
||||
chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
|
||||
{
|
||||
x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
|
||||
@ -91,7 +90,7 @@ chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter)
|
||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
||||
}
|
||||
|
||||
void
|
||||
LOCAL void
|
||||
chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
{
|
||||
u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
@ -169,6 +168,7 @@ chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
x14 = PLUS(x14,j14);
|
||||
x15 = PLUS(x15,j15);
|
||||
|
||||
#ifndef KEYSTREAM_ONLY
|
||||
x0 = XOR(x0,U8TO32_LITTLE(m + 0));
|
||||
x1 = XOR(x1,U8TO32_LITTLE(m + 4));
|
||||
x2 = XOR(x2,U8TO32_LITTLE(m + 8));
|
||||
@ -185,6 +185,7 @@ chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
x13 = XOR(x13,U8TO32_LITTLE(m + 52));
|
||||
x14 = XOR(x14,U8TO32_LITTLE(m + 56));
|
||||
x15 = XOR(x15,U8TO32_LITTLE(m + 60));
|
||||
#endif
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
if (!j12) {
|
||||
@ -219,6 +220,8 @@ chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes)
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
#ifndef KEYSTREAM_ONLY
|
||||
m += 64;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -23,9 +23,15 @@ struct chacha_ctx {
|
||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
||||
#define CHACHA_BLOCKLEN 64
|
||||
|
||||
void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits);
|
||||
void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr);
|
||||
void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m,
|
||||
#ifdef _KERNEL
|
||||
#define LOCAL
|
||||
#else
|
||||
#define LOCAL static
|
||||
#endif
|
||||
|
||||
LOCAL void chacha_keysetup(struct chacha_ctx *x, const u_char *k, u_int kbits);
|
||||
LOCAL void chacha_ivsetup(struct chacha_ctx *x, const u_char *iv, const u_char *ctr);
|
||||
LOCAL void chacha_encrypt_bytes(struct chacha_ctx *x, const u_char *m,
|
||||
u_char *c, u_int bytes);
|
||||
|
||||
#endif /* CHACHA_H */
|
||||
|
Loading…
Reference in New Issue
Block a user