Huge cleanup of random(4) code.
* GENERAL - Update copyright. - Make kernel options for RANDOM_YARROW and RANDOM_DUMMY. Set neither to ON, which means we want Fortuna - If there is no 'device random' in the kernel, there will be NO random(4) device in the kernel, and the KERN_ARND sysctl will return nothing. With RANDOM_DUMMY there will be a random(4) that always blocks. - Repair kern.arandom (KERN_ARND sysctl). The old version went through arc4random(9) and was a bit weird. - Adjust arc4random stirring a bit - the existing code looks a little suspect. - Fix the nasty pre- and post-read overloading by providing explictit functions to do these tasks. - Redo read_random(9) so as to duplicate random(4)'s read internals. This makes it a first-class citizen rather than a hack. - Move stuff out of locked regions when it does not need to be there. - Trim RANDOM_DEBUG printfs. Some are excess to requirement, some behind boot verbose. - Use SYSINIT to sequence the startup. - Fix init/deinit sysctl stuff. - Make relevant sysctls also tunables. - Add different harvesting "styles" to allow for different requirements (direct, queue, fast). - Add harvesting of FFS atime events. This needs to be checked for weighing down the FS code. - Add harvesting of slab allocator events. This needs to be checked for weighing down the allocator code. - Fix the random(9) manpage. - Loadable modules are not present for now. These will be re-engineered when the dust settles. - Use macros for locks. - Fix comments. * src/share/man/... - Update the man pages. * src/etc/... - The startup/shutdown work is done in D2924. * src/UPDATING - Add UPDATING announcement. * src/sys/dev/random/build.sh - Add copyright. - Add libz for unit tests. * src/sys/dev/random/dummy.c - Remove; no longer needed. Functionality incorporated into randomdev.*. * live_entropy_sources.c live_entropy_sources.h - Remove; content moved. - move content to randomdev.[ch] and optimise. * src/sys/dev/random/random_adaptors.c src/sys/dev/random/random_adaptors.h - Remove; plugability is no longer used. Compile-time algorithm selection is the way to go. * src/sys/dev/random/random_harvestq.c src/sys/dev/random/random_harvestq.h - Add early (re)boot-time randomness caching. * src/sys/dev/random/randomdev_soft.c src/sys/dev/random/randomdev_soft.h - Remove; no longer needed. * src/sys/dev/random/uint128.h - Provide a fake uint128_t; if a real one ever arrived, we can use that instead. All that is needed here is N=0, N++, N==0, and some localised trickery is used to manufacture a 128-bit 0ULLL. * src/sys/dev/random/unit_test.c src/sys/dev/random/unit_test.h - Improve unit tests; previously the testing human needed clairvoyance; now the test will do a basic check of compressibility. Clairvoyant talent is still a good idea. - This is still a long way off a proper unit test. * src/sys/dev/random/fortuna.c src/sys/dev/random/fortuna.h - Improve messy union to just uint128_t. - Remove unneeded 'static struct fortuna_start_cache'. - Tighten up up arithmetic. - Provide a method to allow eternal junk to be introduced; harden it against blatant by compress/hashing. - Assert that locks are held correctly. - Fix the nasty pre- and post-read overloading by providing explictit functions to do these tasks. - Turn into self-sufficient module (no longer requires randomdev_soft.[ch]) * src/sys/dev/random/yarrow.c src/sys/dev/random/yarrow.h - Improve messy union to just uint128_t. - Remove unneeded 'staic struct start_cache'. - Tighten up up arithmetic. - Provide a method to allow eternal junk to be introduced; harden it against blatant by compress/hashing. - Assert that locks are held correctly. - Fix the nasty pre- and post-read overloading by providing explictit functions to do these tasks. - Turn into self-sufficient module (no longer requires randomdev_soft.[ch]) - Fix some magic numbers elsewhere used as FAST and SLOW. Differential Revision: https://reviews.freebsd.org/D2025 Reviewed by: vsevolod,delphij,rwatson,trasz,jmg Approved by: so (delphij)
This commit is contained in:
parent
6ef120027f
commit
d1b06863fb
35
UPDATING
35
UPDATING
@ -31,6 +31,41 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW:
|
||||
disable the most expensive debugging functionality run
|
||||
"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
|
||||
|
||||
20150630:
|
||||
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.
|
||||
|
||||
20150623:
|
||||
An additional fix for the issue described in the 20150614 sendmail
|
||||
entry below has been been committed in revision 284717.
|
||||
|
@ -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 30, 2015
|
||||
.Dt RANDOM 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -37,31 +37,32 @@ The
|
||||
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
|
||||
.Xr random 4
|
||||
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.
|
||||
seeding as soon as possible.
|
||||
.Pp
|
||||
It is also possible
|
||||
to read random bytes
|
||||
by using the KERN_ARND sysctl.
|
||||
On the command line
|
||||
this could be done by
|
||||
.Pp
|
||||
.Dl "sysctl -x -B 16 kern.arandom"
|
||||
.Pp
|
||||
This sysctl will not return
|
||||
random bytes unless
|
||||
the
|
||||
.Xr random 4
|
||||
is seeded.
|
||||
.Pp
|
||||
This initial seeding
|
||||
of random number generators
|
||||
@ -90,101 +91,57 @@ To see the current settings of the software
|
||||
.Nm
|
||||
device, use the command line:
|
||||
.Pp
|
||||
.Dl sysctl kern.random
|
||||
.Dl "sysctl kern.random"
|
||||
.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.
|
||||
.Dl kern.random.fortuna.minpoolsize
|
||||
and
|
||||
.Dl kern.random.harvest.mask
|
||||
all settings are read-only.
|
||||
.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).
|
||||
.Pa kern.random.fortuna.minpoolsize
|
||||
sysctl is used
|
||||
to set the seed threshhold.
|
||||
A smaller number gives a faster seed,
|
||||
but a less secure one.
|
||||
In practice,
|
||||
values between 64 and 256
|
||||
are acceptable.
|
||||
.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.
|
||||
.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
|
||||
.Pp
|
||||
Internal
|
||||
.Xr sysctl 3
|
||||
handlers force the above variables
|
||||
into the stated ranges.
|
||||
.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.
|
||||
See
|
||||
.Xr random_harvest 9
|
||||
for more on the harvesting of entropy.
|
||||
.Sh RANDOMNESS
|
||||
The use of randomness in the field of computing
|
||||
is a rather subtle issue because randomness means
|
||||
@ -308,23 +265,36 @@ so its use is discouraged.
|
||||
.Xr RAND_add 3 ,
|
||||
.Xr RAND_bytes 3 ,
|
||||
.Xr random 3 ,
|
||||
.Xr sysctl 8
|
||||
.Xr sysctl 8 ,
|
||||
.Xr random 9
|
||||
.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 10.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.
|
||||
|
@ -1,4 +1,6 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2015
|
||||
.\" Mark R V Murray
|
||||
.\" Copyright (c) 2000
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
@ -26,7 +28,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\" "
|
||||
.Dd September 25, 2000
|
||||
.Dd June 30, 2015
|
||||
.Dt RANDOM 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -53,11 +55,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 +70,28 @@ function may be called with any arbitrary
|
||||
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,
|
||||
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 +102,24 @@ if it has been loaded.
|
||||
If the entropy device is not loaded, then
|
||||
the
|
||||
.Fa buffer
|
||||
is filled with output generated by
|
||||
.Fn random .
|
||||
is ignored
|
||||
and zero is returned.
|
||||
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
|
||||
unless it is
|
||||
necessary to know
|
||||
that no entropy
|
||||
has been returned.
|
||||
.Pp
|
||||
All the bits generated by
|
||||
All the bits returned by
|
||||
.Fn random ,
|
||||
.Fn arc4rand
|
||||
and
|
||||
@ -120,32 +137,38 @@ to return a 32 bit pseudo-random integer.
|
||||
.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
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2002 Mark R V Murray
|
||||
.\" Copyright (c) 2002-2015 Mark R V Murray
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -25,7 +25,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 6, 2002
|
||||
.Dd June 30, 2015
|
||||
.Dt RANDOM_HARVEST 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -35,59 +35,93 @@
|
||||
.In sys/types.h
|
||||
.In sys/random.h
|
||||
.Ft void
|
||||
.Fo random_harvest
|
||||
.Fo random_harvest_direct
|
||||
.Fa "void *entropy"
|
||||
.Fa "u_int size"
|
||||
.Fa "u_int bits"
|
||||
.Fa "enum esource source"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo random_harvest_fast
|
||||
.Fa "void *entropy"
|
||||
.Fa "u_int size"
|
||||
.Fa "u_int bits"
|
||||
.Fa "enum esource source"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo random_harvest_queue
|
||||
.Fa "void *entropy"
|
||||
.Fa "u_int size"
|
||||
.Fa "u_int bits"
|
||||
.Fa "u_int frac"
|
||||
.Fa "enum esource source"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Fn random_harvest
|
||||
function is used by device drivers
|
||||
.Fn random_harvest_*
|
||||
functions are used by device drivers
|
||||
and other kernel processes to pass data
|
||||
that is considered (at least partially) stochastic
|
||||
to the entropy device.
|
||||
.Pp
|
||||
The caller should pass a pointer (to no more than 16 bytes) of
|
||||
the
|
||||
The caller should pass
|
||||
a pointer pointing to the
|
||||
.Dq random
|
||||
data in
|
||||
.Fa entropy .
|
||||
The argument
|
||||
.Fa size
|
||||
contains the number of bytes pointed to.
|
||||
The caller should
|
||||
The
|
||||
.Fa source
|
||||
is chosen from one of
|
||||
the values enumerated in
|
||||
.Pa sys/dev/random.h .
|
||||
and is used to indicate the source of the entropy.
|
||||
.Pp
|
||||
The
|
||||
.Fo random_harvest_direct
|
||||
.Fc
|
||||
variant is used
|
||||
for early harvesting
|
||||
before any multitasking
|
||||
is enabled.
|
||||
.Pp
|
||||
The
|
||||
.Fn random_harvest_fast
|
||||
variant is used
|
||||
by sources that
|
||||
should not take
|
||||
a performance hit
|
||||
from harvesting,
|
||||
as they are high-rate
|
||||
sources.
|
||||
Some entropy is sacrificed,
|
||||
but the hig rate of supply
|
||||
will compensate for this.
|
||||
.Pp
|
||||
The
|
||||
.Fn random_harvest_queue
|
||||
variant is used
|
||||
for general harvesting
|
||||
and is the default
|
||||
choice for most entropy sources
|
||||
such as interrupts
|
||||
or console events.
|
||||
.Pp
|
||||
The
|
||||
.Fa bits
|
||||
argument is only used
|
||||
by the deprecated Yarrow algorithm.
|
||||
For compatibility,
|
||||
the caller should
|
||||
.Em "very conservatively"
|
||||
estimate the number of random bits
|
||||
in the sample,
|
||||
and pass this in
|
||||
.Fa bits
|
||||
or
|
||||
.Fa frac .
|
||||
If the estimated number of bits per sample is an integer, then
|
||||
.Fa bits
|
||||
is used, and
|
||||
.Fa frac
|
||||
is 0.
|
||||
Otherwise,
|
||||
for low-entropy samples,
|
||||
.Dq fractional
|
||||
entropy can be supplied in
|
||||
.Fa frac .
|
||||
(This is considered to be
|
||||
.Fa frac /
|
||||
1024 bits of entropy.)
|
||||
The
|
||||
.Fa source
|
||||
is chosen from
|
||||
.Dv RANDOM_WRITE , RANDOM_KEYBOARD , RANDOM_MOUSE , RANDOM_NET
|
||||
and
|
||||
.Dv RANDOM_INTERRUPT ,
|
||||
and is used to indicate the source of the entropy.
|
||||
.Fa bits .
|
||||
.Pp
|
||||
Interrupt harvesting has been simplified
|
||||
Interrupt harvesting has been
|
||||
in part simplified simplified
|
||||
for the kernel programmer.
|
||||
If a device driver registers an interrupt handler
|
||||
with
|
||||
@ -101,6 +135,7 @@ bit in the
|
||||
.Fa flags
|
||||
argument to have that interrupt source
|
||||
be used for entropy harvesting.
|
||||
This should be done wherever practicable.
|
||||
.Sh SEE ALSO
|
||||
.Xr random 4 ,
|
||||
.Xr BUS_SETUP_INTR 9
|
||||
|
@ -528,14 +528,14 @@ crypto/des/des_ecb.c optional crypto | ipsec | netsmb
|
||||
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 @@ rt2860.fw optional rt2860fw | ralfw \
|
||||
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
|
||||
|
@ -939,9 +939,16 @@ RACCT_DEFAULT_TO_DISABLED opt_global.h
|
||||
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
|
||||
|
@ -476,7 +476,8 @@ glxsb_rnd(void *v)
|
||||
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);
|
||||
|
@ -258,7 +258,8 @@ hifn_partname(struct hifn_softc *sc)
|
||||
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
|
||||
|
@ -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 @@ cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_YARROW \
|
||||
../../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 @@ cc -g -O0 -pthread -DRANDOM_DEBUG -DRANDOM_FORTUNA \
|
||||
../../crypto/rijndael/rijndael-alg-fst.c \
|
||||
../../crypto/sha2/sha2.c \
|
||||
../../crypto/sha2/sha256c.c \
|
||||
-lz \
|
||||
-o funit_test
|
||||
|
@ -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,
|
||||
};
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ __FBSDID("$FreeBSD$");
|
||||
#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
|
||||
/* 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 */
|
||||
|
||||
#if defined(RANDOM_FORTUNA)
|
||||
/*
|
||||
* 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);
|
||||
|
||||
#define NPOOLS 32
|
||||
#define MINPOOLSIZE 64
|
||||
#define DEFPOOLSIZE 256
|
||||
#define MAXPOOLSIZE 65536
|
||||
/* 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 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.
|
||||
/*
|
||||
* 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;
|
||||
|
||||
static struct fortuna_start_cache {
|
||||
uint8_t junk[PAGE_SIZE];
|
||||
size_t length;
|
||||
struct randomdev_hash hash;
|
||||
} fortuna_start_cache;
|
||||
|
||||
#ifdef _KERNEL
|
||||
static struct sysctl_ctx_list random_clist;
|
||||
RANDOM_CHECK_UINT(minpoolsize, MINPOOLSIZE, MAXPOOLSIZE);
|
||||
RANDOM_CHECK_UINT(fs_minpoolsize, RANDOM_FORTUNA_MINPOOLSIZE, RANDOM_FORTUNA_MAXPOOLSIZE);
|
||||
#else
|
||||
static uint8_t zero_region[RANDOM_ZERO_BLOCKSIZE];
|
||||
#endif
|
||||
|
||||
void
|
||||
random_fortuna_init_alg(void)
|
||||
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
|
||||
/* 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
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
/* 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);
|
||||
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.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/* F&S - Reseed() */
|
||||
/* Reseed Mutex is held */
|
||||
/*-
|
||||
* 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
|
||||
reseed(uint8_t *junk, u_int length)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*-
|
||||
* 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
|
||||
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_pre_read(void)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
sbintime_t now;
|
||||
#endif
|
||||
struct randomdev_hash context;
|
||||
uint32_t s[RANDOM_FORTUNA_NPOOLS*RANDOM_KEYSIZE_WORDS];
|
||||
uint8_t temp[RANDOM_KEYSIZE];
|
||||
u_int i;
|
||||
|
||||
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 (fortuna_state.fs_pool[0].fsp_length >= fortuna_state.fs_minpoolsize
|
||||
#ifdef _KERNEL
|
||||
/* FS&K - Use 'getsbinuptime()' to prevent reseed-spamming. */
|
||||
&& (now - fortuna_state.fs_lasttime > hz/10)
|
||||
#endif
|
||||
) {
|
||||
#ifdef _KERNEL
|
||||
fortuna_state.fs_lasttime = now;
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
{
|
||||
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));
|
||||
}
|
||||
RANDOM_RESEED_UNLOCK();
|
||||
}
|
||||
|
||||
/*-
|
||||
* 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_read(uint8_t *buf, u_int bytecount)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
sbintime_t thistime;
|
||||
#endif
|
||||
struct randomdev_hash context;
|
||||
uint8_t s[NPOOLS*KEYSIZE], temp[KEYSIZE];
|
||||
int i;
|
||||
u_int seedlength;
|
||||
|
||||
/* We must be locked for all this as plenty of state gets messed with */
|
||||
mtx_lock(&random_reseed_mtx);
|
||||
|
||||
/* 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
|
||||
#ifdef _KERNEL
|
||||
/* F&S - Use 'getsbinuptime()' to prevent reseed-spamming. */
|
||||
&& ((thistime = getsbinuptime()) - fortuna_state.lasttime > hz/10)
|
||||
#endif
|
||||
) {
|
||||
#ifdef _KERNEL
|
||||
fortuna_state.lasttime = thistime;
|
||||
#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;
|
||||
}
|
||||
#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));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if buf != NULL do a regular read. */
|
||||
else
|
||||
random_fortuna_genrandom(buf, bytecount);
|
||||
|
||||
mtx_unlock(&random_reseed_mtx);
|
||||
RANDOM_RESEED_LOCK();
|
||||
random_fortuna_genrandom(buf, bytecount);
|
||||
RANDOM_RESEED_UNLOCK();
|
||||
}
|
||||
|
||||
/* Internal function to hand external entropy to the PRNG */
|
||||
void
|
||||
random_fortuna_post_read(void)
|
||||
{
|
||||
|
||||
/* CWOT */
|
||||
}
|
||||
|
||||
/* Internal function to hand external entropy to the PRNG. */
|
||||
void
|
||||
random_fortuna_write(uint8_t *buf, u_int count)
|
||||
{
|
||||
uint8_t temp[KEYSIZE];
|
||||
int i;
|
||||
uintmax_t timestamp;
|
||||
struct randomdev_hash hash;
|
||||
uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], 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);
|
||||
|
||||
randomdev_hash_init(&fortuna_start_cache.hash);
|
||||
|
||||
reseed(fortuna_start_cache.junk, MIN(PAGE_SIZE, fortuna_start_cache.length));
|
||||
memset(fortuna_start_cache.junk, 0, sizeof(fortuna_start_cache.junk));
|
||||
|
||||
mtx_unlock(&random_reseed_mtx);
|
||||
/* 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 @@ int
|
||||
random_fortuna_seeded(void)
|
||||
{
|
||||
|
||||
return (!uint128_is_zero(fortuna_state.counter.whole));
|
||||
return (!uint128_is_zero(fortuna_state.fs_counter));
|
||||
}
|
||||
|
||||
#endif /* RANDOM_FORTUNA */
|
||||
|
@ -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 */
|
||||
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ randomdev_hash_iterate(struct randomdev_hash *context, const void *data, size_t
|
||||
}
|
||||
|
||||
/* 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 @@ randomdev_hash_finish(struct randomdev_hash *context, void *buf)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
@ -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_hash_finish(struct randomdev_hash *, void *);
|
||||
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 */
|
||||
|
@ -46,18 +46,15 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ rdrand_modevent(module_t mod, int type, void *unused)
|
||||
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:
|
||||
|
@ -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);
|
||||
}
|
@ -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 */
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ nehemiah_modevent(module_t mod, int type, void *unused)
|
||||
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 @@ nehemiah_modevent(module_t mod, int type, void *unused)
|
||||
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:
|
||||
|
@ -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);
|
@ -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 */
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ static struct sysctl_ctx_list random_clist;
|
||||
* 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
|
||||
|
||||
/* 1 to let the kernel thread run, 0 to terminate */
|
||||
volatile int random_kthread_control;
|
||||
|
||||
/*
|
||||
* The harvest mutex protects the consistency of the entropy Fifos and
|
||||
* empty fifo and other associated structures.
|
||||
* Put all the harvest queue context stuff in one place.
|
||||
* this make is a bit easier to lock and protect.
|
||||
*/
|
||||
static struct mtx harvest_mtx;
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static struct entropyfifo {
|
||||
struct harvest_event ring[RANDOM_FIFO_MAX];
|
||||
volatile u_int ring_in;
|
||||
volatile u_int ring_out;
|
||||
} entropyfifo;
|
||||
static struct kproc_desc random_proc_kp = {
|
||||
"rand_harvestq",
|
||||
random_kthread,
|
||||
&harvest_context.hc_kthread_proc,
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
/* <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 @@ random_print_harvestmask(SYSCTL_HANDLER_ARGS)
|
||||
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 @@ static const char *(random_source_descr[]) = {
|
||||
"NET_NG",
|
||||
"INTERRUPT",
|
||||
"SWI",
|
||||
"UMA_ALLOC",
|
||||
"", /* "ENVIRONMENTAL_END" */
|
||||
"FS_ATIME",
|
||||
"HIGH_PERFORMANCE", /* ENVIRONMENTAL_END */
|
||||
"PURE_OCTEON",
|
||||
"PURE_SAFE",
|
||||
"PURE_GLXSB",
|
||||
@ -231,112 +220,111 @@ random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS)
|
||||
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;
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* 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.");
|
||||
|
||||
/* 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 @@ random_harvestq_deinit(void)
|
||||
* 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));
|
||||
}
|
||||
|
@ -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 */
|
||||
};
|
||||
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;
|
||||
|
||||
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);
|
||||
#define RANDOM_HARVESTQ_BOOT_ENTROPY_FILE "/boot/entropy"
|
||||
|
||||
/* 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];
|
||||
#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 */
|
||||
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
#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,10 +82,183 @@ static struct cdevsw random_cdevsw = {
|
||||
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");
|
||||
|
||||
#if defined(RANDOM_DUMMY)
|
||||
|
||||
/*-
|
||||
* 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 (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dummy_random(void)
|
||||
{
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#else /* !defined(RANDOM_DUMMY) */
|
||||
|
||||
LIST_HEAD(sources_head, random_sources);
|
||||
static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list);
|
||||
static u_int read_rate;
|
||||
|
||||
#endif /* defined(RANDOM_DUMMY) */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*-
|
||||
* 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);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
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);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
|
||||
{
|
||||
|
||||
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_unblock(void)
|
||||
{
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
|
||||
@ -103,30 +271,107 @@ randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
|
||||
case FIOASYNC:
|
||||
case FIONBIO:
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ENOTTY;
|
||||
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* 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
|
||||
random_source_register(struct random_source *rsource)
|
||||
{
|
||||
#if defined(RANDOM_DUMMY)
|
||||
(void)rsource;
|
||||
#else /* !defined(RANDOM_DUMMY) */
|
||||
struct random_sources *rrs;
|
||||
|
||||
KASSERT(rsource != NULL, ("invalid input to %s", __func__));
|
||||
|
||||
rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK);
|
||||
rrs->rrs_source = rsource;
|
||||
|
||||
printf("random: registering fast source %s\n", rsource->rs_ident);
|
||||
LIST_INSERT_HEAD(&source_list, rrs, rrs_entries);
|
||||
#endif /* defined(RANDOM_DUMMY) */
|
||||
}
|
||||
|
||||
void
|
||||
random_source_deregister(struct random_source *rsource)
|
||||
{
|
||||
#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) */
|
||||
}
|
||||
|
||||
#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_set_wakeup_exit(void *control)
|
||||
random_sources_feed(void)
|
||||
{
|
||||
uint32_t entropy[HARVESTSIZE];
|
||||
struct random_sources *rrs;
|
||||
u_int i, n, local_read_rate;
|
||||
|
||||
wakeup(control);
|
||||
kproc_exit(0);
|
||||
/* NOTREACHED */
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
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) */
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
randomdev_modevent(module_t mod __unused, int type, void *data __unused)
|
||||
@ -135,115 +380,28 @@ randomdev_modevent(module_t mod __unused, int type, void *data __unused)
|
||||
|
||||
switch (type) {
|
||||
case MOD_LOAD:
|
||||
printf("random: entropy device infrastructure driver\n");
|
||||
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 */
|
||||
random_adaptors_init();
|
||||
break;
|
||||
|
||||
case MOD_UNLOAD:
|
||||
random_adaptors_deinit();
|
||||
destroy_dev(random_dev);
|
||||
break;
|
||||
|
||||
case MOD_SHUTDOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
DEV_MODULE_ORDERED(randomdev, randomdev_modevent, NULL, SI_ORDER_SECOND);
|
||||
MODULE_VERSION(randomdev, 1);
|
||||
static moduledata_t randomdev_mod = {
|
||||
"random_device",
|
||||
randomdev_modevent,
|
||||
0
|
||||
};
|
||||
|
||||
/* ================
|
||||
* Harvesting stubs
|
||||
* ================
|
||||
*/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Initialise the harvester when/if it is loaded */
|
||||
void
|
||||
randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source))
|
||||
{
|
||||
|
||||
reap_func = reaper;
|
||||
}
|
||||
|
||||
/* Deinitialise the harvester when/if it is unloaded */
|
||||
void
|
||||
randomdev_deinit_harvester(void)
|
||||
{
|
||||
|
||||
reap_func = random_harvest_phony;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
||||
(*reap_func)(entropy, count, bits, origin);
|
||||
}
|
||||
|
||||
/* ================================
|
||||
* Internal reading stubs and fakes
|
||||
* ================================
|
||||
*/
|
||||
|
||||
/* Hold the address of the routine which is actually called */
|
||||
static void (*read_func)(uint8_t *, u_int) = dummy_random_read_phony;
|
||||
|
||||
/* Initialise the reader when/if it is loaded */
|
||||
void
|
||||
randomdev_init_reader(void (*reader)(uint8_t *, u_int))
|
||||
{
|
||||
|
||||
read_func = reader;
|
||||
}
|
||||
|
||||
/* Deinitialise the reader when/if it is unloaded */
|
||||
void
|
||||
randomdev_deinit_reader(void)
|
||||
{
|
||||
|
||||
read_func = dummy_random_read_phony;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
||||
if (count < 0)
|
||||
return 0;
|
||||
|
||||
read_func(buf, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
|
||||
MODULE_VERSION(random_device, 1);
|
||||
|
@ -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 */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 2000-2013 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
|
||||
@ -23,17 +23,50 @@
|
||||
* (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
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
/* This header contains only those definitions that are
|
||||
* specific to the entropy processor
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
void randomdev_init(void);
|
||||
void randomdev_deinit(void);
|
||||
#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)
|
||||
{
|
||||
}
|
@ -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
|
@ -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__
|
||||
#define USE_REAL_UINT128_T
|
||||
#endif
|
||||
|
||||
#ifdef USE_REAL_UINT128_T
|
||||
typedef __uint128_t uint128_t;
|
||||
#define UINT128_ZERO 0ULL
|
||||
#else
|
||||
typedef uint64_t uint128_t[2];
|
||||
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_clear(uint128_t *big_uint)
|
||||
uint128_increment(uint128_t *big_uintp)
|
||||
{
|
||||
#ifdef __SIZEOF_INT128__
|
||||
(*big_uint) = 0ULL;
|
||||
#ifdef USE_REAL_UINT128_T
|
||||
(*big_uintp)++;
|
||||
#else
|
||||
(*big_uint)[0] = (*big_uint)[1] = 0UL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline void
|
||||
uint128_increment(uint128_t *big_uint)
|
||||
{
|
||||
#ifdef __SIZEOF_INT128__
|
||||
(*big_uint)++;
|
||||
#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
|
||||
}
|
||||
|
||||
|
@ -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 @@ cc -g -O0 -pthread -DRANDOM_<alg> -DRANDOM_DEBUG -I../.. -lstdthreads -Wall \
|
||||
../../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 @@ Where <alg> is YARROW or FORTUNA.
|
||||
#include <stdlib.h>
|
||||
#include <threads.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "unit_test.h"
|
||||
|
||||
@ -59,10 +61,77 @@ Where <alg> is YARROW or FORTUNA.
|
||||
#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 @@ WriteCSPRNG(void *threadid)
|
||||
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 @@ WriteCSPRNG(void *threadid)
|
||||
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 @@ ReadCSPRNG(void *threadid)
|
||||
#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 @@ main(int argc, char *argv[])
|
||||
|
||||
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);
|
||||
|
@ -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 @@ enum random_entropy_source {
|
||||
|
||||
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 */
|
||||
|
@ -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 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ __FBSDID("$FreeBSD$");
|
||||
#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
|
||||
#define RANDOM_YARROW_TIMEBIN 16 /* max value for Pt/t */
|
||||
|
||||
#if defined(RANDOM_YARROW)
|
||||
#define RANDOM_YARROW_FAST 0
|
||||
#define RANDOM_YARROW_SLOW 1
|
||||
#define RANDOM_YARROW_NPOOLS 2
|
||||
|
||||
#define TIMEBIN 16 /* max value for Pt/t */
|
||||
/* 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);
|
||||
|
||||
#define FAST 0
|
||||
#define SLOW 1
|
||||
|
||||
/* 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.
|
||||
/*
|
||||
* 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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
/* 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"));
|
||||
/* 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
|
||||
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");
|
||||
}
|
||||
#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_post_read(void)
|
||||
{
|
||||
|
||||
/* CWOT */
|
||||
}
|
||||
|
||||
/* Internal function to hand external entropy to the PRNG. */
|
||||
void
|
||||
random_yarrow_write(uint8_t *buf, u_int count)
|
||||
{
|
||||
uintmax_t timestamp;
|
||||
struct randomdev_hash hash;
|
||||
uint32_t entropy_data[RANDOM_KEYSIZE_WORDS], 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);
|
||||
}
|
||||
|
||||
static void
|
||||
generator_gate(void)
|
||||
{
|
||||
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);
|
||||
/* 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 */
|
||||
|
@ -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 */
|
||||
|
@ -145,16 +145,9 @@ rndtest_harvest(struct rndtest_state *rsp, void *buf, u_int len)
|
||||
*/
|
||||
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
|
||||
|
@ -211,7 +211,8 @@ safe_partname(struct safe_softc *sc)
|
||||
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 */
|
||||
|
||||
|
@ -666,7 +666,7 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
|
||||
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 };
|
||||
|
@ -3411,7 +3411,7 @@ scgetc(sc_softc_t *sc, u_int flags)
|
||||
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);
|
||||
|
@ -259,7 +259,8 @@ ubsec_partname(struct ubsec_softc *sc)
|
||||
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
|
||||
|
@ -215,7 +215,7 @@ vtrnd_harvest(struct vtrnd_softc *sc)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
|
||||
{
|
||||
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) {
|
||||
|
@ -139,7 +139,7 @@ sysmouse_process_event(mouse_info_t *mi)
|
||||
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) {
|
||||
|
@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
|
||||
}
|
||||
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
|
||||
|
@ -888,7 +888,7 @@ intr_event_schedule_thread(struct intr_event *ie)
|
||||
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 @@ intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it)
|
||||
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 @@ swi_sched(void *cookie, int flags)
|
||||
|
||||
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
|
||||
|
@ -43,16 +43,17 @@ __FBSDID("$FreeBSD$");
|
||||
#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 @@ sysctl_kern_arnd(SYSCTL_HANDLER_ARGS)
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -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 @@ device_attach(device_t dev)
|
||||
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;
|
||||
|
@ -22,7 +22,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ arc4_swap(u_int8_t *a, u_int8_t *b)
|
||||
* 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();
|
||||
|
@ -50,7 +50,7 @@ srandom(seed)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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].
|
||||
*/
|
||||
|
@ -125,7 +125,8 @@ octeon_rnd_harvest(void *arg)
|
||||
|
||||
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);
|
||||
|
@ -24,7 +24,7 @@ makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||
|
||||
# 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
|
||||
|
@ -25,7 +25,7 @@ makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
|
||||
|
||||
# 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
|
||||
|
@ -20,7 +20,7 @@ files "../atheros/files.ar71xx"
|
||||
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
|
||||
|
@ -20,7 +20,7 @@ files "../atheros/files.ar71xx"
|
||||
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
|
||||
|
@ -20,7 +20,7 @@ files "../atheros/files.ar71xx"
|
||||
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
|
||||
|
@ -22,7 +22,7 @@ options AR71XX_ENV_UBOOT
|
||||
# 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"
|
||||
|
@ -26,7 +26,7 @@ files "../atheros/files.ar71xx"
|
||||
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
|
||||
|
@ -24,7 +24,7 @@ makeoptions MIPS_LITTLE_ENDIAN=defined
|
||||
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"
|
||||
|
@ -291,7 +291,6 @@ SUBDIR= \
|
||||
${_qlxgbe} \
|
||||
ral \
|
||||
${_ralfw} \
|
||||
${_random} \
|
||||
rc4 \
|
||||
${_rdma} \
|
||||
${_rdrand_rng} \
|
||||
@ -395,9 +394,6 @@ _autofs= autofs
|
||||
_crypto= crypto
|
||||
_cryptodev= cryptodev
|
||||
.endif
|
||||
.if exists(${.CURDIR}/../crypto)
|
||||
_random= random
|
||||
.endif
|
||||
.endif
|
||||
|
||||
.if ${MK_CUSE} != "no" || defined(ALL_MODULES)
|
||||
|
@ -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
|
||||
|
@ -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>
|
@ -426,6 +426,8 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
#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 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
|
||||
m->m_flags |= M_PROMISC;
|
||||
}
|
||||
|
||||
random_harvest(&(m->m_data), 12, 2, RANDOM_NET_ETHER);
|
||||
|
||||
ether_demux(ifp, m);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag)
|
||||
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);
|
||||
|
@ -705,7 +705,7 @@ ng_iface_rcvdata(hook_p hook, item_p item)
|
||||
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);
|
||||
|
@ -107,8 +107,8 @@ enum sysinit_sub_id {
|
||||
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 */
|
||||
|
@ -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 @@ enum random_entropy_source {
|
||||
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 @@ enum random_entropy_source {
|
||||
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 */
|
||||
|
||||
|
@ -36,16 +36,17 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#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 @@ ffs_update(vp, waitfor)
|
||||
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()) {
|
||||
|
@ -2135,11 +2135,8 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
|
||||
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
|
||||
@ -2171,11 +2168,6 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
|
||||
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. */
|
||||
@ -2218,11 +2210,6 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
|
||||
#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);
|
||||
}
|
||||
|
||||
@ -2343,11 +2330,6 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2695,18 +2677,8 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata)
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user