svn commit: r338059 - in head: . contrib/ntp/lib/isc contrib/ntp/sntp/libevent crypto/heimdal/lib/roken crypto/openssh include lib/libc/gen lib/libc/include sys/crypto/chacha20

Xin LI delphij at FreeBSD.org
Sun Aug 19 17:40:54 UTC 2018


Author: delphij
Date: Sun Aug 19 17:40:50 2018
New Revision: 338059
URL: https://svnweb.freebsd.org/changeset/base/338059

Log:
  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

Added:
  head/lib/libc/gen/arc4random-compat.c   (contents, props changed)
  head/lib/libc/gen/arc4random.h   (contents, props changed)
Modified:
  head/ObsoleteFiles.inc
  head/contrib/ntp/lib/isc/random.c
  head/contrib/ntp/sntp/libevent/evutil_rand.c
  head/crypto/heimdal/lib/roken/rand.c
  head/crypto/openssh/config.h
  head/include/stdlib.h
  head/lib/libc/gen/Makefile.inc
  head/lib/libc/gen/Symbol.map
  head/lib/libc/gen/arc4random.3
  head/lib/libc/gen/arc4random.c   (contents, props changed)
  head/lib/libc/gen/getentropy.c
  head/lib/libc/include/libc_private.h
  head/sys/crypto/chacha20/chacha.c
  head/sys/crypto/chacha20/chacha.h

Modified: head/ObsoleteFiles.inc
==============================================================================
--- head/ObsoleteFiles.inc	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/ObsoleteFiles.inc	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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

Modified: head/contrib/ntp/lib/isc/random.c
==============================================================================
--- head/contrib/ntp/lib/isc/random.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/contrib/ntp/lib/isc/random.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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
 }
 

Modified: head/contrib/ntp/sntp/libevent/evutil_rand.c
==============================================================================
--- head/contrib/ntp/sntp/libevent/evutil_rand.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/contrib/ntp/sntp/libevent/evutil_rand.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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

Modified: head/crypto/heimdal/lib/roken/rand.c
==============================================================================
--- head/crypto/heimdal/lib/roken/rand.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/crypto/heimdal/lib/roken/rand.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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)

Modified: head/crypto/openssh/config.h
==============================================================================
--- head/crypto/openssh/config.h	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/crypto/openssh/config.h	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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

Modified: head/include/stdlib.h
==============================================================================
--- head/include/stdlib.h	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/include/stdlib.h	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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,

Modified: head/lib/libc/gen/Makefile.inc
==============================================================================
--- head/lib/libc/gen/Makefile.inc	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/gen/Makefile.inc	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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

Modified: head/lib/libc/gen/Symbol.map
==============================================================================
--- head/lib/libc/gen/Symbol.map	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/gen/Symbol.map	Sun Aug 19 17:40:50 2018	(r338059)
@@ -65,8 +65,6 @@ FBSD_1.0 {
 	pthread_testcancel;
 	alarm;
 	arc4random;
-	arc4random_addrandom;
-	arc4random_stir;
 	__assert;
 	check_utility_compat;
 	clock;

Added: head/lib/libc/gen/arc4random-compat.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/gen/arc4random-compat.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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);

Modified: head/lib/libc/gen/arc4random.3
==============================================================================
--- head/lib/libc/gen/arc4random.3	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/gen/arc4random.3	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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 at 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.

Modified: head/lib/libc/gen/arc4random.c
==============================================================================
--- head/lib/libc/gen/arc4random.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/gen/arc4random.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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 at uun.org>
  * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at 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 <pthread.h>
+#include <signal.h>
+#include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
-#include <sys/param.h>
-#include <sys/sysctl.h>
+#include <sys/types.h>
 #include <sys/time.h>
-#include <pthread.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;
+static inline void _rs_rekey(u_char *dat, size_t datlen);
 
-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
-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;
+
+	chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
+	chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL);
 }
 
-size_t
-__arc4_sysctl(u_char *buf, size_t size)
+static void
+_rs_stir(void)
 {
-	int mib[2];
-	size_t len, done;
+	u_char rnd[KEYSZ + IVSZ];
 
-	mib[0] = CTL_KERN;
-	mib[1] = KERN_ARND;
-	done = 0;
+	if (getentropy(rnd, sizeof rnd) == -1)
+		_getentropy_fail();
 
-	do {
-		len = size;
-		if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1)
-			return (done);
-		done += len;
-		buf += len;
-		size -= len;
-	} while (size > 0);
+	if (!rs)
+		_rs_init(rnd, sizeof(rnd));
+	else
+		_rs_rekey(rnd, sizeof(rnd));
+	explicit_bzero(rnd, sizeof(rnd));	/* discard source seed */
 
-	return (done);
+	/* invalidate rs_buf */
+	rs->rs_have = 0;
+	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
+
+	rs->rs_count = 1600000;
 }
 
-static void
-arc4_stir(void)
+static inline void
+_rs_stir_if_needed(size_t len)
 {
-	u_char rdat[KEYSIZE];
-	int i;
-
-	if (!rs_initialized) {
-		arc4_init();
-		rs_initialized = 1;
-	}
-	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;
+	_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 void
-arc4_stir_if_needed(void)
+static inline void
+_rs_rekey(u_char *dat, size_t datlen)
 {
-	pid_t pid = getpid();
+#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;
 
-	if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
-		arc4_stir_pid = pid;
-		arc4_stir();
+		m = minimum(datlen, KEYSZ + IVSZ);
+		for (i = 0; i < m; i++)
+			rsx->rs_buf[i] ^= dat[i];
 	}
+	/* 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 inline u_int8_t
-arc4_getbyte(void)
+static inline void
+_rs_random_buf(void *_buf, size_t n)
 {
-	u_int8_t si, sj;
+	u_char *buf = (u_char *)_buf;
+	u_char *keystream;
+	size_t m;
 
-	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]);
+	_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 u_int32_t
-arc4_getword(void)
+static inline void
+_rs_random_u32(uint32_t *val)
 {
-	u_int32_t val;
-	val = arc4_getbyte() << 24;
-	val |= arc4_getbyte() << 16;
-	val |= arc4_getbyte() << 8;
-	val |= arc4_getbyte();
-	return val;
-}
+	u_char *keystream;
 
-void
-arc4random_stir(void)
-{
-	_ARC4_LOCK();
-	arc4_stir();
-	_ARC4_UNLOCK();
+	_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);
 }
 
-void
-arc4random_addrandom(u_char *dat, int datlen)
-{
-	_ARC4_LOCK();
-	if (!rs_initialized)
-		arc4_stir();
-	arc4_addrandom(dat, datlen);
-	_ARC4_UNLOCK();
-}
-
-u_int32_t
+uint32_t
 arc4random(void)
 {
-	u_int32_t val;
+	uint32_t val;
+
 	_ARC4_LOCK();
-	arc4_count -= 4;
-	arc4_stir_if_needed();
-	val = arc4_getword();
+	_rs_random_u32(&val);
 	_ARC4_UNLOCK();
 	return val;
 }
 
 void
-arc4random_buf(void *_buf, size_t n)
+arc4random_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();
-	}
+	_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

Added: head/lib/libc/gen/arc4random.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/lib/libc/gen/arc4random.h	Sun Aug 19 17:40:50 2018	(r338059)
@@ -0,0 +1,74 @@
+/*	$OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at 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)
+{
+}

Modified: head/lib/libc/gen/getentropy.c
==============================================================================
--- head/lib/libc/gen/getentropy.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/gen/getentropy.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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);
 		/*

Modified: head/lib/libc/include/libc_private.h
==============================================================================
--- head/lib/libc/include/libc_private.h	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/lib/libc/include/libc_private.h	Sun Aug 19 17:40:50 2018	(r338059)
@@ -405,8 +405,6 @@ int		__sys_futimens(int fd, const struct timespec *tim
 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 *);
 

Modified: head/sys/crypto/chacha20/chacha.c
==============================================================================
--- head/sys/crypto/chacha20/chacha.c	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/sys/crypto/chacha20/chacha.c	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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 *
   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,u
     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,u
     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,u
     }
     bytes -= 64;
     c += 64;
+#ifndef KEYSTREAM_ONLY
     m += 64;
+#endif
   }
 }

Modified: head/sys/crypto/chacha20/chacha.h
==============================================================================
--- head/sys/crypto/chacha20/chacha.h	Sun Aug 19 17:36:50 2018	(r338058)
+++ head/sys/crypto/chacha20/chacha.h	Sun Aug 19 17:40:50 2018	(r338059)
@@ -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 */


More information about the svn-src-all mailing list