Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F161295284
D2025.id6436.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
189 KB
Referenced Files
None
Subscribers
None
D2025.id6436.diff
View Options
Index: UPDATING
===================================================================
--- UPDATING
+++ UPDATING
@@ -31,6 +31,41 @@
disable the most expensive debugging functionality run
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+2015<MM><DD>:
+ The default kernel entropy-processing algorithm is now
+ Fortuna, replacing Yarrow.
+
+ Assuming you have 'device random' in your kernel config
+ file, the configurations allow a kernel option to override
+ this default. You may choose *ONE* of:
+
+ options RANDOM_YARROW # Legacy /dev/random algorithm.
+ options RANDOM_DUMMY # Blocking-only driver.
+
+ If you have neither, you get Fortuna. For most people,
+ read no further, Fortuna will give a /dev/random that works
+ like it always used to, and the difference will be irrelevant.
+
+ If you remove 'device random', you get *NO* kernel-processed
+ entopy at all. This may be acceptable to folks building
+ embedded systems, but has complications. Carry on reading,
+ and it is assumed you know what you need.
+
+ *PLEASE* read random(4) and random(9) if you are in the
+ habit of tweeking kernel configs, and/or if you are a member
+ of the embedded community, wanting specific and not-usual
+ behaviour from your security subsystems.
+
+ NOTE!! If you use RANDOM_DUMMY and/or have no 'device
+ random', you will NOT have a functioning /dev/random, and
+ many cryptographic features will not work, including SSH.
+ You may also find strange behaviour from the random(3) set
+ of library functions, in particular sranddev(3), srandomdev(3)
+ and arc4random(3). The reason for this is that the KERN_ARND
+ sysctl only returns entropy if it thinks it has some to
+ share, and with RANDOM_DUMMY or no 'device random' this
+ will never happen.
+
20150616:
FreeBSD's old make (fmake) has been removed from the system. It is
available as the devel/fmake port or via pkg install fmake.
Index: etc/defaults/rc.conf
===================================================================
--- etc/defaults/rc.conf
+++ etc/defaults/rc.conf
@@ -630,15 +630,16 @@
# in the system booting with securelevel set to 1, as
# init(8) will raise the level when rc(8) completes.
update_motd="YES" # update version info in /etc/motd (or NO)
-entropy_file="/entropy" # Set to NO to disable caching entropy through reboots.
+entropy_boot_file="/boot/entropy" # Set to NO to disable very early
+ # (used at early boot time) entropy caching through reboots.
+entropy_file="/entropy" # Set to NO to disable late (used when going multi-user)
+ # entropy through reboots.
# /var/db/entropy-file is preferred if / is not avail.
entropy_dir="/var/db/entropy" # Set to NO to disable caching entropy via cron.
entropy_save_sz="4096" # Size of the entropy cache files.
entropy_save_num="8" # Number of entropy cache files to save.
-harvest_interrupt="YES" # Entropy device harvests interrupt randomness
-harvest_ethernet="YES" # Entropy device harvests ethernet randomness
-harvest_p_to_p="YES" # Entropy device harvests point-to-point randomness
-harvest_swi="YES" # Entropy device harvests internal SWI randomness
+harvest_mask="511" # Entropy device harvests all but the very invasive sources.
+ # (See 'sysctl kern.random.harvest' and random(4))
dmesg_enable="YES" # Save dmesg(8) to /var/run/dmesg.boot
watchdogd_enable="NO" # Start the software watchdog daemon
watchdogd_flags="" # Flags to watchdogd (if enabled)
Index: etc/rc.d/random
===================================================================
--- etc/rc.d/random
+++ etc/rc.d/random
@@ -41,6 +41,13 @@
random_start()
{
+
+ if [ ${harvest_mask} -gt 0 ]; then
+ echo -n 'Setting up harvesting:'
+ ${SYSCTL} kern.random.harvest.mask=${harvest_mask} > /dev/null
+ ${SYSCTL_N} sysctl -n kern.random.harvest.mask_symbolic
+ fi
+
echo -n 'Feeding entropy:'
if [ ! -w /dev/random ] ; then
@@ -68,6 +75,14 @@
;;
esac
+ case ${entropy_boot_file:=/boot/entropy} in
+ [Nn][Oo] | '')
+ ;;
+ *)
+ save_dev_random "${entropy_boot_file}"
+ ;;
+ esac
+
echo '.'
}
@@ -100,7 +115,33 @@
;;
*)
dd if=/dev/random of=${entropy_file_confirmed} \
- bs=4096 count=1 2> /dev/null
+ bs=4096 count=1 2> /dev/null ||
+ warn 'write failed (unwriteable file or full fs?)'
+ echo '.'
+ ;;
+ esac
+ umask ${oumask}
+ ;;
+ esac
+ case ${entropy_boot_file:=/boot/entropy} in
+ [Nn][Oo] | '')
+ ;;
+ *)
+ echo -n 'Writing early boot entropy file:'
+ rm -f ${entropy_boot_file} 2> /dev/null
+ oumask=`umask`
+ umask 077
+ if touch ${entropy_boot_file} 2> /dev/null; then
+ entropy_boot_file_confirmed="${entropy_boot_file}"
+ fi
+ case ${entropy_boot_file_confirmed} in
+ '')
+ warn 'write failed (read-only fs?)'
+ ;;
+ *)
+ dd if=/dev/random of=${entropy_boot_file_confirmed} \
+ bs=4096 count=1 2> /dev/null ||
+ warn 'write failed (unwriteable file or full fs?)'
echo '.'
;;
esac
Index: share/man/man4/random.4
===================================================================
--- share/man/man4/random.4
+++ share/man/man4/random.4
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2001-2013 Mark R V Murray. All rights reserved.
+.\" Copyright (c) 2001-2015 Mark R V Murray. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -23,7 +23,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 12, 2013
+.Dd June 21, 2015
.Dt RANDOM 4
.Os
.Sh NAME
@@ -37,31 +37,18 @@
device
returns an endless supply of random bytes when read.
It also accepts and reads data
-as any ordinary (and willing) file,
-but discards data written to it.
-The device will probe for
-certain hardware entropy sources,
-and use these in preference to the fallback,
-which is a generator implemented in software.
+as any ordinary file.
.Pp
-The software generator will start in an
+The generator will start in an
.Em unseeded
state, and will block reads until
-it is (re)seeded.
+it is seeded for the first time.
This may cause trouble at system boot
when keys and the like
are generated from
/dev/random
so steps should be taken to ensure a
-reseed as soon as possible.
-The
-.Xr sysctl 8
-controlling the
-.Em seeded
-status (see below) may be used
-if security is not an issue
-or for convenience
-during setup or development.
+seedng as soon as possible.
.Pp
This initial seeding
of random number generators
@@ -94,92 +81,40 @@
.Pp
which results in something like:
.Bd -literal -offset indent
-kern.random.adaptors: yarrow,dummy
-kern.random.active_adaptor: yarrow
-kern.random.yarrow.gengateinterval: 10
-kern.random.yarrow.bins: 10
-kern.random.yarrow.fastthresh: 96
-kern.random.yarrow.slowthresh: 128
-kern.random.yarrow.slowoverthresh: 2
-kern.random.sys.seeded: 1
-kern.random.sys.harvest.ethernet: 1
-kern.random.sys.harvest.point_to_point: 1
-kern.random.sys.harvest.interrupt: 1
-kern.random.sys.harvest.swi: 1
+kern.random.fortuna.minpoolsize: 64
+kern.random.harvest.mask_symbolic: [HIGH_PERFORMANCE], ... ,CACHED
+kern.random.harvest.mask_bin: 00111111111
+kern.random.harvest.mask: 511
+kern.random.random_sources: 'Intel Secure Key RNG'
.Ed
.Pp
Other than
-.Dl kern.random.adaptors
-all settings are read/write.
-.Pp
-The
-.Va kern.random.sys.seeded
-variable indicates whether or not the
-.Nm
-device is in an acceptably secure state
-as a result of reseeding.
-If set to 0,
-the device will block (on read)
-until the next reseed
-as a result of entropy harvesting.
-A reseed will set the value to 1 (non-blocking).
-.Pp
-The
-.Va kern.random.sys.harvest.ethernet
-variable is used to select LAN traffic as an entropy source.
-A 0 (zero) value means that LAN traffic
-is not considered as an entropy source.
-Set the variable to 1 (one)
-if you wish to use LAN traffic for entropy harvesting.
-.Pp
-The
-.Va kern.random.sys.harvest.point_to_point
-variable is used to select serial line traffic as an entropy source.
-(Serial line traffic includes PPP, SLIP and all tun0 traffic.)
-A 0 (zero) value means such traffic
-is not considered as an entropy source.
-Set the variable to 1 (one)
-if you wish to use it for entropy harvesting.
+.Dl kern.random.fortuna.minpoolsize
+and
+.Dl kern.random.harvest.mask
+all settings are read-only.
.Pp
The
-.Va kern.random.sys.harvest.interrupt
-variable is used to select hardware interrupts
+.Va kern.random.harvest.mask
+bitmask is used to select
+the possible entropy sources.
+A 0 (zero) value means
+the corresponding source
+is not considered
as an entropy source.
-A 0 (zero) value means hardware interrupts
-are not considered as an entropy source.
-Set the variable to 1 (one)
-if you wish to use them for entropy harvesting.
-All hardware interrupt harvesting is set up by the
-individual device drivers.
-.Pp
+Set the bit to 1 (one)
+if you wish to use
+that source.
The
-.Va kern.random.sys.harvest.swi
-variable is used to select software interrupts
-as an entropy source.
-A 0 (zero) value means software interrupts
-are not considered as an entropy source.
-Set the variable to 1 (one)
-if you wish to use them for entropy harvesting.
-.Pp
-The other variables are explained in the paper describing the
-.Em Yarrow
-algorithm at
-.Pa http://www.schneier.com/yarrow.html .
-.Pp
-These variables are all limited
-in terms of the values they may contain:
-.Bl -tag -width "kern.random.yarrow.gengateinterval" -compact -offset indent
-.It Va kern.random.yarrow.gengateinterval
-.Bq 4..64
-.It Va kern.random.yarrow.bins
-.Bq 2..16
-.It Va kern.random.yarrow.fastthresh
-.Bq 64..256
-.It Va kern.random.yarrow.slowthresh
-.Bq 64..256
-.It Va kern.random.yarrow.slowoverthresh
-.Bq 1..5
-.El
+.Va kern.random.harvest.mask_bin
+and
+.Va kern.random.harvest.mask_symbolic
+sysctl
+can be used confirm
+that your choices are correct.
+Note that disabled items
+in the latter item
+are listed in square brackets.
.Pp
Internal
.Xr sysctl 3
@@ -308,23 +243,36 @@
.Xr RAND_add 3 ,
.Xr RAND_bytes 3 ,
.Xr random 3 ,
+.Xr random 9 ,
.Xr sysctl 8
+.Rs
+.%A Ferguson
+.%A Schneier
+.%A Kohno
+.%B Cryptography Engineering
+.%I Wiley
+.%O ISBN 978-0-470-47424-2
+.Re
.Sh HISTORY
A
.Nm
device appeared in
.Fx 2.2 .
-The early version was taken from Theodore Ts'o's entropy driver for Linux.
The current software implementation,
introduced in
-.Fx 5.0 ,
-is a complete rewrite by
+.Fx 11.0 ,
+is by
.An Mark R V Murray ,
and is an implementation of the
-.Em Yarrow
-algorithm by Bruce Schneier,
+.Em Fortuna
+algorithm by Ferguson
.Em et al .
-Significant infrastructure work was done by Arthur Mesh.
-.Pp
-The author gratefully acknowledges
-significant assistance from VIA Technologies, Inc.
+It replaces the previous
+.Em Yarrow
+implementation,
+introduced in
+.Fx 5.0 .
+The older
+.Em Yarrow
+algorithm remains available
+as a compile-time fallback.
Index: share/man/man5/rc.conf.5
===================================================================
--- share/man/man5/rc.conf.5
+++ share/man/man5/rc.conf.5
@@ -3995,27 +3995,11 @@
.Va jail_ Ns Ao Ar jname Ac Ns Va _sysvipc_allow
.El
.\" -----------------------------------------------------
-.It Va harvest_interrupt
-.Pq Vt bool
-Set to
-.Dq Li YES
-to use hardware interrupts as an entropy source.
-Refer to
-.Xr random 4
-for more information.
-.It Va harvest_ethernet
-.Pq Vt bool
-Set to
-.Dq Li YES
-to use LAN traffic as an entropy source.
-Refer to
-.Xr random 4
-for more information.
-.It Va harvest_p_to_p
-.Pq Vt bool
-Set to
-.Dq Li YES
-to use serial line traffic as an entropy source.
+.It Va harvest_mask
+.Pq Vt int
+Set to a bit-mask
+representing the entropy sources
+you wish to harvest.
Refer to
.Xr random 4
for more information.
@@ -4036,6 +4020,19 @@
This file should be located on the root file system to seed the
.Xr random 4
device as early as possible in the boot process.
+.It Va entropy_boot_file
+.Pq Vt str
+Set to
+.Dq Li NO
+to disable
+very early caching entropy
+through reboots.
+Otherwise set to the filename
+used to read
+early reboot cached entropy.
+This file should be located where
+.Xr loader 8
+can read it.
.It Va entropy_save_sz
.Pq Vt int
Size of the entropy cache files saved by
Index: share/man/man9/random.9
===================================================================
--- share/man/man9/random.9
+++ share/man/man9/random.9
@@ -53,11 +53,12 @@
.Sh DESCRIPTION
The
.Fn random
-function will by default produce a sequence of numbers that can be duplicated
+function will by default produce
+a sequence of numbers
+that can be duplicated
by calling
.Fn srandom
-with
-.Ql 1
+with some constant
as the
.Fa seed .
The
@@ -67,19 +68,28 @@
value to get slightly more unpredictable numbers.
It is important to remember that the
.Fn random
-function is entirely predictable, and is therefore not of use where
-knowledge of the sequence of numbers may be of benefit to an attacker.
+function is entirely predictable,
+and is therefore not of use where
+knowledge of the sequence of numbers
+may be of benefit to an attacker.
.Pp
The
.Fn arc4rand
-function will return very good quality random numbers, slightly better
-suited for security-related purposes.
+function will return very good quality random numbers,
+slightly better suited
+for security-related purposes.
The random numbers from
.Fn arc4rand
-are seeded from the entropy device if it is available.
-Automatic reseeds happen after a certain timeinterval and after a
-certain number of bytes have been delivered.
-A forced reseed can be forced by passing a non-zero value in the
+are seeded from the entropy device
+if it is available.
+Automatic reseeds happen
+after a certain timeinterval
+and after a certain number of bytes
+have been delivered.
+A forced reseed
+can be forced
+by passing a non-zero
+value in the
.Fa reseed
argument.
.Pp
@@ -90,19 +100,19 @@
If the entropy device is not loaded, then
the
.Fa buffer
-is filled with output generated by
-.Fn random .
+is ignored.
The
.Fa buffer
is filled with no more than
.Fa count
bytes.
-It is advised that
+It is strongly advised that
.Fn read_random
-is not used; instead use
+is not used;
+instead use
.Fn arc4rand
.Pp
-All the bits generated by
+All the bits returned by
.Fn random ,
.Fn arc4rand
and
@@ -120,32 +130,38 @@
.Sh RETURN VALUES
The
.Fn random
-function
-uses a non-linear additive feedback random number generator employing a
-default table of size 31 long integers to return successive pseudo-random
+function uses
+a non-linear additive feedback random number generator
+employing a default table
+of size 31
+containing long integers
+to return successive pseudo-random
numbers in the range from 0 to
.if t 2\u\s731\s10\d\(mi1.
.if n (2**31)\(mi1.
-The period of this random number generator is very large, approximately
+The period of this random number generator
+is very large,
+approximately
.if t 16\(mu(2\u\s731\s10\d\(mi1).
.if n 16*((2**31)\(mi1).
.Pp
The
.Fn arc4rand
-function uses the RC4 algorithm to generate successive pseudo-random
-bytes.
+function uses the RC4 algorithm
+to generate successive pseudo-random bytes.
The
.Fn arc4random
-function
-uses
+function uses
.Fn arc4rand
-to generate pseudo-random numbers in the range from 0 to
+to generate pseudo-random numbers
+in the range from 0 to
.if t 2\u\s732\s10\d\(mi1.
.if n (2**32)\(mi1.
.Pp
The
.Fn read_random
-function returns the number of bytes placed in
+function returns
+the number of bytes placed in
.Fa buffer .
.Sh AUTHORS
.An Dan Moschuk
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -528,14 +528,14 @@
crypto/des/des_setkey.c optional crypto | ipsec | netsmb
crypto/rc4/rc4.c optional netgraph_mppc_encryption | kgssapi
crypto/rijndael/rijndael-alg-fst.c optional crypto | geom_bde | \
- ipsec | random | wlan_ccmp
-crypto/rijndael/rijndael-api-fst.c optional geom_bde | random
+ ipsec | random random_yarrow | random !random_yarrow !random_dummy | wlan_ccmp
+crypto/rijndael/rijndael-api-fst.c optional geom_bde | random random_yarrow | random !random_yarrow !random_dummy
crypto/rijndael/rijndael-api.c optional crypto | ipsec | wlan_ccmp
crypto/sha1.c optional carp | crypto | ipsec | \
netgraph_mppc_encryption | sctp
-crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random | \
+crypto/sha2/sha2.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \
sctp | zfs
-crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random | \
+crypto/sha2/sha256c.c optional crypto | geom_bde | ipsec | random random_yarrow | random !random_yarrow !random_dummy | \
sctp | zfs
crypto/siphash/siphash.c optional inet | inet6
crypto/siphash/siphash_test.c optional inet | inet6
@@ -2139,15 +2139,12 @@
compile-with "${NORMAL_FW}" \
no-obj no-implicit-rule \
clean "rt2860.fw"
-dev/random/randomdev.c standard
-dev/random/random_adaptors.c standard
-dev/random/dummy_rng.c standard
-dev/random/live_entropy_sources.c standard
-dev/random/random_harvestq.c standard
-dev/random/randomdev_soft.c optional random
-dev/random/yarrow.c optional random
-dev/random/fortuna.c optional random
-dev/random/hash.c optional random
+dev/random/randomdev_none.c optional !random
+dev/random/randomdev.c optional random
+dev/random/random_harvestq.c optional random random_yarrow | random !random_dummy
+dev/random/yarrow.c optional random random_yarrow
+dev/random/fortuna.c optional random !random_yarrow !random_dummy
+dev/random/hash.c optional random random_yarrow | random !random_dummy
dev/rc/rc.c optional rc
dev/re/if_re.c optional re
dev/rl/if_rl.c optional rl pci
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -938,9 +938,16 @@
RCTL opt_global.h
# Random number generator(s)
+# The DEBUG option is in global.h as the random harvesting
+# puts probes all over the place, and it makes little sense
+# to pollute these headers with an extra include.
+# the DUMMY option is in global.h because it is used to
+# turn off harvesting all over the kernel.
+RANDOM_DEBUG opt_global.h
+# Which CSPRNG hashes we get.
+# These are mutually exclusive. With neither, Fortuna is selected.
+RANDOM_DUMMY opt_global.h
RANDOM_YARROW opt_random.h
-RANDOM_FORTUNA opt_random.h
-RANDOM_DEBUG opt_random.h
# Intel em(4) driver
EM_MULTIQUEUE opt_em.h
Index: sys/dev/glxsb/glxsb.c
===================================================================
--- sys/dev/glxsb/glxsb.c
+++ sys/dev/glxsb/glxsb.c
@@ -476,7 +476,8 @@
if (status & SB_RNS_TRNG_VALID) {
value = bus_read_4(sc->sc_sr, SB_RANDOM_NUM);
/* feed with one uint32 */
- random_harvest(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(&value, sizeof(value), 32/2, RANDOM_PURE_GLXSB);
}
callout_reset(&sc->sc_rngco, sc->sc_rnghz, glxsb_rnd, sc);
Index: sys/dev/hifn/hifn7751.c
===================================================================
--- sys/dev/hifn/hifn7751.c
+++ sys/dev/hifn/hifn7751.c
@@ -258,7 +258,8 @@
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_HIFN);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_HIFN);
}
static u_int
Index: sys/dev/random/build.sh
===================================================================
--- sys/dev/random/build.sh
+++ sys/dev/random/build.sh
@@ -1,3 +1,29 @@
+#!/bin/sh
+#-
+# Copyright (c) 2013-2015 Mark R V Murray
+# 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
+# in this position and unchanged.
+# 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 ``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 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$
#
# Basic script to build crude unit tests.
@@ -11,6 +37,7 @@
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
../../crypto/sha2/sha256c.c \
+ -lz \
-o yunit_test
cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
-I../.. -lstdthreads -Wall \
@@ -21,4 +48,5 @@
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
../../crypto/sha2/sha256c.c \
+ -lz \
-o funit_test
Index: sys/dev/random/dummy_rng.c
===================================================================
--- sys/dev/random/dummy_rng.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*-
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * Copyright (c) 2013 Mark R V Murray
- * 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
- * in this position and unchanged.
- * 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 ``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 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.
- *
- */
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_random.h"
-
-#include <sys/param.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/random.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
-
-static int
-dummy_random_zero(void)
-{
-
- return (0);
-}
-
-static void
-dummy_random(void)
-{
-}
-
-/* ARGSUSED */
-static void
-dummy_random_init(void)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- randomdev_init_reader(dummy_random_read_phony);
-}
-
-/* This is used only by the internal read_random(9) call, and then only
- * if no entropy processor is loaded.
- *
- * Make a token effort to provide _some_ kind of output. No warranty of
- * the quality of this output is made, mainly because its lousy.
- *
- * This is only used by the internal read_random(9) call when no other
- * adaptor is active.
- *
- * It has external scope due to the way things work in
- * randomdev_[de]init_reader() that the rest of the world doesn't need to
- * know about.
- *
- * Caveat Emptor.
- */
-void
-dummy_random_read_phony(uint8_t *buf, u_int count)
-{
- /* If no entropy device is loaded, don't spam the console with warnings */
- u_long randval;
- size_t size, i;
-
- /* srandom() is called in kern/init_main.c:proc0_post() */
-
- /* Fill buf[] with random(9) output */
- for (i = 0; i < count; i += sizeof(randval)) {
- randval = random();
- size = MIN(count - i, sizeof(randval));
- memcpy(buf + i, &randval, (size_t)size);
- }
-}
-
-struct random_adaptor randomdev_dummy = {
- .ra_ident = "Dummy",
- .ra_priority = 1, /* Bottom priority, so goes to last position */
- .ra_reseed = dummy_random,
- .ra_seeded = (random_adaptor_seeded_func_t *)dummy_random_zero,
- .ra_read = (random_adaptor_read_func_t *)dummy_random_zero,
- .ra_write = (random_adaptor_write_func_t *)dummy_random_zero,
- .ra_init = dummy_random_init,
- .ra_deinit = dummy_random,
-};
Index: sys/dev/random/fortuna.h
===================================================================
--- sys/dev/random/fortuna.h
+++ sys/dev/random/fortuna.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,21 @@
*/
#ifndef SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
-#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
+#define SYS_DEV_RANDOM_FORTUNA_H_INCLUDED
#ifdef _KERNEL
typedef struct mtx mtx_t;
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&fortuna_state.fs_mtx, "reseed mutex", NULL, MTX_DEF)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&fortuna_state.fs_mtx, MA_OWNED)
+#else
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&fortuna_state.fs_mtx, mtx_plain)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&fortuna_state.fs_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x)
#endif
-void random_fortuna_init_alg(void);
-void random_fortuna_deinit_alg(void);
-void random_fortuna_read(uint8_t *, u_int);
-void random_fortuna_write(uint8_t *, u_int);
-void random_fortuna_reseed(void);
-int random_fortuna_seeded(void);
-void random_fortuna_process_event(struct harvest_event *event);
-
-#endif
+#endif /* SYS_DEV_RANDOM_FORTUNA_H_INCLUDED */
Index: sys/dev/random/fortuna.c
===================================================================
--- sys/dev/random/fortuna.c
+++ sys/dev/random/fortuna.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,25 +25,24 @@
*
*/
-/* This implementation of Fortuna is based on the descriptions found in
- * ISBN 0-471-22357-3 "Practical Cryptography" by Ferguson and Schneier
- * ("F&S").
- *
- * The above book is superseded by ISBN 978-0-470-47424-2 "Cryptography
- * Engineering" by Ferguson, Schneier and Kohno ("FS&K"). The code has
- * not yet fully caught up with FS&K.
+/*
+ * This implementation of Fortuna is based on the descriptions found in
+ * ISBN 978-0-470-47424-2 "Cryptography Engineering" by Ferguson, Schneier
+ * and Kohno ("FS&K").
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#ifdef _KERNEL
-#include "opt_random.h"
+#include <sys/limits.h>
+#ifdef _KERNEL
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
@@ -56,13 +55,10 @@
#include <dev/random/hash.h>
#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/uint128.h>
#include <dev/random/fortuna.h>
#else /* !_KERNEL */
-#include <sys/param.h>
-#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -79,351 +75,405 @@
#include <dev/random/fortuna.h>
#endif /* _KERNEL */
-#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
-#define RANDOM_YARROW
-#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
-#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
-#endif
-
-#if defined(RANDOM_FORTUNA)
-
-#define NPOOLS 32
-#define MINPOOLSIZE 64
-#define DEFPOOLSIZE 256
-#define MAXPOOLSIZE 65536
+/* Defined in FS&K */
+#define RANDOM_FORTUNA_NPOOLS 32 /* The number of accumulation pools */
+#define RANDOM_FORTUNA_DEFPOOLSIZE 64 /* The default pool size/length for a (re)seed */
+#define RANDOM_FORTUNA_MAX_READ (1 << 20) /* Max bytes in a single read */
-/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
-CTASSERT(BLOCKSIZE == sizeof(uint128_t));
-CTASSERT(KEYSIZE == 2*BLOCKSIZE);
-
-/* This is the beastie that needs protecting. It contains all of the
- * state that we are excited about.
- * Exactly one is instantiated.
+/*
+ * The allowable range of RANDOM_FORTUNA_DEFPOOLSIZE. The default value is above.
+ * Making RANDOM_FORTUNA_DEFPOOLSIZE too large will mean a long time between reseeds,
+ * and too small may compromise initial security but get faster reseeds.
+ */
+#define RANDOM_FORTUNA_MINPOOLSIZE 16
+#define RANDOM_FORTUNA_MAXPOOLSIZE UINT_MAX
+CTASSERT(RANDOM_FORTUNA_MINPOOLSIZE <= RANDOM_FORTUNA_DEFPOOLSIZE);
+CTASSERT(RANDOM_FORTUNA_DEFPOOLSIZE <= RANDOM_FORTUNA_MAXPOOLSIZE);
+
+/* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
+
+/*
+ * This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about. Exactly one is instantiated.
*/
static struct fortuna_state {
- /* P_i */
- struct pool {
- u_int length;
- struct randomdev_hash hash;
- } pool[NPOOLS];
-
- /* ReseedCnt */
- u_int reseedcount;
-
- /* C - 128 bits */
- union {
- uint8_t byte[BLOCKSIZE];
- uint128_t whole;
- } counter;
-
- /* K */
- struct randomdev_key key;
-
- /* Extras */
- u_int minpoolsize;
-
+ struct fs_pool { /* P_i */
+ u_int fsp_length; /* Only the first one is used by Fortuna */
+ struct randomdev_hash fsp_hash;
+ } fs_pool[RANDOM_FORTUNA_NPOOLS];
+ u_int fs_reseedcount; /* ReseedCnt */
+ uint128_t fs_counter; /* C */
+ struct randomdev_key fs_key; /* K */
+ u_int fs_minpoolsize; /* Extras */
/* Extras for the OS */
-
#ifdef _KERNEL
/* For use when 'pacing' the reseeds */
- sbintime_t lasttime;
+ sbintime_t fs_lasttime;
#endif
+ /* Reseed lock */
+ mtx_t fs_mtx;
} fortuna_state;
-/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
-static mtx_t random_reseed_mtx;
+#ifdef _KERNEL
+static struct sysctl_ctx_list random_clist;
+RANDOM_CHECK_UINT(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE);
+#else
+static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
+#endif
-static struct fortuna_start_cache {
- uint8_t junk[PAGE_SIZE];
- size_t length;
- struct randomdev_hash hash;
-} fortuna_start_cache;
+static void random_fortuna_pre_read(void);
+static void random_fortuna_read(uint8_t *, u_int);
+static void random_fortuna_post_read(void);
+static void random_fortuna_write(uint8_t *, u_int);
+static void random_fortuna_reseed(void);
+static int random_fortuna_seeded(void);
+static void random_fortuna_process_event(struct harvest_event *);
#ifdef _KERNEL
-static struct sysctl_ctx_list random_clist;
-RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
+/* Interface to Adaptors system */
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Fortuna",
+ .ra_pre_read = random_fortuna_pre_read,
+ .ra_read = random_fortuna_read,
+ .ra_post_read = random_fortuna_post_read,
+ .ra_write = random_fortuna_write,
+ .ra_reseed = random_fortuna_reseed,
+ .ra_seeded = random_fortuna_seeded,
+ .ra_event_processor = random_fortuna_process_event,
+ .ra_poolcount = RANDOM_FORTUNA_NPOOLS,
+};
#endif
-void
-random_fortuna_init_alg(void)
+/* ARGSUSED */
+static void
+random_fortuna_init_alg(void *unused __unused)
{
int i;
#ifdef _KERNEL
struct sysctl_oid *random_fortuna_o;
#endif
- memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
- fortuna_start_cache.length = 0U;
- randomdev_hash_init(&fortuna_start_cache.hash);
-
- /* Set up a lock for the reseed process */
-#ifdef _KERNEL
- mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
-#else /* !_KERNEL */
- mtx_init(&random_reseed_mtx, mtx_plain);
-#endif /* _KERNEL */
-
-#ifdef _KERNEL
- /* Fortuna parameters. Do not adjust these unless you have
+ RANDOM_RESEED_INIT_LOCK();
+ /*
+ * Fortuna parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
+ fortuna_state.fs_minpoolsize = RANDOM_FORTUNA_DEFPOOLSIZE;
+#ifdef _KERNEL
+ fortuna_state.fs_lasttime = 0;
random_fortuna_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "fortuna", CTLFLAG_RW, 0,
"Fortuna Parameters");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_fortuna_o), OID_AUTO,
- "minpoolsize", CTLTYPE_UINT|CTLFLAG_RW,
- &fortuna_state.minpoolsize, DEFPOOLSIZE,
- random_check_uint_minpoolsize, "IU",
- "Minimum pool size necessary to cause a reseed automatically");
-
- fortuna_state.lasttime = 0U;
+ "minpoolsize", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &fortuna_state.fs_minpoolsize, RANDOM_FORTUNA_DEFPOOLSIZE,
+ random_check_uint_fs_minpoolsize, "IU",
+ "Minimum pool size necessary to cause a reseed");
+ KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0 at startup"));
#endif
- fortuna_state.minpoolsize = DEFPOOLSIZE;
-
- /* F&S - InitializePRNG() */
-
- /* F&S - P_i = \epsilon */
- for (i = 0; i < NPOOLS; i++) {
- randomdev_hash_init(&fortuna_state.pool[i].hash);
- fortuna_state.pool[i].length = 0U;
+ /*-
+ * FS&K - InitializePRNG()
+ * - P_i = \epsilon
+ * - ReseedCNT = 0
+ */
+ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
+ randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
+ fortuna_state.fs_pool[i].fsp_length = 0;
}
-
- /* F&S - ReseedCNT = 0 */
- fortuna_state.reseedcount = 0U;
-
- /* F&S - InitializeGenerator() */
-
- /* F&S - C = 0 */
- uint128_clear(&fortuna_state.counter.whole);
-
- /* F&S - K = 0 */
- memset(&fortuna_state.key, 0, sizeof(fortuna_state.key));
+ fortuna_state.fs_reseedcount = 0;
+ /*-
+ * FS&K - InitializeGenerator()
+ * - C = 0
+ * - K = 0
+ */
+ fortuna_state.fs_counter = UINT128_ZERO;
+ explicit_bzero(&fortuna_state.fs_key, sizeof(fortuna_state.fs_key));
}
+#ifdef _KERNEL
+SYSINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_init_alg, NULL);
+#endif
-void
-random_fortuna_deinit_alg(void)
+/* ARGSUSED */
+static void
+random_fortuna_deinit_alg(void *unused __unused)
{
- mtx_destroy(&random_reseed_mtx);
- memset(&fortuna_state, 0, sizeof(fortuna_state));
+ RANDOM_RESEED_DEINIT_LOCK();
+ explicit_bzero(&fortuna_state, sizeof(fortuna_state));
+#ifdef _KERNEL
+ sysctl_ctx_free(&random_clist);
+#endif
}
+#ifdef _KERNEL
+SYSUNINIT(random_fortuna, SI_SUB_RANDOM, SI_ORDER_THIRD, random_fortuna_deinit_alg, NULL);
+#endif
-/* F&S - AddRandomEvent() */
-/* Process a single stochastic event off the harvest queue */
+/*-
+ * FS&K - AddRandomEvent()
+ * Process a single stochastic event off the harvest queue
+ */
void
random_fortuna_process_event(struct harvest_event *event)
{
u_int pl;
- /* We must be locked for all this as plenty of state gets messed with */
- mtx_lock(&random_reseed_mtx);
-
- /* Accumulate the event into the appropriate pool
- * where each event carries the destination information
+ RANDOM_RESEED_LOCK();
+ /*-
+ * FS&K - P_i = P_i|<harvested stuff>
+ * Accumulate the event into the appropriate pool
+ * where each event carries the destination information.
+ *
+ * The hash_init() and hash_finish() calls are done in
+ * random_fortuna_pre_read().
+ *
+ * We must be locked against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating.
+ */
+ pl = event->he_destination % RANDOM_FORTUNA_NPOOLS;
+ randomdev_hash_iterate(&fortuna_state.fs_pool[pl].fsp_hash, event, sizeof(*event));
+ /*-
+ * Don't wrap the length. Doing the the hard way so as not to wrap at MAXUINT.
+ * This is a "saturating" add.
+ * XXX: FIX!!: We don't actually need lengths for anything but fs_pool[0],
+ * but it's been useful debugging to see them all.
*/
- /* F&S - P_i = P_i|<harvested stuff> */
- /* The hash_init and hash_finish are done in random_fortuna_read() below */
- pl = event->he_destination % NPOOLS;
- randomdev_hash_iterate(&fortuna_state.pool[pl].hash, event, sizeof(*event));
- /* No point in counting above the outside maximum */
- fortuna_state.pool[pl].length += event->he_size;
- fortuna_state.pool[pl].length = MIN(fortuna_state.pool[pl].length, MAXPOOLSIZE);
-
- /* Done with state-messing */
- mtx_unlock(&random_reseed_mtx);
+ if (RANDOM_FORTUNA_MAXPOOLSIZE - fortuna_state.fs_pool[pl].fsp_length > event->he_size)
+ fortuna_state.fs_pool[pl].fsp_length += event->he_size;
+ else
+ fortuna_state.fs_pool[pl].fsp_length = RANDOM_FORTUNA_MAXPOOLSIZE;
+ explicit_bzero(event, sizeof(*event));
+ RANDOM_RESEED_UNLOCK();
+}
+
+/*-
+ * Process a block of data suspected to be slightly stochastic.
+ * Do this by breaking it up and inserting the pieces as if
+ * they were separate events.
+ */
+static void
+random_fortuna_process_buffer(uint32_t *buf, u_int wordcount)
+{
+ static struct harvest_event event;
+ static u_int destination = 0;
+ int i;
+
+ for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = sizeof(event.he_entropy);
+ event.he_bits = event.he_size/8;
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = destination++; /* Harmless cheating */
+ memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy));
+ random_fortuna_process_event(&event);
+ }
}
-/* F&S - Reseed() */
-/* Reseed Mutex is held */
+/*-
+ * FS&K - Reseed()
+ * This introduces new key material into the output generator.
+ * Additionaly it increments the output generator's counter
+ * variable C. When C > 0, the output generator is seeded and
+ * will deliver output.
+ * The entropy_data buffer passed is a very specific size; the
+ * product of RANDOM_FORTUNA_NPOOLS and RANDOM_KEYSIZE.
+ */
static void
-reseed(uint8_t *junk, u_int length)
+random_fortuna_reseed_internal(uint32_t *entropy_data, u_int blockcount)
{
struct randomdev_hash context;
- uint8_t hash[KEYSIZE];
+ uint8_t hash[RANDOM_KEYSIZE];
- KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
-#ifdef _KERNEL
- mtx_assert(&random_reseed_mtx, MA_OWNED);
-#endif
-
- /* FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m)) */
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ /*-
+ * FS&K - K = Hd(K|s) where Hd(m) is H(H(0^512|m))
+ * - C = C + 1
+ */
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, zero_region, 512/8);
- randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
- randomdev_hash_iterate(&context, junk, length);
+ randomdev_hash_iterate(&context, zero_region, RANDOM_ZERO_BLOCKSIZE);
+ randomdev_hash_iterate(&context, &fortuna_state.fs_key, sizeof(fortuna_state.fs_key));
+ randomdev_hash_iterate(&context, entropy_data, RANDOM_KEYSIZE*blockcount);
randomdev_hash_finish(&context, hash);
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, hash, KEYSIZE);
+ randomdev_hash_iterate(&context, hash, RANDOM_KEYSIZE);
randomdev_hash_finish(&context, hash);
- randomdev_encrypt_init(&fortuna_state.key, hash);
- memset(hash, 0, sizeof(hash));
-
- /* Unblock the device if it was blocked due to being unseeded */
- if (uint128_is_zero(fortuna_state.counter.whole))
- random_adaptor_unblock();
- /* FS&K - C = C + 1 */
- uint128_increment(&fortuna_state.counter.whole);
+ randomdev_encrypt_init(&fortuna_state.fs_key, hash);
+ explicit_bzero(hash, sizeof(hash));
+ /* Unblock the device if this is the first time we are reseeding. */
+ if (uint128_is_zero(fortuna_state.fs_counter))
+ randomdev_unblock();
+ uint128_increment(&fortuna_state.fs_counter);
}
-/* F&S - GenerateBlocks() */
-/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+/*-
+ * FS&K - GenerateBlocks()
+ * Generate a number of complete blocks of random output.
+ */
static __inline void
random_fortuna_genblocks(uint8_t *buf, u_int blockcount)
{
u_int i;
- for (i = 0u; i < blockcount; i++) {
- /* F&S - r = r|E(K,C) */
- randomdev_encrypt(&fortuna_state.key, fortuna_state.counter.byte, buf, BLOCKSIZE);
- buf += BLOCKSIZE;
-
- /* F&S - C = C + 1 */
- uint128_increment(&fortuna_state.counter.whole);
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ for (i = 0; i < blockcount; i++) {
+ /*-
+ * FS&K - r = r|E(K,C)
+ * - C = C + 1
+ */
+ randomdev_encrypt(&fortuna_state.fs_key, &fortuna_state.fs_counter, buf, RANDOM_BLOCKSIZE);
+ buf += RANDOM_BLOCKSIZE;
+ uint128_increment(&fortuna_state.fs_counter);
}
}
-/* F&S - PseudoRandomData() */
-/* Reseed Mutex is held, and buf points to a whole number of blocks. */
+/*-
+ * FS&K - PseudoRandomData()
+ * This generates no more than 2^20 bytes of data, and cleans up its
+ * internal state when finished. It is assumed that a whole number of
+ * blocks are available for writing; any excess generated will be
+ * ignored.
+ */
static __inline void
random_fortuna_genrandom(uint8_t *buf, u_int bytecount)
{
- static uint8_t temp[BLOCKSIZE*(KEYSIZE/BLOCKSIZE)];
+ static uint8_t temp[RANDOM_BLOCKSIZE*(RANDOM_KEYS_PER_BLOCK)];
u_int blockcount;
- /* F&S - assert(n < 2^20) */
- KASSERT((bytecount <= (1 << 20)), ("invalid single read request to fortuna of %d bytes", bytecount));
-
- /* F&S - r = first-n-bytes(GenerateBlocks(ceil(n/16))) */
- blockcount = bytecount / BLOCKSIZE;
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ /*-
+ * FS&K - assert(n < 2^20 (== 1 MB)
+ * - r = first-n-bytes(GenerateBlocks(ceil(n/16)))
+ * - K = GenerateBlocks(2)
+ */
+ KASSERT((bytecount <= RANDOM_FORTUNA_MAX_READ), ("invalid single read request to Fortuna of %d bytes", bytecount));
+ blockcount = (bytecount + RANDOM_BLOCKSIZE - 1)/RANDOM_BLOCKSIZE;
random_fortuna_genblocks(buf, blockcount);
- /* TODO: FIX! remove memcpy()! */
- if (bytecount % BLOCKSIZE > 0) {
- random_fortuna_genblocks(temp, 1);
- memcpy(buf + (blockcount * BLOCKSIZE), temp, bytecount % BLOCKSIZE);
- }
-
- /* F&S - K = GenerateBlocks(2) */
- random_fortuna_genblocks(temp, KEYSIZE/BLOCKSIZE);
- randomdev_encrypt_init(&fortuna_state.key, temp);
- memset(temp, 0, sizeof(temp));
+ random_fortuna_genblocks(temp, RANDOM_KEYS_PER_BLOCK);
+ randomdev_encrypt_init(&fortuna_state.fs_key, temp);
+ explicit_bzero(temp, sizeof(temp));
}
-/* F&S - RandomData() */
-/* Used to return processed entropy from the PRNG */
-/* The argument buf points to a whole number of blocks. */
+/*-
+ * FS&K - RandomData()
+ * Used to return processed entropy from the PRNG.
+ * There is a pre_read and a post_read required to be present
+ * (but they can be null functions) in order to allow specific
+ * actions at the begin or the end of a read. Fortuna does its
+ * reseeding in the _pre_read() part, and _post_read() is not
+ * used.
+ */
void
-random_fortuna_read(uint8_t *buf, u_int bytecount)
+random_fortuna_pre_read(void)
{
#ifdef _KERNEL
- sbintime_t thistime;
+ sbintime_t now;
#endif
struct randomdev_hash context;
- uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
- int i;
- u_int seedlength;
+ uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS];
+ uint8_t temp[RANDOM_KEYSIZE];
+ u_int i;
- /* We must be locked for all this as plenty of state gets messed with */
- mtx_lock(&random_reseed_mtx);
+ KASSERT(fortuna_state.fs_minpoolsize > 0, ("random: Fortuna threshold must be > 0"));
+#ifdef _KERNEL
+ /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ now = getsbinuptime();
+#endif
+ RANDOM_RESEED_LOCK();
- /* if buf == NULL and bytecount == 0 then this is the pre-read. */
- /* if buf == NULL and bytecount != 0 then this is the post-read; ignore. */
- if (buf == NULL) {
- if (bytecount == 0) {
- if (fortuna_state.pool[0].length >= fortuna_state.minpoolsize
+ if (fortuna_state.fs_pool[0].fsp_length >= fortuna_state.fs_minpoolsize
#ifdef _KERNEL
- /* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
- && ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
+ /* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
+ && (now - fortuna_state.fs_lasttime > hz/10)
#endif
- ) {
+ ) {
#ifdef _KERNEL
- fortuna_state.lasttime = thistime;
+ fortuna_state.fs_lasttime = now;
#endif
- seedlength = 0U;
- /* F&S - ReseedCNT = ReseedCNT + 1 */
- fortuna_state.reseedcount++;
- /* s = \epsilon by default */
- for (i = 0; i < NPOOLS; i++) {
- /* F&S - if Divides(ReseedCnt, 2^i) ... */
- if ((fortuna_state.reseedcount % (1 << i)) == 0U) {
- seedlength += KEYSIZE;
- /* F&S - temp = (P_i) */
- randomdev_hash_finish(&fortuna_state.pool[i].hash, temp);
- /* F&S - P_i = \epsilon */
- randomdev_hash_init(&fortuna_state.pool[i].hash);
- fortuna_state.pool[i].length = 0U;
- /* F&S - s = s|H(temp) */
- randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, temp, KEYSIZE);
- randomdev_hash_finish(&context, s + i*KEYSIZE);
- }
- else
- break;
- }
+ /* FS&K - ReseedCNT = ReseedCNT + 1 */
+ fortuna_state.fs_reseedcount++;
+ /* s = \epsilon at start */
+ for (i = 0; i < RANDOM_FORTUNA_NPOOLS; i++) {
+ /* FS&K - if Divides(ReseedCnt, 2^i) ... */
+ if ((fortuna_state.fs_reseedcount % (1 << i)) == 0) {
+ /*-
+ * FS&K - temp = (P_i)
+ * - P_i = \epsilon
+ * - s = s|H(temp)
+ */
+ randomdev_hash_finish(&fortuna_state.fs_pool[i].fsp_hash, temp);
+ randomdev_hash_init(&fortuna_state.fs_pool[i].fsp_hash);
+ fortuna_state.fs_pool[i].fsp_length = 0;
+ randomdev_hash_init(&context);
+ randomdev_hash_iterate(&context, temp, RANDOM_KEYSIZE);
+ randomdev_hash_finish(&context, s + i*RANDOM_KEYSIZE_WORDS);
+ } else
+ break;
+ }
#ifdef RANDOM_DEBUG
- printf("random: active reseed: reseedcount [%d] ", fortuna_state.reseedcount);
- for (i = 0; i < NPOOLS; i++)
- printf(" %d", fortuna_state.pool[i].length);
- printf("\n");
-#endif
- /* F&S */
- reseed(s, seedlength);
-
- /* Clean up */
- memset(s, 0, seedlength);
- seedlength = 0U;
- memset(temp, 0, sizeof(temp));
- memset(&context, 0, sizeof(context));
- }
+ {
+ u_int j;
+
+ printf("random: reseedcount [%d]", fortuna_state.fs_reseedcount);
+ for (j = 0; j < RANDOM_FORTUNA_NPOOLS; j++)
+ printf(" %X", fortuna_state.fs_pool[j].fsp_length);
+ printf("\n");
}
+#endif
+ /* FS&K */
+ random_fortuna_reseed_internal(s, i < RANDOM_FORTUNA_NPOOLS ? i + 1 : RANDOM_FORTUNA_NPOOLS);
+ /* Clean up and secure */
+ explicit_bzero(s, sizeof(s));
+ explicit_bzero(temp, sizeof(temp));
+ explicit_bzero(&context, sizeof(context));
}
- /* if buf != NULL do a regular read. */
- else
- random_fortuna_genrandom(buf, bytecount);
-
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_UNLOCK();
}
-/* Internal function to hand external entropy to the PRNG */
+/*-
+ * Main read from Fortuna.
+ * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size.
+ * Lots of code presumes this for efficiency, both here and in other
+ * routines. You are NOT allowed to break this!
+ */
void
-random_fortuna_write(uint8_t *buf, u_int count)
+random_fortuna_read(uint8_t *buf, u_int bytecount)
{
- uint8_t temp[KEYSIZE];
- int i;
- uintmax_t timestamp;
-
- timestamp = get_cyclecount();
- randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp));
- randomdev_hash_iterate(&fortuna_start_cache.hash, buf, count);
- timestamp = get_cyclecount();
- randomdev_hash_iterate(&fortuna_start_cache.hash, ×tamp, sizeof(timestamp));
- randomdev_hash_finish(&fortuna_start_cache.hash, temp);
- for (i = 0; i < KEYSIZE; i++)
- fortuna_start_cache.junk[(fortuna_start_cache.length + i)%PAGE_SIZE] ^= temp[i];
- fortuna_start_cache.length += KEYSIZE;
-#ifdef RANDOM_DEBUG
- printf("random: %s - ", __func__);
- for (i = 0; i < KEYSIZE; i++)
- printf("%02X", temp[i]);
- printf("\n");
-#endif
-
- memset(temp, 0, KEYSIZE);
-
- /* We must be locked for all this as plenty of state gets messed with */
- mtx_lock(&random_reseed_mtx);
+ RANDOM_RESEED_LOCK();
+ random_fortuna_genrandom(buf, bytecount);
+ RANDOM_RESEED_UNLOCK();
+}
- randomdev_hash_init(&fortuna_start_cache.hash);
+void
+random_fortuna_post_read(void)
+{
- reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
- memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
+ /* CWOT */
+}
- mtx_unlock(&random_reseed_mtx);
+/* Internal function to hand external entropy to the PRNG. */
+void
+random_fortuna_write(uint8_t *buf, u_int count)
+{
+ struct randomdev_hash hash;
+ uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
+
+ /* Extra timing here is helpful to scrape scheduler timing entropy */
+ randomdev_hash_init(&hash);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp));
+ randomdev_hash_iterate(&hash, buf, count);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp));
+ randomdev_hash_finish(&hash, entropy_data);
+ explicit_bzero(&hash, sizeof(hash));
+ random_fortuna_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0]));
+ explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
@@ -437,7 +487,5 @@
random_fortuna_seeded(void)
{
- return (!uint128_is_zero(fortuna_state.counter.whole));
+ return (!uint128_is_zero(fortuna_state.fs_counter));
}
-
-#endif /* RANDOM_FORTUNA */
Index: sys/dev/random/hash.h
===================================================================
--- sys/dev/random/hash.h
+++ sys/dev/random/hash.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,10 +27,14 @@
*/
#ifndef SYS_DEV_RANDOM_HASH_H_INCLUDED
-#define SYS_DEV_RANDOM_HASH_H_INCLUDED
+#define SYS_DEV_RANDOM_HASH_H_INCLUDED
-#define KEYSIZE 32 /* (in bytes) == 256 bits */
-#define BLOCKSIZE 16 /* (in bytes) == 128 bits */
+#define RANDOM_KEYSIZE 32 /* (in bytes) == 256 bits */
+#define RANDOM_KEYSIZE_WORDS (RANDOM_KEYSIZE/sizeof(uint32_t))
+#define RANDOM_BLOCKSIZE 16 /* (in bytes) == 128 bits */
+#define RANDOM_BLOCKSIZE_WORDS (RANDOM_BLOCKSIZE/sizeof(uint32_t))
+#define RANDOM_KEYS_PER_BLOCK (RANDOM_KEYSIZE/RANDOM_BLOCKSIZE)
+#define RANDOM_ZERO_BLOCKSIZE 64 /* (in bytes) == 512 zero bits */
struct randomdev_hash { /* Big! Make static! */
SHA256_CTX sha;
@@ -47,4 +51,4 @@
void randomdev_encrypt_init(struct randomdev_key *, const void *);
void randomdev_encrypt(struct randomdev_key *context, const void *, void *, u_int);
-#endif
+#endif /* SYS_DEV_RANDOM_HASH_H_INCLUDED */
Index: sys/dev/random/hash.c
===================================================================
--- sys/dev/random/hash.c
+++ sys/dev/random/hash.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,8 @@
#include <dev/random/hash.h>
-/* This code presumes that KEYSIZE is twice as large as BLOCKSIZE */
-CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+/* This code presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
/* Initialise the hash */
void
@@ -67,7 +67,7 @@
}
/* Conclude by returning the hash in the supplied <*buf> which must be
- * KEYSIZE bytes long.
+ * RANDOM_KEYSIZE bytes long.
*/
void
randomdev_hash_finish(struct randomdev_hash *context, void *buf)
@@ -77,20 +77,20 @@
}
/* Initialise the encryption routine by setting up the key schedule
- * from the supplied <*data> which must be KEYSIZE bytes of binary
- * data. Use CBC mode for better avalanche.
+ * from the supplied <*data> which must be RANDOM_KEYSIZE bytes of binary
+ * data.
*/
void
randomdev_encrypt_init(struct randomdev_key *context, const void *data)
{
- rijndael_cipherInit(&context->cipher, MODE_CBC, NULL);
- rijndael_makeKey(&context->key, DIR_ENCRYPT, KEYSIZE*8, data);
+ rijndael_cipherInit(&context->cipher, MODE_ECB, NULL);
+ rijndael_makeKey(&context->key, DIR_ENCRYPT, RANDOM_KEYSIZE*8, data);
}
/* Encrypt the supplied data using the key schedule preset in the context.
* <length> bytes are encrypted from <*d_in> to <*d_out>. <length> must be
- * a multiple of BLOCKSIZE.
+ * a multiple of RANDOM_BLOCKSIZE.
*/
void
randomdev_encrypt(struct randomdev_key *context, const void *d_in, void *d_out, u_int length)
Index: sys/dev/random/ivy.c
===================================================================
--- sys/dev/random/ivy.c
+++ sys/dev/random/ivy.c
@@ -46,18 +46,15 @@
#include <machine/specialreg.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_adaptors.h>
-#include <dev/random/live_entropy_sources.h>
#define RETRY_COUNT 10
static u_int random_ivy_read(void *, u_int);
-static struct live_entropy_source random_ivy = {
- .les_ident = "Intel Secure Key RNG",
- .les_source = RANDOM_PURE_RDRAND,
- .les_read = random_ivy_read
+static struct random_source random_ivy = {
+ .rs_ident = "Intel Secure Key RNG",
+ .rs_source = RANDOM_PURE_RDRAND,
+ .rs_read = random_ivy_read
};
static inline int
@@ -108,14 +105,14 @@
switch (type) {
case MOD_LOAD:
if (cpu_feature2 & CPUID2_RDRAND) {
- live_entropy_source_register(&random_ivy);
- printf("random: live provider: \"%s\"\n", random_ivy.les_ident);
+ random_source_register(&random_ivy);
+ printf("random: fast provider: \"%s\"\n", random_ivy.rs_ident);
}
break;
case MOD_UNLOAD:
if (cpu_feature2 & CPUID2_RDRAND)
- live_entropy_source_deregister(&random_ivy);
+ random_source_deregister(&random_ivy);
break;
case MOD_SHUTDOWN:
Index: sys/dev/random/live_entropy_sources.h
===================================================================
--- sys/dev/random/live_entropy_sources.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*-
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * Copyright (c) 2013 Mark R V Murray
- * 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
- * in this position and unchanged.
- * 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 ``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 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$
- */
-
-#ifndef SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
-#define SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED
-
-typedef u_int random_live_read_func_t(void *, u_int);
-
-/*
- * Live entropy source is a source of entropy that can provide
- * specified or approximate amount of entropy immediately upon request or within
- * an acceptable amount of time.
- */
-struct live_entropy_source {
- const char *les_ident;
- enum random_entropy_source les_source;
- random_live_read_func_t *les_read;
-};
-
-struct live_entropy_sources {
- LIST_ENTRY(live_entropy_sources) lles_entries; /* list of providers */
- struct live_entropy_source *lles_rsource; /* associated random adaptor */
-};
-
-extern struct mtx live_mtx;
-
-void live_entropy_sources_init(void);
-void live_entropy_sources_deinit(void);
-void live_entropy_source_register(struct live_entropy_source *);
-void live_entropy_source_deregister(struct live_entropy_source *);
-void live_entropy_sources_feed(void);
-
-#endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */
Index: sys/dev/random/live_entropy_sources.c
===================================================================
--- sys/dev/random/live_entropy_sources.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*-
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * Copyright (c) 2013 Mark R V Murray
- * 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
- * in this position and unchanged.
- * 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 ``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 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.
- */
-
-#include <sys/param.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_random.h"
-
-#include <sys/kernel.h>
-#include <sys/libkern.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/queue.h>
-#include <sys/random.h>
-#include <sys/sbuf.h>
-#include <sys/sx.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/unistd.h>
-
-#include <machine/cpu.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_adaptors.h>
-#include <dev/random/random_harvestq.h>
-
-#include "live_entropy_sources.h"
-
-/*
- * The les_lock protects the consistency of the "struct les_head les_sources"
- */
-static struct sx les_lock; /* Need a sleepable lock for the sbuf/sysctl stuff. */
-
-LIST_HEAD(les_head, live_entropy_sources);
-static struct les_head les_sources = LIST_HEAD_INITIALIZER(les_sources);
-
-void
-live_entropy_source_register(struct live_entropy_source *rsource)
-{
- struct live_entropy_sources *lles;
-
- KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-
- lles = malloc(sizeof(*lles), M_ENTROPY, M_WAITOK);
- lles->lles_rsource = rsource;
-
- sx_xlock(&les_lock);
- LIST_INSERT_HEAD(&les_sources, lles, lles_entries);
- sx_xunlock(&les_lock);
-}
-
-void
-live_entropy_source_deregister(struct live_entropy_source *rsource)
-{
- struct live_entropy_sources *lles = NULL;
-
- KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-
- sx_xlock(&les_lock);
- LIST_FOREACH(lles, &les_sources, lles_entries)
- if (lles->lles_rsource == rsource) {
- LIST_REMOVE(lles, lles_entries);
- break;
- }
- sx_xunlock(&les_lock);
- if (lles != NULL)
- free(lles, M_ENTROPY);
-}
-
-static int
-live_entropy_source_handler(SYSCTL_HANDLER_ARGS)
-{
- struct live_entropy_sources *lles;
- struct sbuf sbuf;
- int error, count;
-
- sx_slock(&les_lock);
-
- sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
-
- count = 0;
- LIST_FOREACH(lles, &les_sources, lles_entries) {
- sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
- sbuf_cat(&sbuf, lles->lles_rsource->les_ident);
- sbuf_cat(&sbuf, "'");
- }
-
- error = sbuf_finish(&sbuf);
- sbuf_delete(&sbuf);
-
- sx_sunlock(&les_lock);
-
- return (error);
-}
-
-/*
- * Run through all "live" sources reading entropy for the given
- * number of rounds, which should be a multiple of the number
- * of entropy accumulation pools in use; 2 for Yarrow and 32
- * for Fortuna.
- *
- * BEWARE!!!
- * This function runs inside the RNG thread! Don't do anything silly!
- */
-/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle
- * counters are built in, but on older hardware it will do a real time clock
- * read which can be quite expensive.
- */
-void
-live_entropy_sources_feed(void)
-{
- static struct harvest_event event;
- struct live_entropy_sources *lles;
- int i, read_rate;
- u_int n;
-
- sx_slock(&les_lock);
-
- /*
- * Walk over all of live entropy sources, and feed their output
- * to the system-wide RNG.
- */
- read_rate = random_adaptor_read_rate();
- LIST_FOREACH(lles, &les_sources, lles_entries) {
-
- for (i = 0; i < harvest_pool_count*read_rate; i++) {
- /* This *must* be quick, since it's a live entropy source. */
- n = lles->lles_rsource->les_read(event.he_entropy, HARVESTSIZE);
- KASSERT((n > 0 && n <= HARVESTSIZE), ("very bad return from les_read (= %d) in %s", n, __func__));
- memset(event.he_entropy + n, 0, HARVESTSIZE - n);
-
- event.he_somecounter = get_cyclecount();
- event.he_size = n;
- event.he_bits = (n*8)/2;
- event.he_source = lles->lles_rsource->les_source;
- event.he_destination = harvest_destination[event.he_source]++;
-
- /* Do the actual entropy insertion */
- harvest_process_event(&event);
- }
-
- }
-
- sx_sunlock(&les_lock);
-}
-
-void
-live_entropy_sources_init(void)
-{
-
- SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, live_entropy_source_handler, "",
- "List of Active Live Entropy Sources");
-
- sx_init(&les_lock, "live_entropy_sources");
-}
-
-void
-live_entropy_sources_deinit(void)
-{
-
- sx_destroy(&les_lock);
-}
Index: sys/dev/random/nehemiah.c
===================================================================
--- sys/dev/random/nehemiah.c
+++ sys/dev/random/nehemiah.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* All rights reserved.
*
@@ -44,24 +44,17 @@
#include <machine/specialreg.h>
#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_adaptors.h>
-#include <dev/random/live_entropy_sources.h>
static void random_nehemiah_init(void);
static void random_nehemiah_deinit(void);
static u_int random_nehemiah_read(void *, u_int);
-static struct live_entropy_source random_nehemiah = {
- .les_ident = "VIA Nehemiah Padlock RNG",
- .les_source = RANDOM_PURE_NEHEMIAH,
- .les_read = random_nehemiah_read
+static struct random_source random_nehemiah = {
+ .rs_ident = "VIA Nehemiah Padlock RNG",
+ .rs_source = RANDOM_PURE_NEHEMIAH,
+ .rs_read = random_nehemiah_read
};
-/* XXX: FIX? Now that the Davies-Meyer hash is gone and we only use
- * the 'xstore' instruction, do we still need to preserve the
- * FPU state with fpu_kern_(enter|leave)() ?
- */
static struct fpu_kern_ctx *fpu_ctx_save;
/* This H/W source never stores more than 8 bytes in one go */
@@ -131,8 +124,8 @@
switch (type) {
case MOD_LOAD:
if (via_feature_rng & VIA_HAS_RNG) {
- live_entropy_source_register(&random_nehemiah);
- printf("random: live provider: \"%s\"\n", random_nehemiah.les_ident);
+ random_source_register(&random_nehemiah);
+ printf("random: fast provider: \"%s\"\n", random_nehemiah.rs_ident);
random_nehemiah_init();
}
break;
@@ -140,7 +133,7 @@
case MOD_UNLOAD:
if (via_feature_rng & VIA_HAS_RNG)
random_nehemiah_deinit();
- live_entropy_source_deregister(&random_nehemiah);
+ random_source_deregister(&random_nehemiah);
break;
case MOD_SHUTDOWN:
Index: sys/dev/random/random_adaptors.h
===================================================================
--- sys/dev/random/random_adaptors.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * 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
- * in this position and unchanged.
- * 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 ``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 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$
- */
-
-#ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED
-
-MALLOC_DECLARE(M_ENTROPY);
-
-typedef void random_adaptor_init_func_t(void);
-typedef void random_adaptor_deinit_func_t(void);
-typedef void random_adaptor_read_func_t(uint8_t *, u_int);
-typedef void random_adaptor_write_func_t(uint8_t *, u_int);
-typedef int random_adaptor_seeded_func_t(void);
-typedef void random_adaptor_reseed_func_t(void);
-
-struct random_adaptor {
- const char *ra_ident;
- int ra_priority;
- random_adaptor_init_func_t *ra_init;
- random_adaptor_deinit_func_t *ra_deinit;
- random_adaptor_read_func_t *ra_read;
- random_adaptor_write_func_t *ra_write;
- random_adaptor_reseed_func_t *ra_reseed;
- random_adaptor_seeded_func_t *ra_seeded;
-};
-
-struct random_adaptors {
- LIST_ENTRY(random_adaptors) rra_entries; /* list of providers */
- const char *rra_name; /* name of random adaptor */
- struct random_adaptor *rra_ra;
-};
-
-/* Dummy "always-block" pseudo-device */
-extern struct random_adaptor randomdev_dummy;
-
-void random_adaptors_init(void);
-void random_adaptors_deinit(void);
-
-void random_adaptor_register(const char *, struct random_adaptor *);
-void random_adaptor_deregister(const char *);
-
-int random_adaptor_read(struct cdev *, struct uio *, int);
-int random_adaptor_write(struct cdev *, struct uio *, int);
-int random_adaptor_poll(struct cdev *, int, struct thread *);
-
-int random_adaptor_read_rate(void);
-void random_adaptor_unblock(void);
-
-#endif /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */
Index: sys/dev/random/random_adaptors.c
===================================================================
--- sys/dev/random/random_adaptors.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*-
- * Copyright (c) 2013 Mark R V Murray
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
- * Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
- * 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
- * in this position and unchanged.
- * 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 ``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 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.
- */
-
-#include <sys/param.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_random.h"
-
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/kernel.h>
-#include <sys/kthread.h>
-#include <sys/libkern.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/queue.h>
-#include <sys/random.h>
-#include <sys/sbuf.h>
-#include <sys/selinfo.h>
-#include <sys/sx.h>
-#include <sys/sysctl.h>
-#include <sys/uio.h>
-#include <sys/unistd.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
-#include <dev/random/live_entropy_sources.h>
-
-/* The random_adaptors_lock protects random_adaptors_list and friends and random_adaptor.
- * We need a sleepable lock for uiomove/block/poll/sbuf/sysctl.
- */
-static struct sx random_adaptors_lock;
-LIST_HEAD(adaptors_head, random_adaptors);
-static struct adaptors_head random_adaptors_list = LIST_HEAD_INITIALIZER(random_adaptors_list);
-static struct random_adaptor *random_adaptor = NULL; /* Currently active adaptor */
-/* End of data items requiring random_adaptors_lock protection */
-
-/* The random_readrate_mtx mutex protects the read-rate estimator.
- */
-static struct mtx random_read_rate_mtx;
-static int random_adaptor_read_rate_cache;
-/* End of data items requiring random_readrate_mtx mutex protection */
-
-static struct selinfo rsel;
-
-/* Utility routine to change active adaptor when the random_adaptors_list
- * gets modified.
- *
- * Walk a list of registered random(4) adaptors and pick either a requested
- * one or the highest priority one, whichever comes first. Panic on failure
- * as the fallback must always be the "dummy" adaptor.
- */
-static void
-random_adaptor_choose(void)
-{
- char rngs[128], *token, *cp;
- struct random_adaptors *rra, *rrai;
- struct random_adaptor *random_adaptor_previous;
- int primax;
-
- /* We are going to be messing with random_adaptor.
- * Exclusive lock is mandatory.
- */
- sx_assert(&random_adaptors_lock, SA_XLOCKED);
-
- random_adaptor_previous = random_adaptor;
-
- random_adaptor = NULL;
- if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) {
- cp = rngs;
-
- /* XXX: FIX!! (DES):
- * - fetch tunable once, at boot
- * - make sysctl r/w
- * - when fetching tunable or processing a sysctl
- * write, parse into list of strings so we don't
- * have to do it here again and again
- * - sysctl read should return a reconstructed string
- */
- while ((token = strsep(&cp, ",")) != NULL) {
- LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
- if (strcmp(rra->rra_name, token) == 0) {
- random_adaptor = rra->rra_ra;
- break;
- }
- if (random_adaptor != NULL) {
- printf("random: selecting requested adaptor <%s>\n",
- random_adaptor->ra_ident);
- break;
- }
- else
- printf("random: requested adaptor <%s> not available\n",
- token);
- }
- }
-
- primax = 0;
- if (random_adaptor == NULL) {
- /*
- * Fall back to the highest priority item on the available
- * RNG list.
- */
- LIST_FOREACH(rrai, &random_adaptors_list, rra_entries) {
- if (rrai->rra_ra->ra_priority >= primax) {
- random_adaptor = rrai->rra_ra;
- primax = rrai->rra_ra->ra_priority;
- }
- }
- if (random_adaptor != NULL)
- printf("random: selecting highest priority adaptor <%s>\n",
- random_adaptor->ra_ident);
- }
-
- KASSERT(random_adaptor != NULL, ("adaptor not found"));
-
- /* If we are changing adaptors, deinit the old and init the new. */
- if (random_adaptor != random_adaptor_previous) {
-#ifdef RANDOM_DEBUG
- printf("random: %s - changing from %s to %s\n", __func__,
- (random_adaptor_previous == NULL ? "NULL" : random_adaptor_previous->ra_ident),
- random_adaptor->ra_ident);
-#endif
- if (random_adaptor_previous != NULL) {
- randomdev_deinit_reader();
- (random_adaptor_previous->ra_deinit)();
- }
- (random_adaptor->ra_init)();
- }
-
- randomdev_init_reader(random_adaptor->ra_read);
-}
-
-
-/* XXX: FIX!! Make sure we are not inserting a duplicate */
-void
-random_adaptor_register(const char *name, struct random_adaptor *ra)
-{
- struct random_adaptors *rra;
-
- KASSERT(name != NULL && ra != NULL, ("invalid input to %s", __func__));
-
- rra = malloc(sizeof(*rra), M_ENTROPY, M_WAITOK);
- rra->rra_name = name;
- rra->rra_ra = ra;
-
- sx_xlock(&random_adaptors_lock);
- LIST_INSERT_HEAD(&random_adaptors_list, rra, rra_entries);
- random_adaptor_choose();
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- sx_xunlock(&random_adaptors_lock);
-}
-
-void
-random_adaptor_deregister(const char *name)
-{
- struct random_adaptors *rra;
-
- KASSERT(name != NULL, ("invalid input to %s", __func__));
-
- sx_xlock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
- LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
- if (strcmp(rra->rra_name, name) == 0) {
- LIST_REMOVE(rra, rra_entries);
- break;
- }
- random_adaptor_choose();
- sx_xunlock(&random_adaptors_lock);
-
- free(rra, M_ENTROPY);
-}
-
-/* ARGSUSED */
-int
-random_adaptor_read(struct cdev *dev __unused, struct uio *uio, int flags)
-{
- void *random_buf;
- int c, error;
- ssize_t nbytes;
-
-#ifdef RANDOM_DEBUG_VERBOSE
- printf("random: %s %ld\n", __func__, uio->uio_resid);
-#endif
-
- random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- /* Let the entropy source do any pre-read setup. */
- (random_adaptor->ra_read)(NULL, 0);
-
- /* (Un)Blocking logic */
- error = 0;
- while (!random_adaptor->ra_seeded() && error == 0) {
- if (flags & O_NONBLOCK) {
- error = EWOULDBLOCK;
- break;
- }
-
- /* Sleep instead of going into a spin-frenzy */
- error = sx_sleep(&random_adaptor, &random_adaptors_lock,
- PUSER | PCATCH, "randrd", hz/10);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s",
- __func__));
-
- /* keep tapping away at the pre-read until we seed/unblock. */
- (random_adaptor->ra_read)(NULL, 0);
- }
-
- mtx_lock(&random_read_rate_mtx);
-
- /* The read-rate stuff is a rough indication of the instantaneous read rate,
- * used to increase the use of 'live' entropy sources when lots of reads are done.
- */
- nbytes = (uio->uio_resid + 32 - 1)/32; /* Round up to units of 32 */
- random_adaptor_read_rate_cache += nbytes*32;
- random_adaptor_read_rate_cache = MIN(random_adaptor_read_rate_cache, 32);
-
- mtx_unlock(&random_read_rate_mtx);
-
- if (error == 0) {
- nbytes = uio->uio_resid;
-
- /* The actual read */
- while (uio->uio_resid && !error) {
- c = MIN(uio->uio_resid, PAGE_SIZE);
- (random_adaptor->ra_read)(random_buf, c);
- error = uiomove(random_buf, c, uio);
- }
-
- /* Let the entropy source do any post-read cleanup. */
- (random_adaptor->ra_read)(NULL, 1);
-
- if (nbytes != uio->uio_resid && (error == ERESTART ||
- error == EINTR) )
- error = 0; /* Return partial read, not error. */
-
- }
- sx_sunlock(&random_adaptors_lock);
-
- free(random_buf, M_ENTROPY);
-
- return (error);
-}
-
-int
-random_adaptor_read_rate(void)
-{
- int ret;
-
- mtx_lock(&random_read_rate_mtx);
-
- ret = random_adaptor_read_rate_cache;
- random_adaptor_read_rate_cache = 1;
-
- mtx_unlock(&random_read_rate_mtx);
-
- return (ret);
-}
-
-/* ARGSUSED */
-int
-random_adaptor_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
-{
- int c, error = 0;
- void *random_buf;
- ssize_t nbytes;
-
-#ifdef RANDOM_DEBUG
- printf("random: %s %zd\n", __func__, uio->uio_resid);
-#endif
-
- random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- nbytes = uio->uio_resid;
- while (uio->uio_resid > 0 && error == 0) {
- c = MIN(uio->uio_resid, PAGE_SIZE);
- error = uiomove(random_buf, c, uio);
- if (error)
- break;
- (random_adaptor->ra_write)(random_buf, c);
-
- /* Introduce an annoying delay to stop swamping */
- error = sx_sleep(&random_adaptor, &random_adaptors_lock,
- PUSER | PCATCH, "randwr", hz/10);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s",
- __func__));
- }
-
- sx_sunlock(&random_adaptors_lock);
-
- if (nbytes != uio->uio_resid && (error == ERESTART ||
- error == EINTR) )
- error = 0; /* Partial write, not error. */
-
- free(random_buf, M_ENTROPY);
-
- return (error);
-}
-
-/* ARGSUSED */
-int
-random_adaptor_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- sx_slock(&random_adaptors_lock);
-
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- if (events & (POLLIN | POLLRDNORM)) {
- if (random_adaptor->ra_seeded())
- events &= (POLLIN | POLLRDNORM);
- else
- selrecord(td, &rsel);
- }
-
- sx_sunlock(&random_adaptors_lock);
-
- return (events);
-}
-
-/* This will be called by the entropy processor when it seeds itself and becomes secure */
-void
-random_adaptor_unblock(void)
-{
-
- selwakeuppri(&rsel, PUSER);
- wakeup(&random_adaptor);
- printf("random: unblocking device.\n");
-
- /* Do arc4random(9) a favour while we are about it. */
- (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
-}
-
-static int
-random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
-{
- struct random_adaptors *rra;
- struct sbuf sbuf;
- int error, count;
-
- sx_slock(&random_adaptors_lock);
- sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
- count = 0;
- LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
- sbuf_printf(&sbuf, "%s%s(%d)",
- (count++ ? "," : ""), rra->rra_name, rra->rra_ra->ra_priority);
-
- error = sbuf_finish(&sbuf);
- sbuf_delete(&sbuf);
- sx_sunlock(&random_adaptors_lock);
-
- return (error);
-}
-
-static int
-random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS)
-{
- struct random_adaptors *rra;
- struct sbuf sbuf;
- int error;
-
- sx_slock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- sbuf_new_for_sysctl(&sbuf, NULL, 16, req);
- LIST_FOREACH(rra, &random_adaptors_list, rra_entries)
- if (rra->rra_ra == random_adaptor) {
- sbuf_cat(&sbuf, rra->rra_name);
- break;
- }
- error = sbuf_finish(&sbuf);
- sbuf_delete(&sbuf);
- sx_sunlock(&random_adaptors_lock);
-
- return (error);
-}
-
-void
-random_adaptors_init(void)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- SYSCTL_PROC(_kern_random, OID_AUTO, adaptors,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, random_sysctl_adaptors_handler, "A",
- "Random Number Generator adaptors");
-
- SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor,
- CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
- NULL, 0, random_sysctl_active_adaptor_handler, "A",
- "Active Random Number Generator Adaptor");
-
- sx_init(&random_adaptors_lock, "random_adaptors");
-
- mtx_init(&random_read_rate_mtx, "read rate mutex", NULL, MTX_DEF);
-
- /* The dummy adaptor is not a module by itself, but part of the
- * randomdev module.
- */
- random_adaptor_register("dummy", &randomdev_dummy);
-
- live_entropy_sources_init();
-}
-
-void
-random_adaptors_deinit(void)
-{
-
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- live_entropy_sources_deinit();
-
- /* Don't do this! Panic will surely follow! */
- /* random_adaptor_deregister("dummy"); */
-
- mtx_destroy(&random_read_rate_mtx);
-
- sx_destroy(&random_adaptors_lock);
-}
-
-/*
- * Reseed the active adaptor shortly before starting init(8).
- */
-/* ARGSUSED */
-static void
-random_adaptors_seed(void *unused __unused)
-{
-
- sx_slock(&random_adaptors_lock);
- KASSERT(random_adaptor != NULL, ("No active random adaptor in %s", __func__));
-
- random_adaptor->ra_reseed();
- sx_sunlock(&random_adaptors_lock);
-
- arc4rand(NULL, 0, 1);
-}
-SYSINIT(random_seed, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST,
- random_adaptors_seed, NULL);
Index: sys/dev/random/random_harvestq.h
===================================================================
--- sys/dev/random/random_harvestq.h
+++ sys/dev/random/random_harvestq.h
@@ -1,6 +1,5 @@
/*-
- * Copyright (c) 2013-2014 Mark R V Murray
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,43 +27,26 @@
*/
#ifndef SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
+#define SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED
-#define HARVESTSIZE 16 /* max size of each harvested entropy unit */
+#define HARVESTSIZE 2 /* Max length in words of each harvested entropy unit */
/* These are used to queue harvested packets of entropy. The entropy
* buffer size is pretty arbitrary.
*/
struct harvest_event {
- uintmax_t he_somecounter; /* fast counter for clock jitter */
- uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
- u_int he_size; /* harvested entropy byte count */
- u_int he_bits; /* stats about the entropy */
- u_int he_destination; /* destination pool of this entropy */
- enum random_entropy_source he_source; /* origin of the entropy */
-};
-
-void random_harvestq_init(void (*)(struct harvest_event *), int);
-void random_harvestq_deinit(void);
-void random_harvestq_internal(const void *, u_int, u_int, enum random_entropy_source);
-
-/* Pool count is used by anything needing to know how many entropy
- * pools are currently being maintained.
- * This is of use to (e.g.) the live source feed where we need to give
- * all the pools a top-up.
- */
-extern int harvest_pool_count;
-
-/* This is in randomdev.c as it needs to be permanently in the kernel */
-void randomdev_set_wakeup_exit(void *);
-
-/* Force all currently pending queue contents to clear, and kick the software processor */
-void random_harvestq_flush(void);
-
-/* Function called to process one harvested stochastic event */
-extern void (*harvest_process_event)(struct harvest_event *);
-
-/* Round-robin destination cache. */
-extern u_int harvest_destination[ENTROPYSOURCE];
+ uint32_t he_somecounter; /* fast counter for clock jitter */
+ uint32_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ uint8_t he_size; /* harvested entropy byte count */
+ uint8_t he_bits; /* stats about the entropy */
+ uint8_t he_destination; /* destination pool of this entropy */
+ uint8_t he_source; /* origin of the entropy */
+} __packed;
+
+#define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy"
+
+#define RANDOM_HARVEST_INIT_LOCK(x) mtx_init(&harvest_context.hc_mtx, "entropy harvest mutex", NULL, MTX_SPIN)
+#define RANDOM_HARVEST_LOCK(x) mtx_lock_spin(&harvest_context.hc_mtx)
+#define RANDOM_HARVEST_UNLOCK(x) mtx_unlock_spin(&harvest_context.hc_mtx)
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
Index: sys/dev/random/random_harvestq.c
===================================================================
--- sys/dev/random/random_harvestq.c
+++ sys/dev/random/random_harvestq.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2014 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* Copyright (c) 2013 Arthur Mesh
* Copyright (c) 2004 Robert N. M. Watson
* All rights reserved.
@@ -30,16 +30,17 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_random.h"
-
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/conf.h>
#include <sys/eventhandler.h>
+#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sbuf.h>
@@ -49,9 +50,9 @@
#include <machine/cpu.h>
#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#include <dev/random/live_entropy_sources.h>
+
+static void random_kthread(void);
/* List for the dynamic sysctls */
static struct sysctl_ctx_list random_clist;
@@ -62,122 +63,111 @@
* supplied junk. When used, they are transferred back to the
* 'empty' queue.
*/
-#define RANDOM_FIFO_MAX 1024
+#define RANDOM_RING_MAX 1024
+#define RANDOM_ACCUM_MAX 8
-/*
- * The harvest mutex protects the consistency of the entropy Fifos and
- * empty fifo and other associated structures.
- */
-static struct mtx harvest_mtx;
+/* 1 to let the kernel thread run, 0 to terminate */
+volatile int random_kthread_control;
/*
- * Lockable FIFO ring buffer holding entropy events
- * If ring_in == ring_out,
- * the buffer is empty.
- * If (ring_in + 1) == ring_out (MOD RANDOM_FIFO_MAX),
- * the buffer is full.
- *
- * The ring_in variable needs locking as there are multiple
- * sources to the ring. Only the sources may change ring_in,
- * but the consumer may examine it.
- *
- * The ring_out variable does not need locking as there is
- * only one consumer. Only the consumer may change ring_out,
- * but the sources may examine it.
+ * Put all the harvest queue context stuff in one place.
+ * this make is a bit easier to lock and protect.
*/
-static struct entropyfifo {
- struct harvest_event ring[RANDOM_FIFO_MAX];
- volatile u_int ring_in;
- volatile u_int ring_out;
-} entropyfifo;
-
-/* Round-robin destination cache. */
-u_int harvest_destination[ENTROPYSOURCE];
-
-/* Function called to process one harvested stochastic event */
-void (*harvest_process_event)(struct harvest_event *);
-
-/* Allow the sysadmin to select the broad category of
- * entropy types to harvest.
- */
-static u_int harvest_source_mask = ((1U << RANDOM_ENVIRONMENTAL_END) - 1);
-
-/* Pool count is used by anything needing to know how many entropy
- * pools are currently being maintained.
- * This is of use to (e.g.) the live source feed where we need to give
- * all the pools a top-up.
- */
-int harvest_pool_count;
+static struct harvest_context {
+ /* The harvest mutex protects the consistency of the entropy Fifos and
+ * empty fifo and other associated structures.
+ */
+ struct mtx hc_mtx;
+ /* Round-robin destination cache. */
+ u_int hc_destination[ENTROPYSOURCE];
+ /* The context of the kernel thread processing harvested entropy */
+ struct proc *hc_kthread_proc;
+ /* Allow the sysadmin to select the broad category of
+ * entropy types to harvest.
+ */
+ u_int hc_source_mask;
+ /*
+ * Lockless ring buffer holding entropy events
+ * If ring.in == ring.out,
+ * the buffer is empty.
+ * If ring.in != ring.out,
+ * the buffer contains harvested entropy.
+ * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX),
+ * the buffer is full.
+ *
+ * The ring.in variable needs locking as there are multiple
+ * sources to the ring. Only the sources may change ring.in,
+ * but the consumer may examine it.
+ *
+ * The ring.out variable does not need locking as there is
+ * only one consumer. Only the consumer may change ring.out,
+ * but the sources may examine it.
+ */
+ struct entropy_ring {
+ struct harvest_event ring[RANDOM_RING_MAX];
+ volatile u_int in;
+ volatile u_int out;
+ } hc_entropy_ring;
+ struct fast_entropy_accumulator {
+ volatile u_int pos;
+ uint32_t buf[8];
+ } hc_entropy_fast_accumulator;
+} harvest_context;
+
+static struct kproc_desc random_proc_kp = {
+ "rand_harvestq",
+ random_kthread,
+ &harvest_context.hc_kthread_proc,
+};
-/* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */
-static int random_kthread_control = 0;
-static struct proc *random_kthread_proc;
+/* Pass the given event straight through to Fortuna/Yarrow/Whatever. */
+static __inline void
+random_harvestq_fast_process_event(struct harvest_event *event)
+{
+ if (random_alg_context.ra_event_processor)
+ random_alg_context.ra_event_processor(event);
+}
static void
-random_kthread(void *arg __unused)
+random_kthread(void)
{
- u_int maxloop, ring_out;
+ u_int maxloop, ring_out, i;
/*
- * Process until told to stop.
- *
- * Locking is not needed as this is the only place we modify ring_out, and
- * we only examine ring_in without changing it. Both of these are volatile,
+ * Locking is not needed as this is the only place we modify ring.out, and
+ * we only examine ring.in without changing it. Both of these are volatile,
* and this is a unique thread.
*/
- while (random_kthread_control >= 0) {
-
+ for (random_kthread_control = 1; random_kthread_control;) {
/* Deal with events, if any. Restrict the number we do in one go. */
- maxloop = RANDOM_FIFO_MAX;
- while (entropyfifo.ring_out != entropyfifo.ring_in) {
-
- ring_out = (entropyfifo.ring_out + 1)%RANDOM_FIFO_MAX;
- harvest_process_event(entropyfifo.ring + ring_out);
- /* Modifying ring_out here ONLY. Sufficient for atomicity? */
- entropyfifo.ring_out = ring_out;
-
- /* The ring may be filled quickly so don't loop forever. */
- if (--maxloop)
+ maxloop = RANDOM_RING_MAX;
+ while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) {
+ ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX;
+ random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out);
+ harvest_context.hc_entropy_ring.out = ring_out;
+ if (!--maxloop)
break;
-
}
-
- /*
- * Give the fast hardware sources a go
- */
- live_entropy_sources_feed();
-
- /*
- * If a queue flush was commanded, it has now happened,
- * and we can mark this by resetting the command.
- * A negative value, however, terminates the thread.
- */
-
- if (random_kthread_control == 1)
- random_kthread_control = 0;
-
- /* Some work is done, so give the rest of the OS a chance. */
- tsleep_sbt(&random_kthread_control, 0, "-", SBT_1S/10, 0, C_PREL(1));
-
+ random_sources_feed();
+ /* XXX: FIX!! This This seems a little slow; 8 items every 0.1s from UMA? */
+ for (i = 0; i < RANDOM_ACCUM_MAX; i++) {
+ if (harvest_context.hc_entropy_fast_accumulator.buf[i]) {
+ random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), 4, RANDOM_FAST);
+ harvest_context.hc_entropy_fast_accumulator.buf[i] = 0;
+ }
+ }
+ /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */
+ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1));
}
-
- randomdev_set_wakeup_exit(&random_kthread_control);
+ wakeup(&harvest_context.hc_kthread_proc);
+ kproc_exit(0);
/* NOTREACHED */
}
-
-void
-random_harvestq_flush(void)
-{
-
- /* Command a entropy queue flush and wait for it to finish */
- random_kthread_control = 1;
- while (random_kthread_control)
- pause("-", hz/10);
-}
+SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp);
/* ARGSUSED */
-RANDOM_CHECK_UINT(harvestmask, 0, ((1U << RANDOM_ENVIRONMENTAL_END) - 1));
+RANDOM_CHECK_UINT(harvestmask, 0, RANDOM_HARVEST_EVERYTHING_MASK);
/* ARGSUSED */
static int
@@ -189,12 +179,11 @@
error = sysctl_wire_old_buffer(req, 0);
if (error == 0) {
sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
- for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--)
- sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? "1" : "0");
+ for (i = RANDOM_ENVIRONMENTAL_END; i >= 0; i--)
+ sbuf_cat(&sbuf, (harvest_context.hc_source_mask & (1 << i)) ? "1" : "0");
error = sbuf_finish(&sbuf);
sbuf_delete(&sbuf);
}
-
return (error);
}
@@ -208,8 +197,8 @@
"NET_NG",
"INTERRUPT",
"SWI",
- "UMA_ALLOC",
- "", /* "ENVIRONMENTAL_END" */
+ "FS_ATIME",
+ "HIGH_PERFORMANCE", /* ENVIRONMENTAL_END */
"PURE_OCTEON",
"PURE_SAFE",
"PURE_GLXSB",
@@ -231,112 +220,111 @@
error = sysctl_wire_old_buffer(req, 0);
if (error == 0) {
sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
- for (i = RANDOM_ENVIRONMENTAL_END - 1; i >= 0; i--) {
- sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END - 1) ? "" : ",");
- sbuf_cat(&sbuf, (harvest_source_mask & (1U << i)) ? random_source_descr[i] : "");
+ for (i = RANDOM_ENVIRONMENTAL_END; i >= 0; i--) {
+ sbuf_cat(&sbuf, (i == RANDOM_ENVIRONMENTAL_END) ? "" : ",");
+ sbuf_cat(&sbuf, !(harvest_context.hc_source_mask & (1 << i)) ? "[" : "");
+ sbuf_cat(&sbuf, random_source_descr[i]);
+ sbuf_cat(&sbuf, !(harvest_context.hc_source_mask & (1 << i)) ? "]" : "");
}
error = sbuf_finish(&sbuf);
sbuf_delete(&sbuf);
}
-
return (error);
}
-void
-random_harvestq_init(void (*event_processor)(struct harvest_event *), int poolcount)
+/* ARGSUSED */
+static void
+random_harvestq_init(void *unused __unused)
{
- uint8_t *keyfile, *data;
- int error;
- size_t size, j;
struct sysctl_oid *random_sys_o;
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
+ if (bootverbose)
+ printf("random: %s\n", __func__);
random_sys_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "harvest", CTLFLAG_RW, 0,
"Entropy Device Parameters");
-
+ harvest_context.hc_source_mask = RANDOM_HARVEST_EVERYTHING_MASK;
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_o),
OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW,
- &harvest_source_mask, ((1U << RANDOM_ENVIRONMENTAL_END) - 1),
+ &harvest_context.hc_source_mask, 0,
random_check_uint_harvestmask, "IU",
"Entropy harvesting mask");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_o),
OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD,
NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_o),
OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD,
NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)");
+ RANDOM_HARVEST_INIT_LOCK();
+ harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0;
+}
+SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL);
- /* Point to the correct event_processing function */
- harvest_process_event = event_processor;
-
- /* Store the pool count (used by live source feed) */
- harvest_pool_count = poolcount;
-
- /* Initialise the harvesting mutex and in/out indexes. */
- mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN);
- entropyfifo.ring_in = entropyfifo.ring_out = 0U;
-
- /* Start the hash/reseed thread */
- error = kproc_create(random_kthread, NULL,
- &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq");
-
- if (error != 0)
- panic("Cannot create entropy maintenance thread.");
+/*
+ * This is used to prime the RNG by grabbing any early random stuff
+ * known to the kernel, and inserting it directly into the hashing
+ * module, e.g. Fortuna or Yarrow.
+ */
+/* ARGSUSED */
+static void
+random_harvestq_prime(void *unused __unused)
+{
+ struct harvest_event event;
+ size_t count, size, i;
+ uint8_t *keyfile, *data;
- /* Get entropy that may have been preloaded by loader(8)
+ /*
+ * Get entropy that may have been preloaded by loader(8)
* and use it to pre-charge the entropy harvest queue.
*/
- keyfile = preload_search_by_type("/boot/entropy");
+ keyfile = preload_search_by_type(RANDOM_HARVESTQ_BOOT_ENTROPY_FILE);
if (keyfile != NULL) {
data = preload_fetch_addr(keyfile);
size = preload_fetch_size(keyfile);
if (data != NULL && size != 0) {
- for (j = 0; j < size; j += 16)
- random_harvestq_internal(data + j, 16, 16, RANDOM_CACHED);
- printf("random: read %zu bytes from preloaded cache\n", size);
- bzero(data, size);
- }
- else
- printf("random: no preloaded entropy cache\n");
+ for (i = 0; i < size; i += sizeof(event.he_entropy)) {
+ count = sizeof(event.he_entropy);
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = count;
+ event.he_bits = count/4; /* Underestimate the size for Yarrow */
+ event.he_source = RANDOM_CACHED;
+ event.he_destination = harvest_context.hc_destination[0]++;
+ memcpy(event.he_entropy, data + i, sizeof(event.he_entropy));
+ random_harvestq_fast_process_event(&event);
+ explicit_bzero(&event, sizeof(event));
+ }
+ explicit_bzero(data, size);
+ if (bootverbose)
+ printf("random: read %zu bytes from preloaded cache\n", size);
+ } else
+ if (bootverbose)
+ printf("random: no preloaded entropy cache\n");
}
-
}
+SYSINIT(random_device_prime, SI_SUB_RANDOM, SI_ORDER_FOURTH, random_harvestq_prime, NULL);
-void
-random_harvestq_deinit(void)
+/* ARGSUSED */
+static void
+random_harvestq_deinit(void *unused __unused)
{
-#ifdef RANDOM_DEBUG
- printf("random: %s\n", __func__);
-#endif
-
- /*
- * Command the hash/reseed thread to end and wait for it to finish
- */
- random_kthread_control = -1;
- tsleep(&random_kthread_control, 0, "term", 0);
-
- mtx_destroy(&harvest_mtx);
-
+ /* Command the hash/reseed thread to end and wait for it to finish */
+ random_kthread_control = 0;
+ tsleep(&harvest_context.hc_kthread_proc, 0, "term", 0);
sysctl_ctx_free(&random_clist);
}
+SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL);
-/*
- * Entropy harvesting routine.
- * This is supposed to be fast; do not do anything slow in here!
+/*-
+ * Entropy harvesting queue routine.
*
+ * This is supposed to be fast; do not do anything slow in here!
* It is also illegal (and morally reprehensible) to insert any
- * high-rate data here. "High-rate" is define as a data source
+ * high-rate data here. "High-rate" is defined as a data source
* that will usually cause lots of failures of the "Lockless read"
* check a few lines below. This includes the "always-on" sources
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources.
@@ -346,37 +334,78 @@
* read which can be quite expensive.
*/
void
-random_harvestq_internal(const void *entropy, u_int count, u_int bits,
- enum random_entropy_source origin)
+random_harvest_queue(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
{
struct harvest_event *event;
u_int ring_in;
- KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE,
- ("random_harvest_internal: origin %d invalid\n", origin));
-
- /* Mask out unwanted sources */
- if (!(harvest_source_mask & (1U << origin)))
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
return;
-
- /* Lock ring_in against multi-thread contention */
- mtx_lock_spin(&harvest_mtx);
- ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX;
- if (ring_in != entropyfifo.ring_out) {
+ RANDOM_HARVEST_LOCK();
+ ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX;
+ if (ring_in != harvest_context.hc_entropy_ring.out) {
/* The ring is not full */
- event = entropyfifo.ring + ring_in;
-
- /* Stash the harvested stuff in the *event buffer */
- count = MIN(count, HARVESTSIZE);
- event->he_somecounter = get_cyclecount();
- event->he_size = count;
- event->he_bits = bits;
+ event = harvest_context.hc_entropy_ring.ring + ring_in;
+ event->he_somecounter = (uint32_t)get_cyclecount();
event->he_source = origin;
- event->he_destination = harvest_destination[origin]++;
- memcpy(event->he_entropy, entropy, count);
- memset(event->he_entropy + count, 0, HARVESTSIZE - count);
-
- entropyfifo.ring_in = ring_in;
+ event->he_destination = harvest_context.hc_destination[origin]++;
+ event->he_bits = bits;
+ if (count <= sizeof(event->he_entropy)) {
+ event->he_size = count;
+ memcpy(event->he_entropy, entropy, count);
+ }
+ else {
+ /* Big event, so squash it */
+ event->he_size = sizeof(event->he_entropy[0]);
+ event->he_entropy[0] = jenkins_hash(entropy, count, (uint32_t)(uintptr_t)event);
+ }
+ harvest_context.hc_entropy_ring.in = ring_in;
}
- mtx_unlock_spin(&harvest_mtx);
+ RANDOM_HARVEST_UNLOCK();
+}
+
+/*-
+ * Entropy harvesting fast routine.
+ *
+ * This is supposed to be very fast; do not do anything slow in here!
+ * This is the right place for high-rate harvested data.
+ */
+void
+random_harvest_fast(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
+{
+ u_int pos;
+
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ /* XXX: FIX!! The above KASSERT is BS. Right now we ignore most structure and just accumulate the supplied data */
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
+ return;
+ pos = harvest_context.hc_entropy_fast_accumulator.pos;
+ harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, count, (uint32_t)get_cyclecount());
+ harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX;
+}
+
+/*-
+ * Entropy harvesting direct routine.
+ *
+ * This is not supposed to be fast, but will only be used during
+ * (e.g.) booting when initial entropy is being gathered.
+ */
+void
+random_harvest_direct(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
+{
+ struct harvest_event event;
+
+ KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin));
+ if (!(harvest_context.hc_source_mask & (1 << origin)))
+ return;
+ count = MIN(count, sizeof(event.he_entropy));
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = count;
+ event.he_bits = bits;
+ event.he_source = origin;
+ event.he_destination = harvest_context.hc_destination[origin]++;
+ memcpy(event.he_entropy, entropy, count);
+ random_harvestq_fast_process_event(&event);
+ explicit_bzero(&event, sizeof(event));
}
Index: sys/dev/random/randomdev.h
===================================================================
--- sys/dev/random/randomdev.h
+++ sys/dev/random/randomdev.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,41 +27,87 @@
*/
#ifndef SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
+#define SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED
/* This header contains only those definitions that are global
* and non algorithm-specific for the entropy processor
*/
-typedef void random_init_func_t(void);
-typedef void random_deinit_func_t(void);
-
-void randomdev_init_harvester(void (*)(const void *, u_int, u_int, enum random_entropy_source));
-void randomdev_init_reader(void (*)(uint8_t *, u_int));
-void randomdev_deinit_harvester(void);
-void randomdev_deinit_reader(void);
-
-/* Stub/fake routines for when no entropy processor is loaded */
-extern void dummy_random_read_phony(uint8_t *, u_int);
-
-/* kern.random sysctls */
#ifdef SYSCTL_DECL /* from sysctl.h */
SYSCTL_DECL(_kern_random);
-/* If this was C++, the macro below would be a template */
-#define RANDOM_CHECK_UINT(name, min, max) \
+#define RANDOM_CHECK_UINT(name, min, max) \
static int \
random_check_uint_##name(SYSCTL_HANDLER_ARGS) \
{ \
if (oidp->oid_arg1 != NULL) { \
- if (*(u_int *)(oidp->oid_arg1) <= (min)) \
+ if (*(u_int *)(oidp->oid_arg1) <= (min)) \
*(u_int *)(oidp->oid_arg1) = (min); \
- else if (*(u_int *)(oidp->oid_arg1) > (max)) \
+ else if (*(u_int *)(oidp->oid_arg1) > (max)) \
*(u_int *)(oidp->oid_arg1) = (max); \
} \
- return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
+ return (sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, \
req)); \
}
#endif /* SYSCTL_DECL */
-#endif
+MALLOC_DECLARE(M_ENTROPY);
+
+#define RANDOM_ALG_READ_RATE_MINIMUM 32
+
+struct harvest_event;
+
+typedef void random_alg_pre_read_t(void);
+typedef void random_alg_read_t(uint8_t *, u_int);
+typedef void random_alg_post_read_t(void);
+typedef void random_alg_write_t(uint8_t *, u_int);
+typedef int random_alg_seeded_t(void);
+typedef void random_alg_reseed_t(void);
+typedef void random_alg_eventprocessor_t(struct harvest_event *);
+
+typedef u_int random_source_read_t(void *, u_int);
+
+/*
+ * Random Algorithm is a processor of randomness for the kernel
+ * and for userland.
+ */
+struct random_algorithm {
+ const char *ra_ident;
+ u_int ra_poolcount;
+ random_alg_pre_read_t *ra_pre_read;
+ random_alg_read_t *ra_read;
+ random_alg_post_read_t *ra_post_read;
+ random_alg_write_t *ra_write;
+ random_alg_reseed_t *ra_reseed;
+ random_alg_seeded_t *ra_seeded;
+ random_alg_eventprocessor_t *ra_event_processor;
+};
+
+extern struct random_algorithm random_alg_context;
+
+/*
+ * Random Source is a source of entropy that can provide
+ * specified or approximate amount of entropy immediately
+ * upon request.
+ */
+struct random_source {
+ const char *rs_ident;
+ enum random_entropy_source rs_source;
+ random_source_read_t *rs_read;
+};
+
+#if !defined(RANDOM_DUMMY)
+struct random_sources {
+ LIST_ENTRY(random_sources) rrs_entries;
+ struct random_source *rrs_source;
+};
+#endif /* !defined(RANDOM_DUMMY) */
+
+void random_source_register(struct random_source *);
+void random_source_deregister(struct random_source *);
+
+void random_sources_feed(void);
+
+void randomdev_unblock(void);
+
+#endif /* SYS_DEV_RANDOM_RANDOMDEV_H_INCLUDED */
Index: sys/dev/random/randomdev.c
===================================================================
--- sys/dev/random/randomdev.c
+++ sys/dev/random/randomdev.c
@@ -1,6 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
- * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,28 +25,9 @@
*
*/
-/*
- * NOTE NOTE NOTE
- *
- * This file is compiled into the kernel unconditionally. Any random(4)
- * infrastructure that needs to be in the kernel by default goes here!
- *
- * Except ...
- *
- * The adaptor code all goes into random_adaptor.c, which is also compiled
- * the kernel by default. The module in that file is initialised before
- * this one.
- *
- * Other modules must be initialised after the above two, and are
- * software random processors which plug into random_adaptor.c.
- *
- */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include "opt_random.h"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -59,27 +39,42 @@
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/malloc.h>
+#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/random.h>
+#include <sys/sbuf.h>
+#include <sys/selinfo.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/unistd.h>
+#include <crypto/rijndael/rijndael-api-fst.h>
+#include <crypto/sha2/sha2.h>
+
+#include <dev/random/hash.h>
#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
-#define RANDOM_MINOR 0
+#include "opt_random.h"
+
+#if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW)
+#error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW"
+#endif
+#define RANDOM_MINOR 0
+
+static d_read_t randomdev_read;
+static d_write_t randomdev_write;
+static d_poll_t randomdev_poll;
static d_ioctl_t randomdev_ioctl;
static struct cdevsw random_cdevsw = {
.d_name = "random",
.d_version = D_VERSION,
- .d_read = random_adaptor_read,
- .d_write = random_adaptor_write,
- .d_poll = random_adaptor_poll,
+ .d_read = randomdev_read,
+ .d_write = randomdev_write,
+ .d_poll = randomdev_poll,
.d_ioctl = randomdev_ioctl,
};
@@ -87,163 +82,326 @@
static struct cdev *random_dev;
/* Set up the sysctl root node for the entropy device */
-SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
+SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator");
MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures");
-/* ARGSUSED */
-static int
-randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
- int flags __unused, struct thread *td __unused)
-{
- int error = 0;
-
- switch (cmd) {
- /* Really handled in upper layer */
- case FIOASYNC:
- case FIONBIO:
- break;
+#if defined(RANDOM_DUMMY)
- default:
- error = ENOTTY;
+/*-
+ * Dummy "always block" pseudo algorithm, used when there is no real
+ * random(4) driver to provide a CSPRNG.
+ */
- }
+static u_int
+dummy_random_zero(void)
+{
- return (error);
+ return (0);
}
-/* Helper routine to enable kproc_exit() to work while the module is
- * being (or has been) unloaded.
- * This routine is in this file because it is always linked into the kernel,
- * and will thus never be unloaded. This is critical for unloadable modules
- * that have threads.
- */
-void
-randomdev_set_wakeup_exit(void *control)
+static void
+dummy_random(void)
{
-
- wakeup(control);
- kproc_exit(0);
- /* NOTREACHED */
}
-/* ARGSUSED */
-static int
-randomdev_modevent(module_t mod __unused, int type, void *data __unused)
-{
- int error = 0;
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Dummy",
+ .ra_reseed = dummy_random,
+ .ra_seeded = (random_alg_seeded_t *)dummy_random_zero,
+ .ra_pre_read = dummy_random,
+ .ra_read = (random_alg_read_t *)dummy_random_zero,
+ .ra_post_read = dummy_random,
+ .ra_write = (random_alg_write_t *)dummy_random_zero,
+ .ra_event_processor = NULL,
+ .ra_poolcount = 0,
+};
- switch (type) {
- case MOD_LOAD:
- printf("random: entropy device infrastructure driver\n");
- random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
- RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
- make_dev_alias(random_dev, "urandom"); /* compatibility */
- random_adaptors_init();
- break;
+#else /* !defined(RANDOM_DUMMY) */
- case MOD_UNLOAD:
- random_adaptors_deinit();
- destroy_dev(random_dev);
- break;
+LIST_HEAD(sources_head, random_sources);
+static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
+static u_int read_rate;
- case MOD_SHUTDOWN:
- break;
+#endif /* defined(RANDOM_DUMMY) */
- default:
- error = EOPNOTSUPP;
- break;
+static struct selinfo rsel;
+/*
+ * This is the read uio(9) interface for random(4).
+ */
+/* ARGSUSED */
+static int
+randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags)
+{
+ uint8_t *random_buf;
+ int c, error;
+ ssize_t nbytes;
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ random_alg_context.ra_pre_read();
+ /* (Un)Blocking logic */
+ error = 0;
+ while (!random_alg_context.ra_seeded() && error == 0) {
+ if (flags & O_NONBLOCK) {
+ error = EWOULDBLOCK;
+ break;
+ }
+ tsleep(&random_alg_context, 0, "randrd", hz/10);
+ /* keep tapping away at the pre-read until we seed/unblock. */
+ random_alg_context.ra_pre_read();
+ printf("random: %s unblock (error = %d)\n", __func__, error);
}
-
+ if (error == 0) {
+#if !defined(RANDOM_DUMMY)
+ /* XXX: FIX!! Next line as an atomic operation? */
+ read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t);
+#endif
+ nbytes = uio->uio_resid;
+ while (uio->uio_resid && !error) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ random_alg_context.ra_read(random_buf, c);
+ error = uiomove(random_buf, c, uio);
+ }
+ random_alg_context.ra_post_read();
+ if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR) )
+ /* Return partial read, not error. */
+ error = 0;
+ }
+ free(random_buf, M_ENTROPY);
return (error);
}
-DEV_MODULE_ORDERED(randomdev, randomdev_modevent, NULL, SI_ORDER_SECOND);
-MODULE_VERSION(randomdev, 1);
-
-/* ================
- * Harvesting stubs
- * ================
+/*-
+ * Kernel API version of read_random().
+ * This is similar to random_alg_read(),
+ * except it doesn't interface with uio(9).
+ * It cannot assumed that random_buf is a multiple of
+ * RANDOM_BLOCKSIZE bytes.
*/
+u_int
+read_random(void *random_buf, u_int len)
+{
+ u_int read_len, total_read, c;
+ uint8_t local_buf[len + RANDOM_BLOCKSIZE];
+
+ KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__));
+ random_alg_context.ra_pre_read();
+ /* (Un)Blocking logic; if not seeded, return nothing. */
+ if (random_alg_context.ra_seeded()) {
+#if !defined(RANDOM_DUMMY)
+ /* XXX: FIX!! Next line as an atomic operation? */
+ read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t);
+#endif
+ read_len = len;
+ total_read = 0;
+ while (read_len) {
+ c = MIN(read_len, PAGE_SIZE);
+ random_alg_context.ra_read(&local_buf[total_read], c);
+ read_len -= c;
+ total_read += c;
+ }
+ memcpy(random_buf, local_buf, len);
+ } else
+ len = 0;
+ random_alg_context.ra_post_read();
+ return (len);
+}
-/* Internal stub/fake routine for when no entropy processor is loaded.
- * If the entropy device is not loaded, don't act on harvesting calls
- * and just return.
- */
/* ARGSUSED */
-static void
-random_harvest_phony(const void *entropy __unused, u_int count __unused,
- u_int bits __unused, enum random_entropy_source origin __unused)
+static int
+randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused)
{
+ uint8_t *random_buf;
+ int c, error = 0;
+ ssize_t nbytes;
+
+ random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK);
+ nbytes = uio->uio_resid;
+ while (uio->uio_resid > 0 && error == 0) {
+ c = MIN(uio->uio_resid, PAGE_SIZE);
+ error = uiomove(random_buf, c, uio);
+ if (error)
+ break;
+ random_alg_context.ra_write(random_buf, c);
+ tsleep(&random_alg_context, 0, "randwr", hz/10);
+ }
+ if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR))
+ /* Partial write, not error. */
+ error = 0;
+ free(random_buf, M_ENTROPY);
+ return (error);
}
-/* Hold the address of the routine which is actually called */
-static void (*reap_func)(const void *, u_int, u_int, enum random_entropy_source) = random_harvest_phony;
+/* ARGSUSED */
+static int
+randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
+{
-/* Initialise the harvester when/if it is loaded */
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (random_alg_context.ra_seeded())
+ events &= (POLLIN | POLLRDNORM);
+ else
+ selrecord(td, &rsel);
+ }
+ return (events);
+}
+
+/* This will be called by the entropy processor when it seeds itself and becomes secure */
void
-randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
+randomdev_unblock(void)
{
- reap_func = reaper;
+ selwakeuppri(&rsel, PUSER);
+ wakeup(&random_alg_context);
+ printf("random: unblocking device.\n");
+ /* Do random(9) a favour while we are about it. */
+ (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE);
}
-/* Deinitialise the harvester when/if it is unloaded */
-void
-randomdev_deinit_harvester(void)
+/* ARGSUSED */
+static int
+randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
+ int flags __unused, struct thread *td __unused)
{
+ int error = 0;
+
+ switch (cmd) {
+ /* Really handled in upper layer */
+ case FIOASYNC:
+ case FIONBIO:
+ break;
+ default:
+ error = ENOTTY;
+ }
- reap_func = random_harvest_phony;
+ return (error);
}
-/* Entropy harvesting routine.
- * Implemented as in indirect call to allow non-inclusion of
- * the entropy device.
- */
void
-random_harvest(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin)
+random_source_register(struct random_source *rsource)
{
+#if defined(RANDOM_DUMMY)
+ (void)rsource;
+#else /* !defined(RANDOM_DUMMY) */
+ struct random_sources *rrs;
- (*reap_func)(entropy, count, bits, origin);
-}
+ KASSERT(rsource != NULL, ("invalid input to %s", __func__));
-/* ================================
- * Internal reading stubs and fakes
- * ================================
- */
+ rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK);
+ rrs->rrs_source = rsource;
-/* Hold the address of the routine which is actually called */
-static void (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
+ printf("random: registering fast source %s\n", rsource->rs_ident);
+ LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
+#endif /* defined(RANDOM_DUMMY) */
+}
-/* Initialise the reader when/if it is loaded */
void
-randomdev_init_reader(void (*reader)(uint8_t *, u_int))
+random_source_deregister(struct random_source *rsource)
{
-
- read_func = reader;
+#if defined(RANDOM_DUMMY)
+ (void)rsource;
+#else /* !defined(RANDOM_DUMMY) */
+ struct random_sources *rrs = NULL;
+
+ KASSERT(rsource != NULL, ("invalid input to %s", __func__));
+ LIST_FOREACH(rrs, &source_list, rrs_entries)
+ if (rrs->rrs_source == rsource) {
+ LIST_REMOVE(rrs, rrs_entries);
+ break;
+ }
+ if (rrs != NULL)
+ free(rrs, M_ENTROPY);
+#endif /* defined(RANDOM_DUMMY) */
}
-/* Deinitialise the reader when/if it is unloaded */
+#if !defined(RANDOM_DUMMY)
+/*
+ * Run through all fast sources reading entropy for the given
+ * number of rounds, which should be a multiple of the number
+ * of entropy accumulation pools in use; 2 for Yarrow and 32
+ * for Fortuna.
+ *
+ * BEWARE!!!
+ * This function runs inside the RNG thread! Don't do anything silly!
+ */
void
-randomdev_deinit_reader(void)
+random_sources_feed(void)
{
+ uint32_t entropy[HARVESTSIZE];
+ struct random_sources *rrs;
+ u_int i, n, local_read_rate;
+
+ /*
+ * Step over all of live entropy sources, and feed their output
+ * to the system-wide RNG.
+ */
+ /* XXX: FIX!! Next lines as an atomic operation? */
+ local_read_rate = read_rate;
+ read_rate = RANDOM_ALG_READ_RATE_MINIMUM;
+ LIST_FOREACH(rrs, &source_list, rrs_entries) {
+ for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) {
+ n = rrs->rrs_source->rs_read(entropy, sizeof(entropy));
+ KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__));
+ random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source);
+ }
+ }
+ explicit_bzero(entropy, sizeof(entropy));
+}
- read_func = dummy_random_read_phony;
+static int
+random_source_handler(SYSCTL_HANDLER_ARGS)
+{
+ struct random_sources *rrs;
+ struct sbuf sbuf;
+ int error, count;
+
+ sbuf_new_for_sysctl(&sbuf, NULL, 64, req);
+ count = 0;
+ LIST_FOREACH(rrs, &source_list, rrs_entries) {
+ sbuf_cat(&sbuf, (count++ ? ",'" : "'"));
+ sbuf_cat(&sbuf, rrs->rrs_source->rs_ident);
+ sbuf_cat(&sbuf, "'");
+ }
+ error = sbuf_finish(&sbuf);
+ sbuf_delete(&sbuf);
+ return (error);
}
+SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, random_source_handler, "A",
+ "List of active fast entropy sources.");
+#endif /* !defined(RANDOM_DUMMY) */
-/* Kernel API version of read_random().
- * Implemented as in indirect call to allow non-inclusion of
- * the entropy device.
- */
-int
-read_random(void *buf, int count)
+/* ARGSUSED */
+static int
+randomdev_modevent(module_t mod __unused, int type, void *data __unused)
{
+ int error = 0;
- if (count < 0)
- return 0;
+ switch (type) {
+ case MOD_LOAD:
+ printf("random: entropy device external interface\n");
+ random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
+ RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random");
+ make_dev_alias(random_dev, "urandom"); /* compatibility */
+ break;
+ case MOD_UNLOAD:
+ destroy_dev(random_dev);
+ break;
+ case MOD_SHUTDOWN:
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
- read_func(buf, count);
+static moduledata_t randomdev_mod = {
+ "random_device",
+ randomdev_modevent,
+ 0
+};
- return count;
-}
+DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_VERSION(random_device, 1);
Index: sys/dev/random/randomdev_none.c
===================================================================
--- /dev/null
+++ sys/dev/random/randomdev_none.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2015 Mark R V Murray
+ * 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
+ * in this position and unchanged.
+ * 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 ``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 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/random.h>
+#include <sys/systm.h>
+
+#include <dev/random/randomdev.h>
+
+#include "opt_random.h"
+
+#if defined(RANDOM_DUMMY) || defined(RANDOM_YARROW)
+#error "Cannot define any of RANDOM_DUMMY and RANDOM_YARROW without 'device random'"
+#endif
+
+/*-
+ * Dummy "not even here" device. Stub out all routines that the kernel would need.
+ */
+
+/* ARGSUSED */
+u_int
+read_random(void *random_buf __unused, u_int len __unused)
+{
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+random_harvest_direct(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
+
+/* ARGSUSED */
+void
+random_harvest_queue(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
+
+/* ARGSUSED */
+void
+random_harvest_fast(const void *entropy __unused, u_int count __unused, u_int bits __unused, enum random_entropy_source origin __unused)
+{
+}
Index: sys/dev/random/randomdev_soft.h
===================================================================
--- sys/dev/random/randomdev_soft.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-
- * Copyright (c) 2000-2013 Mark R V Murray
- * 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
- * in this position and unchanged.
- * 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 ``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 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$
- */
-
-#ifndef SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
-#define SYS_DEV_RANDOM_RANDOMDEV_SOFT_H_INCLUDED
-
-/* This header contains only those definitions that are
- * specific to the entropy processor
- */
-
-void randomdev_init(void);
-void randomdev_deinit(void);
-
-#endif
Index: sys/dev/random/randomdev_soft.c
===================================================================
--- sys/dev/random/randomdev_soft.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*-
- * Copyright (c) 2000-2014 Mark R V Murray
- * Copyright (c) 2004 Robert N. M. Watson
- * 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
- * in this position and unchanged.
- * 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 ``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 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.
- *
- */
-
-/*
- * This is the loadable infrastructure base file for software CSPRNG
- * drivers such as Yarrow or Fortuna.
- *
- * It is anticipated that one instance of this file will be used
- * for _each_ invocation of a CSPRNG, but with different #defines
- * set. See below.
- *
- */
-
-#include "opt_random.h"
-
-#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
-#define RANDOM_YARROW
-#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
-#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
-#endif
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/poll.h>
-#include <sys/random.h>
-#include <sys/sysctl.h>
-#include <sys/unistd.h>
-
-#include <dev/random/randomdev.h>
-#include <dev/random/randomdev_soft.h>
-#include <dev/random/random_harvestq.h>
-#include <dev/random/random_adaptors.h>
-#if defined(RANDOM_YARROW)
-#include <dev/random/yarrow.h>
-#endif
-#if defined(RANDOM_FORTUNA)
-#include <dev/random/fortuna.h>
-#endif
-
-static struct random_adaptor random_soft_processor = {
-#if defined(RANDOM_YARROW)
-#define RANDOM_CSPRNG_NAME "yarrow"
- .ra_ident = "Yarrow",
- .ra_priority = 90, /* High priority, so top of the list. Fortuna may still win. */
- .ra_read = random_yarrow_read,
- .ra_write = random_yarrow_write,
- .ra_reseed = random_yarrow_reseed,
- .ra_seeded = random_yarrow_seeded,
-#endif
-#if defined(RANDOM_FORTUNA)
-#define RANDOM_CSPRNG_NAME "fortuna"
- .ra_ident = "Fortuna",
- .ra_priority = 100, /* High priority, so top of the list. Beat Yarrow. */
- .ra_read = random_fortuna_read,
- .ra_write = random_fortuna_write,
- .ra_reseed = random_fortuna_reseed,
- .ra_seeded = random_fortuna_seeded,
-#endif
- .ra_init = randomdev_init,
- .ra_deinit = randomdev_deinit,
-};
-
-void
-randomdev_init(void)
-{
-
-#if defined(RANDOM_YARROW)
- random_yarrow_init_alg();
- random_harvestq_init(random_yarrow_process_event, 2);
-#endif
-#if defined(RANDOM_FORTUNA)
- random_fortuna_init_alg();
- random_harvestq_init(random_fortuna_process_event, 32);
-#endif
-
- /* Register the randomness harvesting routine */
- randomdev_init_harvester(random_harvestq_internal);
-}
-
-void
-randomdev_deinit(void)
-{
- /* Deregister the randomness harvesting routine */
- randomdev_deinit_harvester();
-
-#if defined(RANDOM_YARROW)
- random_yarrow_deinit_alg();
-#endif
-#if defined(RANDOM_FORTUNA)
- random_fortuna_deinit_alg();
-#endif
-}
-
-/* ARGSUSED */
-static int
-randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
-{
- int error = 0;
-
- switch (type) {
- case MOD_LOAD:
- printf("random: SOFT: %s init()\n", RANDOM_CSPRNG_NAME);
- random_adaptor_register(RANDOM_CSPRNG_NAME, &random_soft_processor);
- break;
-
- case MOD_UNLOAD:
- random_adaptor_deregister(RANDOM_CSPRNG_NAME);
- break;
-
- case MOD_SHUTDOWN:
- break;
-
- default:
- error = EOPNOTSUPP;
- break;
-
- }
- return (error);
-}
-
-#if defined(RANDOM_YARROW)
-DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
-MODULE_VERSION(yarrow, 1);
-MODULE_DEPEND(yarrow, randomdev, 1, 1, 1);
-#endif
-#if defined(RANDOM_FORTUNA)
-DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
-MODULE_VERSION(fortuna, 1);
-MODULE_DEPEND(fortuna, randomdev, 1, 1, 1);
-#endif
Index: sys/dev/random/uint128.h
===================================================================
--- sys/dev/random/uint128.h
+++ sys/dev/random/uint128.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2014 Mark R V Murray
+ * Copyright (c) 2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,7 @@
*/
#ifndef SYS_DEV_RANDOM_UINT128_H_INCLUDED
-#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
+#define SYS_DEV_RANDOM_UINT128_H_INCLUDED
/* This whole thing is a crock :-(
*
@@ -35,40 +35,41 @@
*/
#ifdef __SIZEOF_INT128__
-typedef __uint128_t uint128_t;
-#else
-typedef uint64_t uint128_t[2];
+#define USE_REAL_UINT128_T
#endif
-static __inline void
-uint128_clear(uint128_t *big_uint)
-{
-#ifdef __SIZEOF_INT128__
- (*big_uint) = 0ULL;
+#ifdef USE_REAL_UINT128_T
+typedef __uint128_t uint128_t;
+#define UINT128_ZERO 0ULL
#else
- (*big_uint)[0] = (*big_uint)[1] = 0UL;
+typedef struct {
+ /* Ignore endianness */
+ uint64_t u128t_word0;
+ uint64_t u128t_word1;
+} uint128_t;
+static const uint128_t very_long_zero = {0UL,0UL};
+#define UINT128_ZERO very_long_zero
#endif
-}
static __inline void
-uint128_increment(uint128_t *big_uint)
+uint128_increment(uint128_t *big_uintp)
{
-#ifdef __SIZEOF_INT128__
- (*big_uint)++;
+#ifdef USE_REAL_UINT128_T
+ (*big_uintp)++;
#else
- (*big_uint)[0]++;
- if ((*big_uint)[0] == 0UL)
- (*big_uint)[1]++;
+ big_uintp->u128t_word0++;
+ if (big_uintp->u128t_word0 == 0UL)
+ big_uintp->u128t_word1++;
#endif
}
static __inline int
uint128_is_zero(uint128_t big_uint)
{
-#ifdef __SIZEOF_INT128__
- return (big_uint == 0ULL);
+#ifdef USE_REAL_UINT128_T
+ return (big_uint == UINT128_ZERO);
#else
- return (big_uint[0] == 0UL && big_uint[1] == 0UL);
+ return (big_uint.u128t_word0 == 0UL && big_uint.u128t_word1 == 0UL);
#endif
}
Index: sys/dev/random/unit_test.h
===================================================================
--- sys/dev/random/unit_test.h
+++ sys/dev/random/unit_test.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2013 Mark R V Murray
+ * Copyright (c) 2013-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,20 +28,39 @@
#ifndef UNIT_TEST_H_INCLUDED
-#define UNIT_TEST_H_INCLUDED
+#define UNIT_TEST_H_INCLUDED
+
+#ifdef _KERNEL
+#error "Random unit tests cannot be compiled into the kernel."
+#endif
void random_adaptor_unblock(void);
+#if defined(clang) && __has_builtin(__builtin_readcyclecounter)
+#define rdtsc __builtin_readcyclecounter
+#else /* !clang */
+#if defined(__amd64__) || defined(__i386__)
+static __inline uint64_t
+rdtsc(void)
+{
+ uint32_t low, high;
+
+ __asm __volatile("rdtsc" : "=a" (low), "=d" (high));
+ return (low | ((uint64_t)high << 32));
+}
+#else /* __amd64__ || __i386__ */
+#error "No rdtsc() implementation available."
+#endif /* __amd64__ || __i386__ */
+#endif /* !clang */
+
static __inline uint64_t
get_cyclecount(void)
{
- /* Shaddup! */
- return (4ULL);
+ return (rdtsc());
}
-// #define PAGE_SIZE 4096
-#define HARVESTSIZE 16
+#define HARVESTSIZE 2
enum random_entropy_source {
RANDOM_START = 0,
@@ -51,7 +70,7 @@
struct harvest_event {
uintmax_t he_somecounter; /* fast counter for clock jitter */
- uint8_t he_entropy[HARVESTSIZE];/* some harvested entropy */
+ uint32_t he_entropy[HARVESTSIZE];/* some harvested entropy */
u_int he_size; /* harvested entropy byte count */
u_int he_bits; /* stats about the entropy */
u_int he_destination; /* destination pool of this entropy */
Index: sys/dev/random/unit_test.c
===================================================================
--- sys/dev/random/unit_test.c
+++ sys/dev/random/unit_test.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@
../../crypto/rijndael/rijndael-api-fst.c \
../../crypto/rijndael/rijndael-alg-fst.c \
../../crypto/sha2/sha2.c \
+ -lz \
-o unit_test
./unit_test
@@ -49,6 +50,7 @@
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
+#include <zlib.h>
#include "unit_test.h"
@@ -59,10 +61,77 @@
#include "dev/random/fortuna.h"
#endif
-#define NUM_THREADS 3
+#define NUM_THREADS 3
+#define DEBUG
static volatile int stopseeding = 0;
+static __inline void
+check_err(int err, const char *func)
+{
+ if (err != Z_OK) {
+ fprintf(stderr, "Compress error in %s: %d\n", func, err);
+ exit(0);
+ }
+}
+
+void *
+myalloc(void *q, unsigned n, unsigned m)
+{
+ q = Z_NULL;
+ return (calloc(n, m));
+}
+
+void myfree(void *q, void *p)
+{
+ q = Z_NULL;
+ free(p);
+}
+
+size_t
+block_deflate(uint8_t *uncompr, uint8_t *compr, const size_t len)
+{
+ z_stream c_stream;
+ int err;
+
+ if (len == 0)
+ return (0);
+
+ c_stream.zalloc = myalloc;
+ c_stream.zfree = myfree;
+ c_stream.opaque = NULL;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ check_err(err, "deflateInit");
+
+ c_stream.next_in = uncompr;
+ c_stream.next_out = compr;
+ c_stream.avail_in = len;
+ c_stream.avail_out = len*2u +512u;
+
+ while (c_stream.total_in != len && c_stream.total_out < (len*2u + 512u)) {
+ err = deflate(&c_stream, Z_NO_FLUSH);
+#ifdef DEBUG
+ printf("deflate: len = %zd total_in = %lu total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
+#endif
+ check_err(err, "deflate(..., Z_NO_FLUSH)");
+ }
+
+ for (;;) {
+ err = deflate(&c_stream, Z_FINISH);
+#ifdef DEBUG
+ printf("deflate: len = %zd total_in = %lu total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
+#endif
+ if (err == Z_STREAM_END) break;
+ check_err(err, "deflate(..., Z_STREAM_END)");
+ }
+
+ err = deflateEnd(&c_stream);
+ check_err(err, "deflateEnd");
+
+ return ((size_t)c_stream.total_out);
+}
+
void
random_adaptor_unblock(void)
{
@@ -128,6 +197,7 @@
if (i % 1000 == 0)
printf("Thread write 1 - %d\n", i);
if (buf != NULL) {
+ printf("Thread 1 writing.\n");
#ifdef RANDOM_YARROW
random_yarrow_write(buf, i);
#endif
@@ -149,9 +219,12 @@
static int
ReadCSPRNG(void *threadid)
{
- size_t tid;
- uint8_t *buf;
+ size_t tid, zsize;
+ uint8_t *buf, *zbuf;
int i;
+#ifdef DEBUG
+ int j;
+#endif
tid = (size_t)threadid;
printf("Thread #%zd starts\n", tid);
@@ -164,42 +237,50 @@
#endif
{
#ifdef RANDOM_YARROW
- random_yarrow_read(NULL, 0);
- random_yarrow_read(NULL, 1);
+ random_yarrow_pre_read();
+ random_yarrow_post_read();
#endif
#ifdef RANDOM_FORTUNA
- random_fortuna_read(NULL, 0);
- random_fortuna_read(NULL, 1);
+ random_fortuna_pre_read();
+ random_fortuna_post_read();
#endif
usleep(100);
}
for (i = 0; i < 100000; i++) {
buf = malloc(i);
+ zbuf = malloc(2*i + 1024);
if (i % 1000 == 0)
- printf("Thread read %zd - %d %p\n", tid, i, buf);
- if (buf != NULL) {
+ printf("Thread read %zd - %d\n", tid, i);
+ if (buf != NULL && zbuf != NULL) {
#ifdef RANDOM_YARROW
- random_yarrow_read(NULL, 0);
+ random_yarrow_pre_read();
random_yarrow_read(buf, i);
- random_yarrow_read(NULL, 1);
+ random_yarrow_post_read();
#endif
#ifdef RANDOM_FORTUNA
- random_fortuna_read(NULL, 0);
+ random_fortuna_pre_read();
random_fortuna_read(buf, i);
- random_fortuna_read(NULL, 1);
+ random_fortuna_post_read();
#endif
-#if 0
- {
- int j;
-
+ zsize = block_deflate(buf, zbuf, i);
+ if (zsize < i)
+ printf("ERROR!! Compressible RNG output!\n");
+#ifdef DEBUG
+ printf("RNG output:\n");
for (j = 0; j < i; j++) {
printf(" %02X", buf[j]);
if (j % 32 == 31 || j == i - 1)
printf("\n");
}
+ printf("Compressed output:\n");
+ for (j = 0; j < zsize; j++) {
+ printf(" %02X", zbuf[j]);
+ if (j % 32 == 31 || j == zsize - 1)
+ printf("\n");
}
#endif
+ free(zbuf);
free(buf);
}
usleep(100);
@@ -228,7 +309,7 @@
for (t = 0; t < NUM_THREADS; t++) {
printf("In main: creating thread %ld\n", t);
- rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), t);
+ rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : (t == 1 ? WriteCSPRNG : ReadCSPRNG)), NULL);
if (rc != thrd_success) {
printf("ERROR; return code from thrd_create() is %d\n", rc);
exit(-1);
Index: sys/dev/random/yarrow.h
===================================================================
--- sys/dev/random/yarrow.h
+++ sys/dev/random/yarrow.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,21 @@
*/
#ifndef SYS_DEV_RANDOM_YARROW_H_INCLUDED
-#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
+#define SYS_DEV_RANDOM_YARROW_H_INCLUDED
#ifdef _KERNEL
typedef struct mtx mtx_t;
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&yarrow_state.ys_mtx, "reseed mutex", NULL, MTX_DEF)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x) mtx_assert(&yarrow_state.ys_mtx, MA_OWNED)
+#else
+#define RANDOM_RESEED_INIT_LOCK(x) mtx_init(&yarrow_state.ys_mtx, mtx_plain)
+#define RANDOM_RESEED_DEINIT_LOCK(x) mtx_destroy(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_LOCK(x) mtx_lock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_UNLOCK(x) mtx_unlock(&yarrow_state.ys_mtx)
+#define RANDOM_RESEED_ASSERT_LOCK_OWNED(x)
#endif
-void random_yarrow_init_alg(void);
-void random_yarrow_deinit_alg(void);
-void random_yarrow_read(uint8_t *, u_int);
-void random_yarrow_write(uint8_t *, u_int);
-void random_yarrow_reseed(void);
-int random_yarrow_seeded(void);
-void random_yarrow_process_event(struct harvest_event *event);
-
-#endif
+#endif /* SYS_DEV_RANDOM_YARROW_H_INCLUDED */
Index: sys/dev/random/yarrow.c
===================================================================
--- sys/dev/random/yarrow.c
+++ sys/dev/random/yarrow.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2000-2013 Mark R V Murray
+ * Copyright (c) 2000-2015 Mark R V Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,12 +29,12 @@
__FBSDID("$FreeBSD$");
#ifdef _KERNEL
-#include "opt_random.h"
-
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/conf.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/random.h>
#include <sys/sysctl.h>
@@ -47,13 +47,10 @@
#include <dev/random/hash.h>
#include <dev/random/randomdev.h>
-#include <dev/random/random_adaptors.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/uint128.h>
#include <dev/random/yarrow.h>
#else /* !_KERNEL */
-#include <sys/param.h>
-#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@@ -66,467 +63,403 @@
#include <crypto/sha2/sha2.h>
#include <dev/random/hash.h>
-#include <dev/random/randomdev.h>
#include <dev/random/uint128.h>
#include <dev/random/yarrow.h>
#endif /* _KERNEL */
-#if !defined(RANDOM_YARROW) && !defined(RANDOM_FORTUNA)
-#define RANDOM_YARROW
-#elif defined(RANDOM_YARROW) && defined(RANDOM_FORTUNA)
-#error "Must define either RANDOM_YARROW or RANDOM_FORTUNA"
-#endif
-
-#if defined(RANDOM_YARROW)
-
-#define TIMEBIN 16 /* max value for Pt/t */
+#define RANDOM_YARROW_TIMEBIN 16 /* max value for Pt/t */
-#define FAST 0
-#define SLOW 1
+#define RANDOM_YARROW_FAST 0
+#define RANDOM_YARROW_SLOW 1
+#define RANDOM_YARROW_NPOOLS 2
-/* This algorithm (and code) presumes that KEYSIZE is twice as large as BLOCKSIZE */
-CTASSERT(BLOCKSIZE == sizeof(uint128_t));
-CTASSERT(KEYSIZE == 2*BLOCKSIZE);
+/* This algorithm (and code) presumes that RANDOM_KEYSIZE is twice as large as RANDOM_BLOCKSIZE */
+CTASSERT(RANDOM_BLOCKSIZE == sizeof(uint128_t));
+CTASSERT(RANDOM_KEYSIZE == 2*RANDOM_BLOCKSIZE);
-/* This is the beastie that needs protecting. It contains all of the
- * state that we are excited about.
- * Exactly one is instantiated.
+/*
+ * This is the beastie that needs protecting. It contains all of the
+ * state that we are excited about. Exactly one is instantiated.
*/
static struct yarrow_state {
- union {
- uint8_t byte[BLOCKSIZE];
- uint128_t whole;
- } counter; /* C */
- struct randomdev_key key; /* K */
- u_int gengateinterval; /* Pg */
- u_int bins; /* Pt/t */
- u_int outputblocks; /* count output blocks for gates */
- u_int slowoverthresh; /* slow pool overthreshhold reseed count */
- struct pool {
- struct source {
- u_int bits; /* estimated bits of entropy */
- } source[ENTROPYSOURCE];/* ... per source */
- u_int thresh; /* pool reseed threshhold */
- struct randomdev_hash hash; /* accumulated entropy */
- } pool[2]; /* pool[0] is fast, pool[1] is slow */
- int seeded;
-
- struct start_cache {
- uint8_t junk[KEYSIZE];
- struct randomdev_hash hash;
- } start_cache;
+ uint128_t ys_counter; /* C */
+ struct randomdev_key ys_key; /* K */
+ u_int ys_gengateinterval; /* Pg */
+ u_int ys_bins; /* Pt/t */
+ u_int ys_outputblocks; /* count output blocks for gates */
+ u_int ys_slowoverthresh; /* slow pool overthreshhold reseed count */
+ struct ys_pool {
+ u_int ysp_source_bits[ENTROPYSOURCE]; /* estimated bits of entropy per source */
+ u_int ysp_thresh; /* pool reseed threshhold */
+ struct randomdev_hash ysp_hash; /* accumulated entropy */
+ } ys_pool[RANDOM_YARROW_NPOOLS];/* pool[0] is fast, pool[1] is slow */
+ int ys_seeded;
+ /* Reseed lock */
+ mtx_t ys_mtx;
} yarrow_state;
-/* The random_reseed_mtx mutex protects seeding and polling/blocking. */
-static mtx_t random_reseed_mtx;
-
#ifdef _KERNEL
static struct sysctl_ctx_list random_clist;
RANDOM_CHECK_UINT(gengateinterval, 4, 64);
-RANDOM_CHECK_UINT(bins, 2, 16);
-RANDOM_CHECK_UINT(fastthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
-RANDOM_CHECK_UINT(slowthresh, (BLOCKSIZE*8)/4, (BLOCKSIZE*8)); /* Bit counts */
+RANDOM_CHECK_UINT(bins, RANDOM_YARROW_NPOOLS, 16);
+RANDOM_CHECK_UINT(fastthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_BLOCKSIZE*8)); /* Bit counts */
+RANDOM_CHECK_UINT(slowthresh, (RANDOM_BLOCKSIZE*8)/4, (RANDOM_BLOCKSIZE*8)); /* Bit counts */
RANDOM_CHECK_UINT(slowoverthresh, 1, 5);
-#else /* !_KERNEL */
-static u_int harvest_destination[ENTROPYSOURCE];
#endif /* _KERNEL */
-static void generator_gate(void);
-static void reseed(u_int);
+static void random_yarrow_pre_read(void);
+static void random_yarrow_read(uint8_t *, u_int);
+static void random_yarrow_post_read(void);
+static void random_yarrow_write(uint8_t *, u_int);
+static void random_yarrow_reseed(void);
+static int random_yarrow_seeded(void);
+static void random_yarrow_reseed_internal(u_int);
+static void random_yarrow_process_event(struct harvest_event *);
-void
-random_yarrow_init_alg(void)
+#ifdef _KERNEL
+/* Interface to Adaptors system */
+struct random_algorithm random_alg_context = {
+ .ra_ident = "Yarrow",
+ .ra_pre_read = random_yarrow_pre_read,
+ .ra_read = random_yarrow_read,
+ .ra_post_read = random_yarrow_post_read,
+ .ra_write = random_yarrow_write,
+ .ra_reseed = random_yarrow_reseed,
+ .ra_seeded = random_yarrow_seeded,
+ .ra_event_processor = random_yarrow_process_event,
+ .ra_poolcount = RANDOM_YARROW_NPOOLS,
+};
+#endif
+
+/* ARGSUSED */
+static void
+random_yarrow_init_alg(void *unused __unused)
{
int i, j;
#ifdef _KERNEL
struct sysctl_oid *random_yarrow_o;
-#endif /* _KERNEL */
-
- memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
- randomdev_hash_init(&yarrow_state.start_cache.hash);
-
- /* Set up the lock for the reseed/gate state */
-#ifdef _KERNEL
- mtx_init(&random_reseed_mtx, "reseed mutex", NULL, MTX_DEF);
-#else /* !_KERNEL */
- mtx_init(&random_reseed_mtx, mtx_plain);
-#endif /* _KERNEL */
+#endif
+ RANDOM_RESEED_INIT_LOCK();
/* Start unseeded, therefore blocked. */
- yarrow_state.seeded = 0;
-
+ yarrow_state.ys_seeded = 0;
#ifdef _KERNEL
- /* Yarrow parameters. Do not adjust these unless you have
+ /*
+ * Yarrow parameters. Do not adjust these unless you have
* have a very good clue about what they do!
*/
random_yarrow_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "yarrow", CTLFLAG_RW, 0,
"Yarrow Parameters");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "gengateinterval", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.gengateinterval, 10,
- random_check_uint_gengateinterval, "I",
+ "gengateinterval", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_gengateinterval, 0,
+ random_check_uint_gengateinterval, "UI",
"Generation gate interval");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "bins", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.bins, 10,
- random_check_uint_bins, "I",
+ "bins", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_bins, 0,
+ random_check_uint_bins, "UI",
"Execution time tuner");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "fastthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.pool[0].thresh, (3*(BLOCKSIZE*8))/4,
- random_check_uint_fastthresh, "I",
+ "fastthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_pool[0].ysp_thresh, 0,
+ random_check_uint_fastthresh, "UI",
"Fast reseed threshold");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "slowthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.pool[1].thresh, (BLOCKSIZE*8),
- random_check_uint_slowthresh, "I",
+ "slowthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_pool[1].ysp_thresh, 0,
+ random_check_uint_slowthresh, "UI",
"Slow reseed threshold");
-
SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_yarrow_o), OID_AUTO,
- "slowoverthresh", CTLTYPE_INT|CTLFLAG_RW,
- &yarrow_state.slowoverthresh, 2,
- random_check_uint_slowoverthresh, "I",
+ "slowoverthresh", CTLTYPE_UINT | CTLFLAG_RWTUN,
+ &yarrow_state.ys_slowoverthresh, 0,
+ random_check_uint_slowoverthresh, "UI",
"Slow over-threshold reseed");
#endif /* _KERNEL */
-
- yarrow_state.gengateinterval = 10;
- yarrow_state.bins = 10;
- yarrow_state.pool[FAST].thresh = (3*(BLOCKSIZE*8))/4;
- yarrow_state.pool[SLOW].thresh = (BLOCKSIZE*8);
- yarrow_state.slowoverthresh = 2;
-
+ yarrow_state.ys_gengateinterval = 10;
+ yarrow_state.ys_bins = 10;
+ yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh = (3*(RANDOM_BLOCKSIZE*8))/4;
+ yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh = (RANDOM_BLOCKSIZE*8);
+ yarrow_state.ys_slowoverthresh = 2;
/* Ensure that the first time we read, we are gated. */
- yarrow_state.outputblocks = yarrow_state.gengateinterval;
-
+ yarrow_state.ys_outputblocks = yarrow_state.ys_gengateinterval;
/* Initialise the fast and slow entropy pools */
- for (i = FAST; i <= SLOW; i++) {
- randomdev_hash_init(&yarrow_state.pool[i].hash);
+ for (i = RANDOM_YARROW_FAST; i <= RANDOM_YARROW_SLOW; i++) {
+ randomdev_hash_init(&yarrow_state.ys_pool[i].ysp_hash);
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- yarrow_state.pool[i].source[j].bits = 0U;
+ yarrow_state.ys_pool[i].ysp_source_bits[j] = 0;
}
-
/* Clear the counter */
- uint128_clear(&yarrow_state.counter.whole);
+ yarrow_state.ys_counter = UINT128_ZERO;
}
+#ifdef _KERNEL
+SYSINIT(random_yarrow, SI_SUB_RANDOM, SI_ORDER_THIRD, random_yarrow_init_alg, NULL);
+#endif
-void
-random_yarrow_deinit_alg(void)
+/* ARGSUSED */
+static void
+random_yarrow_deinit_alg(void *unused __unused)
{
- mtx_destroy(&random_reseed_mtx);
- memset(&yarrow_state, 0, sizeof(yarrow_state));
-
+ RANDOM_RESEED_DEINIT_LOCK();
+ explicit_bzero(&yarrow_state, sizeof(yarrow_state));
#ifdef _KERNEL
sysctl_ctx_free(&random_clist);
#endif
}
+#ifdef _KERNEL
+SYSUNINIT(random_yarrow, SI_SUB_RANDOM, SI_ORDER_THIRD, random_yarrow_deinit_alg, NULL);
+#endif
-static __inline void
-random_yarrow_post_insert(void)
+/* Process a single stochastic event off the harvest queue */
+static void
+random_yarrow_process_event(struct harvest_event *event)
{
- u_int pl, overthreshhold[2];
+ u_int pl, overthreshhold[RANDOM_YARROW_NPOOLS];
enum random_entropy_source src;
-#ifdef _KERNEL
- mtx_assert(&random_reseed_mtx, MA_OWNED);
-#endif
+ RANDOM_RESEED_LOCK();
+ /*
+ * Accumulate the event into the appropriate pool
+ * where each event carries the destination information.
+ * We lock against pool state modification which can happen
+ * during accumulation/reseeding and reading/regating
+ */
+ pl = event->he_destination % RANDOM_YARROW_NPOOLS;
+ randomdev_hash_iterate(&yarrow_state.ys_pool[pl].ysp_hash, event, sizeof(*event));
+ yarrow_state.ys_pool[pl].ysp_source_bits[event->he_source] += event->he_bits;
/* Count the over-threshold sources in each pool */
- for (pl = 0; pl < 2; pl++) {
+ for (pl = RANDOM_YARROW_FAST; pl <= RANDOM_YARROW_SLOW; pl++) {
overthreshhold[pl] = 0;
for (src = RANDOM_START; src < ENTROPYSOURCE; src++) {
- if (yarrow_state.pool[pl].source[src].bits > yarrow_state.pool[pl].thresh)
+ if (yarrow_state.ys_pool[pl].ysp_source_bits[src] > yarrow_state.ys_pool[pl].ysp_thresh)
overthreshhold[pl]++;
}
}
-
- /* If enough slow sources are over threshhold, then slow reseed
+ /*
+ * If enough slow sources are over threshhold, then slow reseed
* else if any fast source over threshhold, then fast reseed.
*/
- if (overthreshhold[SLOW] >= yarrow_state.slowoverthresh)
- reseed(SLOW);
- else if (overthreshhold[FAST] > 0 && yarrow_state.seeded)
- reseed(FAST);
-}
-
-/* Process a single stochastic event off the harvest queue */
-void
-random_yarrow_process_event(struct harvest_event *event)
-{
- u_int pl;
-
- mtx_lock(&random_reseed_mtx);
-
- /* Accumulate the event into the appropriate pool
- * where each event carries the destination information.
- * We lock against pool state modification which can happen
- * during accumulation/reseeding and reading/regating
- */
- pl = event->he_destination % 2;
- randomdev_hash_iterate(&yarrow_state.pool[pl].hash, event, sizeof(*event));
- yarrow_state.pool[pl].source[event->he_source].bits += event->he_bits;
-
- random_yarrow_post_insert();
-
- mtx_unlock(&random_reseed_mtx);
+ if (overthreshhold[RANDOM_YARROW_SLOW] >= yarrow_state.ys_slowoverthresh)
+ random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
+ else if (overthreshhold[RANDOM_YARROW_FAST] > 0 && yarrow_state.ys_seeded)
+ random_yarrow_reseed_internal(RANDOM_YARROW_FAST);
+ explicit_bzero(event, sizeof(*event));
+ RANDOM_RESEED_UNLOCK();
}
-/* Process a block of data suspected to be slightly stochastic */
+/* Process a block of data suspected to be slightly stochastic. */
static void
-random_yarrow_process_buffer(uint8_t *buf, u_int length)
+random_yarrow_process_buffer(uint32_t *buf, u_int wordcount)
{
static struct harvest_event event;
- u_int i, pl;
+ static u_int destination = 0;
+ int i;
- /* Accumulate the data into the appropriate pools
- * where each event carries the destination information.
- * We lock against pool state modification which can happen
- * during accumulation/reseeding and reading/regating
- */
- memset(event.he_entropy + sizeof(uint32_t), 0, HARVESTSIZE - sizeof(uint32_t));
- for (i = 0; i < length/sizeof(uint32_t); i++) {
- event.he_somecounter = get_cyclecount();
- event.he_bits = 0; /* Fake */
+ for (i = 0; i < wordcount; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
+ event.he_somecounter = (uint32_t)get_cyclecount();
+ event.he_size = sizeof(event.he_entropy);
+ event.he_bits = event.he_size/8;
event.he_source = RANDOM_CACHED;
- event.he_destination = harvest_destination[RANDOM_CACHED]++;
- event.he_size = sizeof(uint32_t);
- *((uint32_t *)event.he_entropy) = *((uint32_t *)buf + i);
-
- /* Do the actual entropy insertion */
- pl = event.he_destination % 2;
- randomdev_hash_iterate(&yarrow_state.pool[pl].hash, &event, sizeof(event));
-#ifdef DONT_DO_THIS_HERE
- /* Don't do this here - do it in bulk at the end */
- yarrow_state.pool[pl].source[RANDOM_CACHED].bits += bits;
-#endif
+ event.he_destination = destination++; /* Harmless cheating */
+ memcpy(event.he_entropy, buf + i, sizeof(event.he_entropy));
+ random_yarrow_process_event(&event);
}
- for (pl = FAST; pl <= SLOW; pl++)
- yarrow_state.pool[pl].source[RANDOM_CACHED].bits += (length >> 4);
-
- random_yarrow_post_insert();
}
static void
-reseed(u_int fastslow)
+random_yarrow_reseed_internal(u_int fastslow)
{
- /* Interrupt-context stack is a limited resource; make large
+ /*
+ * Interrupt-context stack is a limited resource; make large
* structures static.
*/
- static uint8_t v[TIMEBIN][KEYSIZE]; /* v[i] */
- static uint8_t hash[KEYSIZE]; /* h' */
- static uint8_t temp[KEYSIZE];
+ static uint8_t v[RANDOM_YARROW_TIMEBIN][RANDOM_KEYSIZE]; /* v[i] */
+ static uint128_t temp;
static struct randomdev_hash context;
u_int i;
enum random_entropy_source j;
- KASSERT(yarrow_state.pool[FAST].thresh > 0, ("random: Yarrow fast threshold = 0"));
- KASSERT(yarrow_state.pool[SLOW].thresh > 0, ("random: Yarrow slow threshold = 0"));
-
+ KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh > 0, ("random: Yarrow fast threshold = 0"));
+ KASSERT(yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh > 0, ("random: Yarrow slow threshold = 0"));
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
#ifdef RANDOM_DEBUG
-#ifdef RANDOM_DEBUG_VERBOSE
- printf("random: %s %s\n", __func__, (fastslow == FAST ? "FAST" : "SLOW"));
-#endif
- if (!yarrow_state.seeded) {
- printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.pool[FAST].thresh);
- for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
- printf(" %d", yarrow_state.pool[FAST].source[i].bits);
- printf("\n");
- printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.pool[SLOW].thresh, yarrow_state.slowoverthresh);
- for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
- printf(" %d", yarrow_state.pool[SLOW].source[i].bits);
- printf("\n");
- }
+ /* WARNING! This is dangerously tedious to do with mutexes held! */
+ printf("random: %s %s seeded = %d\n", __func__, (fastslow == RANDOM_YARROW_FAST ? "RANDOM_YARROW_FAST" : "RANDOM_YARROW_SLOW"), yarrow_state.ys_seeded);
+ printf("random: %s - fast - thresh %d,1 - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_thresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_source_bits[i]);
+ printf("\n");
+ printf("random: %s - slow - thresh %d,%d - ", __func__, yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_thresh, yarrow_state.ys_slowoverthresh);
+ for (i = RANDOM_START; i < ENTROPYSOURCE; i++)
+ printf(" %d", yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_source_bits[i]);
+ printf("\n");
#endif
-#ifdef _KERNEL
- mtx_assert(&random_reseed_mtx, MA_OWNED);
-#endif
-
/* 1. Hash the accumulated entropy into v[0] */
-
randomdev_hash_init(&context);
/* Feed the slow pool hash in if slow */
- if (fastslow == SLOW) {
- randomdev_hash_finish(&yarrow_state.pool[SLOW].hash, temp);
- randomdev_hash_iterate(&context, temp, sizeof(temp));
+ if (fastslow == RANDOM_YARROW_SLOW) {
+ randomdev_hash_finish(&yarrow_state.ys_pool[RANDOM_YARROW_SLOW].ysp_hash, &temp);
+ randomdev_hash_iterate(&context, &temp, sizeof(temp));
}
- randomdev_hash_finish(&yarrow_state.pool[FAST].hash, temp);
- randomdev_hash_iterate(&context, temp, sizeof(temp));
+ randomdev_hash_finish(&yarrow_state.ys_pool[RANDOM_YARROW_FAST].ysp_hash, &temp);
+ randomdev_hash_iterate(&context, &temp, sizeof(temp));
randomdev_hash_finish(&context, v[0]);
-
- /* 2. Compute hash values for all v. _Supposed_ to be computationally
+ /*-
+ * 2. Compute hash values for all v. _Supposed_ to be computationally
* intensive.
*/
-
- if (yarrow_state.bins > TIMEBIN)
- yarrow_state.bins = TIMEBIN;
- for (i = 1; i < yarrow_state.bins; i++) {
+ if (yarrow_state.ys_bins > RANDOM_YARROW_TIMEBIN)
+ yarrow_state.ys_bins = RANDOM_YARROW_TIMEBIN;
+ for (i = 1; i < yarrow_state.ys_bins; i++) {
randomdev_hash_init(&context);
/* v[i] #= h(v[i - 1]) */
- randomdev_hash_iterate(&context, v[i - 1], KEYSIZE);
+ randomdev_hash_iterate(&context, v[i - 1], RANDOM_KEYSIZE);
/* v[i] #= h(v[0]) */
- randomdev_hash_iterate(&context, v[0], KEYSIZE);
+ randomdev_hash_iterate(&context, v[0], RANDOM_KEYSIZE);
/* v[i] #= h(i) */
randomdev_hash_iterate(&context, &i, sizeof(i));
/* Return the hashval */
randomdev_hash_finish(&context, v[i]);
}
-
- /* 3. Compute a new key; h' is the identity function here;
+ /*-
+ * 3. Compute a new key; h' is the identity function here;
* it is not being ignored!
*/
-
randomdev_hash_init(&context);
- randomdev_hash_iterate(&context, &yarrow_state.key, KEYSIZE);
- for (i = 1; i < yarrow_state.bins; i++)
- randomdev_hash_iterate(&context, v[i], KEYSIZE);
- randomdev_hash_finish(&context, temp);
- randomdev_encrypt_init(&yarrow_state.key, temp);
-
+ randomdev_hash_iterate(&context, &yarrow_state.ys_key, RANDOM_KEYSIZE);
+ for (i = 1; i < yarrow_state.ys_bins; i++)
+ randomdev_hash_iterate(&context, v[i], RANDOM_KEYSIZE);
+ randomdev_hash_finish(&context, &temp);
+ randomdev_encrypt_init(&yarrow_state.ys_key, &temp);
/* 4. Recompute the counter */
-
- uint128_clear(&yarrow_state.counter.whole);
- randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp, BLOCKSIZE);
- memcpy(yarrow_state.counter.byte, temp, BLOCKSIZE);
-
+ yarrow_state.ys_counter = UINT128_ZERO;
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, &temp, RANDOM_BLOCKSIZE);
+ yarrow_state.ys_counter = temp;
/* 5. Reset entropy estimate accumulators to zero */
-
for (i = 0; i <= fastslow; i++)
for (j = RANDOM_START; j < ENTROPYSOURCE; j++)
- yarrow_state.pool[i].source[j].bits = 0;
-
+ yarrow_state.ys_pool[i].ysp_source_bits[j] = 0;
/* 6. Wipe memory of intermediate values */
-
- memset(v, 0, sizeof(v));
- memset(temp, 0, sizeof(temp));
- memset(hash, 0, sizeof(hash));
- memset(&context, 0, sizeof(context));
-
-#ifdef RANDOM_RWFILE_WRITE_IS_OK /* Not defined so writes ain't gonna happen */
- /* 7. Dump to seed file */
-
- /* This pseudo-code is documentation. Please leave it alone. */
+ explicit_bzero(v, sizeof(v));
+ explicit_bzero(&temp, sizeof(temp));
+ explicit_bzero(&context, sizeof(context));
+/* Not defined so writes ain't gonna happen. Kept for documenting. */
+#ifdef RANDOM_RWFILE_WRITE_IS_OK
+ /*-
+ * 7. Dump to seed file.
+ * This pseudo-code is documentation. Please leave it alone.
+ */
seed_file = "<some file>";
error = randomdev_write_file(seed_file, <generated entropy>, PAGE_SIZE);
if (error == 0)
printf("random: entropy seed file '%s' successfully written\n", seed_file);
#endif
-
/* Unblock the device if it was blocked due to being unseeded */
- if (!yarrow_state.seeded) {
- yarrow_state.seeded = 1;
- random_adaptor_unblock();
+ if (!yarrow_state.ys_seeded) {
+ yarrow_state.ys_seeded = 1;
+ randomdev_unblock();
}
}
-/* Internal function to return processed entropy from the PRNG */
+static __inline void
+random_yarrow_generator_gate(void)
+{
+ u_int i;
+ uint8_t temp[RANDOM_KEYSIZE];
+
+ RANDOM_RESEED_ASSERT_LOCK_OWNED();
+ uint128_increment(&yarrow_state.ys_counter);
+ for (i = 0; i < RANDOM_KEYSIZE; i += RANDOM_BLOCKSIZE)
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, temp + i, RANDOM_BLOCKSIZE);
+ randomdev_encrypt_init(&yarrow_state.ys_key, temp);
+ explicit_bzero(temp, sizeof(temp));
+}
+
+/*-
+ * Used to return processed entropy from the PRNG.
+ * There is a pre_read and a post_read required to be present
+ * (but they can be null functions) in order to allow specific
+ * actions at the begin or the end of a read. Yarrow does its
+ * reseeding in its own thread. The _pre_read() and _post_read()
+ * are not used here, and must be kept for completeness.
+ */
+void
+random_yarrow_pre_read(void)
+{
+}
+
+/*-
+ * Main read from Yarrow.
+ * The supplied buf MUST be a multiple (>=0) of RANDOM_BLOCKSIZE in size.
+ * Lots of code presumes this for efficiency, both here and in other
+ * routines. You are NOT allowed to break this!
+ */
void
random_yarrow_read(uint8_t *buf, u_int bytecount)
{
- uint8_t tbuf[BLOCKSIZE];
u_int blockcount, i;
- /* Check for initial/final read requests */
- if (buf == NULL)
- return;
-
- /* The reseed task must not be jumped on */
- mtx_lock(&random_reseed_mtx);
-
- blockcount = (bytecount + BLOCKSIZE - 1)/BLOCKSIZE;
+ RANDOM_RESEED_LOCK();
+ blockcount = (bytecount + RANDOM_BLOCKSIZE - 1)/RANDOM_BLOCKSIZE;
for (i = 0; i < blockcount; i++) {
- if (yarrow_state.outputblocks++ >= yarrow_state.gengateinterval) {
- generator_gate();
- yarrow_state.outputblocks = 0;
- }
- uint128_increment(&yarrow_state.counter.whole);
- if ((i + 1) * BLOCKSIZE > bytecount) {
- /* TODO: FIX! remove memcpy()! */
- randomdev_encrypt(&yarrow_state.key,
- yarrow_state.counter.byte, tbuf, BLOCKSIZE);
- memcpy(buf, tbuf, bytecount - i * BLOCKSIZE);
- } else {
- randomdev_encrypt(&yarrow_state.key,
- yarrow_state.counter.byte, buf, BLOCKSIZE);
- buf += BLOCKSIZE;
+ if (yarrow_state.ys_outputblocks++ >= yarrow_state.ys_gengateinterval) {
+ random_yarrow_generator_gate();
+ yarrow_state.ys_outputblocks = 0;
}
+ uint128_increment(&yarrow_state.ys_counter);
+ randomdev_encrypt(&yarrow_state.ys_key, &yarrow_state.ys_counter, buf, RANDOM_BLOCKSIZE);
+ buf += RANDOM_BLOCKSIZE;
}
-
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_UNLOCK();
}
-/* Internal function to hand external entropy to the PRNG */
void
-random_yarrow_write(uint8_t *buf, u_int count)
+random_yarrow_post_read(void)
{
- uintmax_t timestamp;
-
- /* We must be locked for all this as plenty of state gets messed with */
- mtx_lock(&random_reseed_mtx);
-
- timestamp = get_cyclecount();
- randomdev_hash_iterate(&yarrow_state.start_cache.hash, ×tamp, sizeof(timestamp));
- randomdev_hash_iterate(&yarrow_state.start_cache.hash, buf, count);
- timestamp = get_cyclecount();
- randomdev_hash_iterate(&yarrow_state.start_cache.hash, ×tamp, sizeof(timestamp));
- randomdev_hash_finish(&yarrow_state.start_cache.hash, yarrow_state.start_cache.junk);
- randomdev_hash_init(&yarrow_state.start_cache.hash);
-
-#ifdef RANDOM_DEBUG_VERBOSE
- {
- int i;
-
- printf("random: %s - ", __func__);
- for (i = 0; i < KEYSIZE; i++)
- printf("%02X", yarrow_state.start_cache.junk[i]);
- printf("\n");
- }
-#endif
-
- random_yarrow_process_buffer(yarrow_state.start_cache.junk, KEYSIZE);
- memset(yarrow_state.start_cache.junk, 0, KEYSIZE);
- mtx_unlock(&random_reseed_mtx);
+ /* CWOT */
}
-static void
-generator_gate(void)
+/* Internal function to hand external entropy to the PRNG. */
+void
+random_yarrow_write(uint8_t *buf, u_int count)
{
- u_int i;
- uint8_t temp[KEYSIZE];
-
- for (i = 0; i < KEYSIZE; i += BLOCKSIZE) {
- uint128_increment(&yarrow_state.counter.whole);
- randomdev_encrypt(&yarrow_state.key, yarrow_state.counter.byte, temp + i, BLOCKSIZE);
- }
-
- randomdev_encrypt_init(&yarrow_state.key, temp);
- memset(temp, 0, KEYSIZE);
+ struct randomdev_hash hash;
+ uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], timestamp;
+
+ /* Extra timing here is helpful to scrape scheduler timing entropy */
+ randomdev_hash_init(&hash);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp));
+ randomdev_hash_iterate(&hash, buf, count);
+ timestamp = (uint32_t)get_cyclecount();
+ randomdev_hash_iterate(&hash, ×tamp, sizeof(timestamp));
+ randomdev_hash_finish(&hash, entropy_data);
+ explicit_bzero(&hash, sizeof(hash));
+ random_yarrow_process_buffer(entropy_data, sizeof(entropy_data)/sizeof(entropy_data[0]));
+ explicit_bzero(entropy_data, sizeof(entropy_data));
}
void
random_yarrow_reseed(void)
{
- mtx_lock(&random_reseed_mtx);
- reseed(SLOW);
- mtx_unlock(&random_reseed_mtx);
+ RANDOM_RESEED_LOCK();
+ random_yarrow_reseed_internal(RANDOM_YARROW_SLOW);
+ RANDOM_RESEED_UNLOCK();
}
int
random_yarrow_seeded(void)
{
- return (yarrow_state.seeded);
+ return (yarrow_state.ys_seeded);
}
-
-#endif /* RANDOM_YARROW */
Index: sys/dev/rndtest/rndtest.c
===================================================================
--- sys/dev/rndtest/rndtest.c
+++ sys/dev/rndtest/rndtest.c
@@ -145,16 +145,9 @@
*/
if (rsp->rs_discard)
rndstats.rst_discard += len;
- else {
-#if __FreeBSD_version < 500000
- /* XXX verify buffer is word aligned */
- u_int32_t *p = buf;
- for (len /= sizeof (u_int32_t); len; len--)
- add_true_randomness(*p++);
-#else
- random_harvest(buf, len, len*NBBY/2, RANDOM_PURE_RNDTEST);
-#endif
- }
+ else
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, len, len*NBBY/2, RANDOM_PURE_RNDTEST);
}
static void
Index: sys/dev/safe/safe.c
===================================================================
--- sys/dev/safe/safe.c
+++ sys/dev/safe/safe.c
@@ -211,7 +211,8 @@
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_SAFE);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_SAFE);
}
#endif /* SAFE_NO_RNG */
Index: sys/dev/syscons/scmouse.c
===================================================================
--- sys/dev/syscons/scmouse.c
+++ sys/dev/syscons/scmouse.c
@@ -666,7 +666,7 @@
mouse = (mouse_info_t*)data;
- random_harvest(mouse, sizeof(mouse_info_t), 2, RANDOM_MOUSE);
+ random_harvest_queue(mouse, sizeof(mouse_info_t), 2, RANDOM_MOUSE);
if (cmd == OLD_CONS_MOUSECTL) {
static u_char swapb[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
Index: sys/dev/syscons/syscons.c
===================================================================
--- sys/dev/syscons/syscons.c
+++ sys/dev/syscons/syscons.c
@@ -3411,7 +3411,7 @@
sc_touch_scrn_saver();
if (!(flags & SCGETC_CN))
- random_harvest(&c, sizeof(c), 1, RANDOM_KEYBOARD);
+ random_harvest_queue(&c, sizeof(c), 1, RANDOM_KEYBOARD);
if (scp->kbd_mode != K_XLATE)
return KEYCHAR(c);
Index: sys/dev/ubsec/ubsec.c
===================================================================
--- sys/dev/ubsec/ubsec.c
+++ sys/dev/ubsec/ubsec.c
@@ -259,7 +259,8 @@
static void
default_harvest(struct rndtest_state *rsp, void *buf, u_int count)
{
- random_harvest(buf, count, count*NBBY/2, RANDOM_PURE_UBSEC);
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(buf, count, count*NBBY/2, RANDOM_PURE_UBSEC);
}
static int
Index: sys/dev/virtio/random/virtio_random.c
===================================================================
--- sys/dev/virtio/random/virtio_random.c
+++ sys/dev/virtio/random/virtio_random.c
@@ -215,7 +215,7 @@
virtqueue_notify(vq);
virtqueue_poll(vq, NULL);
- random_harvest(&value, sizeof(value), sizeof(value) * NBBY / 2,
+ random_harvest_queue(&value, sizeof(value), sizeof(value) * NBBY / 2,
RANDOM_PURE_VIRTIO);
}
Index: sys/dev/vt/vt_core.c
===================================================================
--- sys/dev/vt/vt_core.c
+++ sys/dev/vt/vt_core.c
@@ -48,6 +48,7 @@
#include <sys/power.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/random.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/terminal.h>
@@ -732,6 +733,7 @@
{
struct vt_window *vw = vd->vd_curwindow;
+ random_harvest_queue(&c, sizeof(c), 1, RANDOM_KEYBOARD);
#if VT_ALT_TO_ESC_HACK
if (c & RELKEY) {
switch (c & ~RELKEY) {
Index: sys/dev/vt/vt_sysmouse.c
===================================================================
--- sys/dev/vt/vt_sysmouse.c
+++ sys/dev/vt/vt_sysmouse.c
@@ -139,7 +139,7 @@
unsigned char buf[MOUSE_SYS_PACKETSIZE];
int x, y, iy, z;
- random_harvest(mi, sizeof *mi, 2, RANDOM_MOUSE);
+ random_harvest_queue(mi, sizeof *mi, 2, RANDOM_MOUSE);
mtx_lock(&sysmouse_lock);
switch (mi->operation) {
Index: sys/fs/tmpfs/tmpfs_subr.c
===================================================================
--- sys/fs/tmpfs/tmpfs_subr.c
+++ sys/fs/tmpfs/tmpfs_subr.c
@@ -42,6 +42,7 @@
#include <sys/namei.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/random.h>
#include <sys/rwlock.h>
#include <sys/stat.h>
#include <sys/systm.h>
@@ -1758,6 +1759,8 @@
}
node->tn_status &=
~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
+ /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
+ random_harvest_queue(node, sizeof(*node), 1, RANDOM_FS_ATIME);
}
void
Index: sys/kern/kern_intr.c
===================================================================
--- sys/kern/kern_intr.c
+++ sys/kern/kern_intr.c
@@ -888,7 +888,7 @@
if (ie->ie_flags & IE_ENTROPY) {
entropy.event = (uintptr_t)ie;
entropy.td = ctd;
- random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
+ random_harvest_queue(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
}
KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
@@ -1039,7 +1039,7 @@
if (ie->ie_flags & IE_ENTROPY) {
entropy.event = (uintptr_t)ie;
entropy.td = ctd;
- random_harvest(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
+ random_harvest_queue(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
}
KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
@@ -1126,7 +1126,7 @@
entropy.event = (uintptr_t)ih;
entropy.td = curthread;
- random_harvest(&entropy, sizeof(entropy), 1, RANDOM_SWI);
+ random_harvest_queue(&entropy, sizeof(entropy), 1, RANDOM_SWI);
/*
* Set ih_need for this handler so that if the ithread is already
Index: sys/kern/kern_mib.c
===================================================================
--- sys/kern/kern_mib.c
+++ sys/kern/kern_mib.c
@@ -43,16 +43,17 @@
#include "opt_config.h"
#include <sys/param.h>
+#include <sys/jail.h>
#include <sys/kernel.h>
-#include <sys/sbuf.h>
-#include <sys/systm.h>
-#include <sys/sysctl.h>
-#include <sys/proc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
-#include <sys/jail.h>
+#include <sys/proc.h>
+#include <sys/random.h>
+#include <sys/sbuf.h>
#include <sys/smp.h>
#include <sys/sx.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <sys/unistd.h>
SYSCTL_ROOT_NODE(0, sysctl, CTLFLAG_RW, 0,
@@ -152,10 +153,15 @@
char buf[256];
size_t len;
- len = req->oldlen;
- if (len > sizeof(buf))
- len = sizeof(buf);
- arc4rand(buf, len, 0);
+ /*-
+ * This is one of the very few legitimate uses of read_random(9).
+ * Use of arc4random(9) is not recommended as that will ignore
+ * an unsafe (i.e. unseeded) random(4).
+ *
+ * If random(4) is not seeded, then this returns 0, so the
+ * sysctl will return a zero-length buffer.
+ */
+ len = read_random(buf, MIN(req->oldlen, sizeof(buf)));
return (SYSCTL_OUT(req, buf, len));
}
Index: sys/kern/subr_bus.c
===================================================================
--- sys/kern/subr_bus.c
+++ sys/kern/subr_bus.c
@@ -28,7 +28,6 @@
__FBSDID("$FreeBSD$");
#include "opt_bus.h"
-#include "opt_random.h"
#include <sys/param.h>
#include <sys/conf.h>
@@ -2877,14 +2876,16 @@
attachtime = get_cyclecount() - attachtime;
/*
* 4 bits per device is a reasonable value for desktop and server
- * hardware with good get_cyclecount() implementations, but may
+ * hardware with good get_cyclecount() implementations, but WILL
* need to be adjusted on other platforms.
*/
-#ifdef RANDOM_DEBUG
- printf("random: %s(): feeding %d bit(s) of entropy from %s%d\n",
- __func__, 4, dev->driver->name, dev->unit);
-#endif
- random_harvest(&attachtime, sizeof(attachtime), 4, RANDOM_ATTACH);
+#define RANDOM_PROBE_BIT_GUESS 4
+ if (bootverbose)
+ printf("random: harvesting attach, %zu bytes (%d bits) from %s%d\n",
+ sizeof(attachtime), RANDOM_PROBE_BIT_GUESS,
+ dev->driver->name, dev->unit);
+ random_harvest_direct(&attachtime, sizeof(attachtime),
+ RANDOM_PROBE_BIT_GUESS, RANDOM_ATTACH);
device_sysctl_update(dev);
if (dev->busy)
dev->state = DS_BUSY;
Index: sys/libkern/arc4random.c
===================================================================
--- sys/libkern/arc4random.c
+++ sys/libkern/arc4random.c
@@ -22,7 +22,7 @@
#define ARC4_RESEED_BYTES 65536
#define ARC4_RESEED_SECONDS 300
-#define ARC4_KEYBYTES (256 / 8)
+#define ARC4_KEYBYTES 256
int arc4rand_iniseed_state = ARC4_ENTR_NONE;
@@ -48,39 +48,33 @@
* Stir our S-box.
*/
static void
-arc4_randomstir (void)
+arc4_randomstir(void)
{
- u_int8_t key[256];
- int r, n;
+ u_int8_t key[ARC4_KEYBYTES];
+ int n;
struct timeval tv_now;
/*
- * XXX read_random() returns unsafe numbers if the entropy
- * device is not loaded -- MarkM.
+ * XXX: FIX!! This isn't brilliant. Need more confidence.
+ * This returns zero entropy before random(4) is seeded.
*/
- r = read_random(key, ARC4_KEYBYTES);
+ (void)read_random(key, ARC4_KEYBYTES);
getmicrouptime(&tv_now);
mtx_lock(&arc4_mtx);
- /* If r == 0 || -1, just use what was on the stack. */
- if (r > 0) {
- for (n = r; n < sizeof(key); n++)
- key[n] = key[n % r];
- }
-
for (n = 0; n < 256; n++) {
arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256;
arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]);
}
arc4_i = arc4_j = 0;
-
/* Reset for next reseed cycle. */
arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS;
arc4_numruns = 0;
-
/*
* Throw away the first N words of output, as suggested in the
* paper "Weaknesses in the Key Scheduling Algorithm of RC4"
* by Fluher, Mantin, and Shamir. (N = 256 in our case.)
+ *
+ * http://dl.acm.org/citation.cfm?id=646557.694759
*/
for (n = 0; n < 256*4; n++)
arc4_randbyte();
Index: sys/libkern/random.c
===================================================================
--- sys/libkern/random.c
+++ sys/libkern/random.c
@@ -50,7 +50,7 @@
}
/*
- * Pseudo-random number generator for randomizing the profiling clock,
+ * Pseudo-random number generator for perturbing the profiling clock,
* and whatever else we might use it for. The result is uniform on
* [0, 2^31 - 1].
*/
Index: sys/mips/cavium/octeon_rnd.c
===================================================================
--- sys/mips/cavium/octeon_rnd.c
+++ sys/mips/cavium/octeon_rnd.c
@@ -125,7 +125,8 @@
for (i = 0; i < OCTEON_RND_WORDS; i++)
sc->sc_entropy[i] = cvmx_rng_get_random64();
- random_harvest(sc->sc_entropy, sizeof sc->sc_entropy,
+ /* MarkM: FIX!! Check that this does not swamp the harvester! */
+ random_harvest_queue(sc->sc_entropy, sizeof sc->sc_entropy,
(sizeof(sc->sc_entropy)*8)/2, RANDOM_PURE_OCTEON);
callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc);
Index: sys/mips/conf/AR71XX_BASE
===================================================================
--- sys/mips/conf/AR71XX_BASE
+++ sys/mips/conf/AR71XX_BASE
@@ -24,7 +24,7 @@
# Build these as modules so small platform builds will have the
# modules already built.
-makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_pci"
+makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_pci"
# For small memory footprints
options VM_KMEM_SIZE_SCALE=1
Index: sys/mips/conf/AR724X_BASE
===================================================================
--- sys/mips/conf/AR724X_BASE
+++ sys/mips/conf/AR724X_BASE
@@ -25,7 +25,7 @@
# Build these as modules so small platform builds will have the
# modules already built.
-makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_pci hwpmc cam"
+makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_pci hwpmc cam"
# For small memory footprints
options VM_KMEM_SIZE_SCALE=1
Index: sys/mips/conf/AR91XX_BASE
===================================================================
--- sys/mips/conf/AR91XX_BASE
+++ sys/mips/conf/AR91XX_BASE
@@ -20,7 +20,7 @@
hints "AR91XX_BASE.hints"
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
-makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc"
+makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc"
options DDB
options KDB
Index: sys/mips/conf/AR933X_BASE
===================================================================
--- sys/mips/conf/AR933X_BASE
+++ sys/mips/conf/AR933X_BASE
@@ -20,7 +20,7 @@
hints "AR933X_BASE.hints"
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
-makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_vlan if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw"
+makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw"
options DDB
options KDB
Index: sys/mips/conf/AR934X_BASE
===================================================================
--- sys/mips/conf/AR934X_BASE
+++ sys/mips/conf/AR934X_BASE
@@ -20,7 +20,7 @@
hints "AR934X_BASE.hints"
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
-makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_vlan if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc ipfw ipfw_nat libalias"
+makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_gre if_vlan if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc ipfw ipfw_nat libalias"
# makeoptions MODULES_OVERRIDE=""
options DDB
Index: sys/mips/conf/PB92
===================================================================
--- sys/mips/conf/PB92
+++ sys/mips/conf/PB92
@@ -22,7 +22,7 @@
# who already are using it without modifying the default flash layout)
# we need to cut down on a lot of things.
-makeoptions MODULES_OVERRIDE="ath ath_pci ath_ahb bridgestp if_bridge if_gif if_gre random wlan wlan_acl wlan_amrr wlan_ccmp wlan_rssadapt wlan_tkip wlan_wep wlan_xauth usb ar71xx"
+makeoptions MODULES_OVERRIDE="ath ath_pci ath_ahb bridgestp if_bridge if_gif if_gre wlan wlan_acl wlan_amrr wlan_ccmp wlan_rssadapt wlan_tkip wlan_wep wlan_xauth usb ar71xx"
hints "PB92.hints"
include "../atheros/std.ar71xx"
Index: sys/mips/conf/QCA955X_BASE
===================================================================
--- sys/mips/conf/QCA955X_BASE
+++ sys/mips/conf/QCA955X_BASE
@@ -26,7 +26,7 @@
hints "QCA955X_BASE.hints"
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
-# makeoptions MODULES_OVERRIDE="random gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc"
+# makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_gre if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr ath ath_ahb hwpmc"
makeoptions MODULES_OVERRIDE="if_vlan ipfw if_gre if_gif if_bridge bridgestp"
options DDB
Index: sys/mips/conf/RT305X
===================================================================
--- sys/mips/conf/RT305X
+++ sys/mips/conf/RT305X
@@ -24,7 +24,7 @@
makeoptions KERNLOADADDR=0x80001000
# Don't build any modules yet.
-makeoptions MODULES_OVERRIDE="wlan_xauth wlan_wep wlan_tkip wlan_acl wlan_amrr wlan_ccmp wlan_rssadapt random if_bridge bridgestp msdosfs md ipfw dummynet libalias geom/geom_label ufs usb/uplcom usb/u3g usb/umodem usb/umass usb/ucom cam zlib"
+makeoptions MODULES_OVERRIDE="wlan_xauth wlan_wep wlan_tkip wlan_acl wlan_amrr wlan_ccmp wlan_rssadapt if_bridge bridgestp msdosfs md ipfw dummynet libalias geom/geom_label ufs usb/uplcom usb/u3g usb/umodem usb/umass usb/ucom cam zlib"
makeoptions RT3052F
include "../rt305x/std.rt305x"
Index: sys/modules/Makefile
===================================================================
--- sys/modules/Makefile
+++ sys/modules/Makefile
@@ -291,7 +291,6 @@
${_qlxgbe} \
ral \
${_ralfw} \
- ${_random} \
rc4 \
${_rdma} \
${_rdrand_rng} \
@@ -395,9 +394,6 @@
_crypto= crypto
_cryptodev= cryptodev
.endif
-.if exists(${.CURDIR}/../crypto)
-_random= random
-.endif
.endif
.if ${MK_CUSE} != "no" || defined(ALL_MODULES)
Index: sys/modules/crypto/Makefile
===================================================================
--- sys/modules/crypto/Makefile
+++ sys/modules/crypto/Makefile
@@ -12,7 +12,7 @@
KMOD = crypto
SRCS = crypto.c cryptodev_if.c
SRCS += criov.c cryptosoft.c xform.c
-SRCS += cast.c cryptodeflate.c rmd160.c rijndael-alg-fst.c rijndael-api.c
+SRCS += cast.c cryptodeflate.c rmd160.c rijndael-alg-fst.c rijndael-api.c rijndael-api-fst.c
SRCS += skipjack.c bf_enc.c bf_ecb.c bf_skey.c
SRCS += camellia.c camellia-api.c
SRCS += des_ecb.c des_enc.c des_setkey.c
Index: sys/modules/random/Makefile
===================================================================
--- sys/modules/random/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# $FreeBSD$
-
-.PATH: ${.CURDIR}/../../dev/random
-.PATH: ${.CURDIR}/../../crypto/rijndael
-.PATH: ${.CURDIR}/../../crypto/sha2
-
-KMOD= random
-SRCS= randomdev_soft.c
-SRCS+= yarrow.c fortuna.c hash.c
-SRCS+= rijndael-alg-fst.c rijndael-api-fst.c sha2.c sha256c.c
-SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h opt_random.h
-
-CFLAGS+= -I${.CURDIR}/../..
-
-.include <bsd.kmod.mk>
Index: sys/modules/random_fortuna/Makefile
===================================================================
--- /dev/null
+++ sys/modules/random_fortuna/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD= random_fortuna
+SRCS= fortuna.c hash.c
+SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h
+
+CFLAGS+= -I${.CURDIR}/../..
+
+.include <bsd.kmod.mk>
Index: sys/modules/random_yarrow/Makefile
===================================================================
--- /dev/null
+++ sys/modules/random_yarrow/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/random
+
+KMOD= random_yarrow
+SRCS= yarrow.c hash.c
+SRCS+= bus_if.h device_if.h vnode_if.h opt_cpu.h
+
+CFLAGS+= -I${.CURDIR}/../..
+
+.include <bsd.kmod.mk>
Index: sys/net/if_ethersubr.c
===================================================================
--- sys/net/if_ethersubr.c
+++ sys/net/if_ethersubr.c
@@ -426,6 +426,8 @@
}
#endif
+ random_harvest_queue(m, sizeof(*m), 2, RANDOM_NET_ETHER);
+
CURVNET_SET_QUIET(ifp->if_vnet);
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
@@ -570,8 +572,6 @@
m->m_flags |= M_PROMISC;
}
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_ETHER);
-
ether_demux(ifp, m);
CURVNET_RESTORE();
}
Index: sys/net/if_tun.c
===================================================================
--- sys/net/if_tun.c
+++ sys/net/if_tun.c
@@ -906,7 +906,7 @@
m_freem(m);
return (EAFNOSUPPORT);
}
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_TUN);
+ random_harvest_queue(&(m->m_data), 12, 2, RANDOM_NET_TUN);
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
CURVNET_SET(ifp->if_vnet);
Index: sys/netgraph/ng_iface.c
===================================================================
--- sys/netgraph/ng_iface.c
+++ sys/netgraph/ng_iface.c
@@ -705,7 +705,7 @@
m_freem(m);
return (EAFNOSUPPORT);
}
- random_harvest(&(m->m_data), 12, 2, RANDOM_NET_NG);
+ random_harvest_queue(&(m->m_data), 12, 2, RANDOM_NET_NG);
M_SETFIB(m, ifp->if_fib);
netisr_dispatch(isr, m);
return (0);
Index: sys/sys/kernel.h
===================================================================
--- sys/sys/kernel.h
+++ sys/sys/kernel.h
@@ -107,8 +107,8 @@
SI_SUB_KLD = 0x2000000, /* KLD and module setup */
SI_SUB_CPU = 0x2100000, /* CPU resource(s)*/
SI_SUB_RACCT = 0x2110000, /* resource accounting */
- SI_SUB_RANDOM = 0x2120000, /* random number generator */
SI_SUB_KDTRACE = 0x2140000, /* Kernel dtrace hooks */
+ SI_SUB_RANDOM = 0x2160000, /* random number generator */
SI_SUB_MAC = 0x2180000, /* TrustedBSD MAC subsystem */
SI_SUB_MAC_POLICY = 0x21C0000, /* TrustedBSD MAC policies */
SI_SUB_MAC_LATE = 0x21D0000, /* TrustedBSD MAC subsystem */
Index: sys/sys/random.h
===================================================================
--- sys/sys/random.h
+++ sys/sys/random.h
@@ -31,7 +31,7 @@
#ifdef _KERNEL
-int read_random(void *, int);
+u_int read_random(void *, u_int);
/*
* Note: if you add or remove members of random_entropy_source, remember to also update the
@@ -53,9 +53,10 @@
RANDOM_NET_NG,
RANDOM_INTERRUPT,
RANDOM_SWI,
- RANDOM_UMA_ALLOC,
- RANDOM_ENVIRONMENTAL_END, /* This one is wasted */
- /* High-quality HW RNGs from here on. */
+ RANDOM_FS_ATIME,
+ RANDOM_FAST, /* Special!! Miscellaneous high performance stuff, like UMA/SLAB Allocator */
+ RANDOM_ENVIRONMENTAL_END = RANDOM_FAST,
+ /* Fast hardware random-number sources from here on. */
RANDOM_PURE_OCTEON,
RANDOM_PURE_SAFE,
RANDOM_PURE_GLXSB,
@@ -67,7 +68,18 @@
RANDOM_PURE_VIRTIO,
ENTROPYSOURCE
};
-void random_harvest(const void *, u_int, u_int, enum random_entropy_source);
+
+#define RANDOM_HARVEST_EVERYTHING_MASK ((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1)
+
+#if defined(RANDOM_DUMMY)
+#define random_harvest_queue(a, b, c, d) do {} while (0)
+#define random_harvest_fast(a, b, c, d) do {} while (0)
+#define random_harvest_direct(a, b, c, d) do {} while (0)
+#else /* !defined(RANDOM_DUMMY) */
+void random_harvest_queue(const void *, u_int, u_int, enum random_entropy_source);
+void random_harvest_fast(const void *, u_int, u_int, enum random_entropy_source);
+void random_harvest_direct(const void *, u_int, u_int, enum random_entropy_source);
+#endif /* defined(RANDOM_DUMMY) */
#endif /* _KERNEL */
Index: sys/ufs/ffs/ffs_inode.c
===================================================================
--- sys/ufs/ffs/ffs_inode.c
+++ sys/ufs/ffs/ffs_inode.c
@@ -36,16 +36,17 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/mount.h>
-#include <sys/proc.h>
#include <sys/bio.h>
#include <sys/buf.h>
-#include <sys/vnode.h>
#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/random.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
-#include <sys/vmmeter.h>
#include <sys/stat.h>
+#include <sys/vmmeter.h>
+#include <sys/vnode.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -143,12 +144,17 @@
softdep_update_inodeblock(ip, bp, waitfor);
else if (ip->i_effnlink != ip->i_nlink)
panic("ffs_update: bad link cnt");
- if (ip->i_ump->um_fstype == UFS1)
+ if (ip->i_ump->um_fstype == UFS1) {
*((struct ufs1_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
- else
+ /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
+ random_harvest_queue(&(ip->i_din1), sizeof(ip->i_din1), 1, RANDOM_FS_ATIME);
+ } else {
*((struct ufs2_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
+ /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
+ random_harvest_queue(&(ip->i_din2), sizeof(ip->i_din2), 1, RANDOM_FS_ATIME);
+ }
if (waitfor && !DOINGASYNC(vp))
error = bwrite(bp);
else if (vm_page_count_severe() || buf_dirty_count_severe()) {
Index: sys/vm/uma_core.c
===================================================================
--- sys/vm/uma_core.c
+++ sys/vm/uma_core.c
@@ -2121,11 +2121,8 @@
int lockfail;
int cpu;
-#if 0
- /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
- /* The entropy here is desirable, but the harvesting is expensive */
- random_harvest(&(zone->uz_name), sizeof(void *), 1, RANDOM_UMA_ALLOC);
-#endif
+ /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
+ random_harvest_fast(&zone, sizeof(zone), 1, RANDOM_FAST);
/* This is the fast path allocation */
#ifdef UMA_DEBUG_ALLOC_1
@@ -2157,11 +2154,6 @@
zone->uz_fini(item, zone->uz_size);
return (NULL);
}
-#if 0
- /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
- /* The entropy here is desirable, but the harvesting is expensive */
- random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
-#endif
return (item);
}
/* This is unfortunate but should not be fatal. */
@@ -2204,11 +2196,6 @@
#endif
if (flags & M_ZERO)
uma_zero_item(item, zone);
-#if 0
- /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
- /* The entropy here is desirable, but the harvesting is expensive */
- random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
-#endif
return (item);
}
@@ -2329,11 +2316,6 @@
zalloc_item:
item = zone_alloc_item(zone, udata, flags);
-#if 0
- /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
- /* The entropy here is desirable, but the harvesting is expensive */
- random_harvest(&item, sizeof(void *), 1, RANDOM_UMA_ALLOC);
-#endif
return (item);
}
@@ -2681,18 +2663,8 @@
int lockfail;
int cpu;
-#if 0
- /* XXX: FIX!! Do not enable this in CURRENT!! MarkM */
- /* The entropy here is desirable, but the harvesting is expensive */
- struct entropy {
- const void *uz_name;
- const void *item;
- } entropy;
-
- entropy.uz_name = zone->uz_name;
- entropy.item = item;
- random_harvest(&entropy, sizeof(struct entropy), 2, RANDOM_UMA_ALLOC);
-#endif
+ /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
+ random_harvest_fast(&zone, sizeof(zone), 1, RANDOM_FAST);
#ifdef UMA_DEBUG_ALLOC_1
printf("Freeing item %p to %s(%p)\n", item, zone->uz_name, zone);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jul 3, 12:59 PM (9 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34624094
Default Alt Text
D2025.id6436.diff (189 KB)
Attached To
Mode
D2025: Tidy up random(4) driver after developer feedback and code audit.
Attached
Detach File
Event Timeline
Log In to Comment