summaryrefslogtreecommitdiff
path: root/sys/dev/rndpool.c
diff options
context:
space:
mode:
authortls <tls@NetBSD.org>2012-02-02 19:42:57 +0000
committertls <tls@NetBSD.org>2012-02-02 19:42:57 +0000
commitcc9ee3de3e25ef31d3a97dc35bedc36945e35d2a (patch)
tree06a2889eb6b4b02bc8b8bba6b5cc3f9b1938d18b /sys/dev/rndpool.c
parentf622122a62827e27b444c2f95632d61f73357ced (diff)
Entropy-pool implementation move and cleanup.
1) Move core entropy-pool code and source/sink/sample management code to sys/kern from sys/dev. 2) Remove use of NRND as test for presence of entropy-pool code throughout source tree. 3) Remove use of RND_ENABLED in device drivers as microoptimization to avoid expensive operations on disabled entropy sources; make the rnd_add calls do this directly so all callers benefit. 4) Fix bug in recent rnd_add_data()/rnd_add_uint32() changes that might have lead to slight entropy overestimation for some sources. 5) Add new source types for environmental sensors, power sensors, VM system events, and skew between clocks, with a sample implementation for each. ok releng to go in before the branch due to the difficulty of later pullup (widespread #ifdef removal and moved files). Tested with release builds on amd64 and evbarm and live testing on amd64.
Diffstat (limited to 'sys/dev/rndpool.c')
-rw-r--r--sys/dev/rndpool.c311
1 files changed, 0 insertions, 311 deletions
diff --git a/sys/dev/rndpool.c b/sys/dev/rndpool.c
deleted file mode 100644
index 10c8fb70ef1..00000000000
--- a/sys/dev/rndpool.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/* $NetBSD: rndpool.c,v 1.22 2011/12/17 20:05:38 tls Exp $ */
-
-/*-
- * Copyright (c) 1997 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Michael Graff <explorer@flame.org>. This code uses ideas and
- * algorithms from the Linux driver written by Ted Ts'o.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rndpool.c,v 1.22 2011/12/17 20:05:38 tls Exp $");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sha1.h>
-
-#include <sys/rnd.h>
-#include <dev/rnd_private.h>
-
-/*
- * The random pool "taps"
- */
-#define TAP1 99
-#define TAP2 59
-#define TAP3 31
-#define TAP4 9
-#define TAP5 7
-
-/*
- * Let others know: the pool is full.
- */
-int rnd_full;
-
-static inline void rndpool_add_one_word(rndpool_t *, u_int32_t);
-
-void
-rndpool_init(rndpool_t *rp)
-{
-
- rp->cursor = 0;
- rp->rotate = 1;
-
- memset(&rp->stats, 0, sizeof(rp->stats));
-
- rp->stats.curentropy = 0;
- rp->stats.poolsize = RND_POOLWORDS;
- rp->stats.threshold = RND_ENTROPY_THRESHOLD;
- rp->stats.maxentropy = RND_POOLBITS;
-
- KASSERT(RND_ENTROPY_THRESHOLD * 2 <= SHA1_DIGEST_LENGTH);
-}
-
-u_int32_t
-rndpool_get_entropy_count(rndpool_t *rp)
-{
-
- return (rp->stats.curentropy);
-}
-
-void rndpool_get_stats(rndpool_t *rp, void *rsp, int size)
-{
-
- memcpy(rsp, &rp->stats, size);
-}
-
-void
-rndpool_increment_entropy_count(rndpool_t *rp, u_int32_t entropy)
-{
-
- rp->stats.curentropy += entropy;
- rp->stats.added += entropy;
- if (rp->stats.curentropy > RND_POOLBITS) {
- rp->stats.discarded += (rp->stats.curentropy - RND_POOLBITS);
- rp->stats.curentropy = RND_POOLBITS;
- }
-}
-
-u_int32_t *
-rndpool_get_pool(rndpool_t *rp)
-{
-
- return (rp->pool);
-}
-
-u_int32_t
-rndpool_get_poolsize(void)
-{
-
- return (RND_POOLWORDS);
-}
-
-/*
- * The input function treats the contents of the pool as an array of
- * 32 LFSR's of length RND_POOLWORDS, one per bit-plane. The LFSR's
- * are clocked once in parallel, using 32-bit xor operations, for each
- * word to be added.
- *
- * Each word to be added is xor'd with the output word of the LFSR
- * array (one tap at a time).
- *
- * In order to facilitate distribution of entropy between the
- * bit-planes, a 32-bit rotate of this result is performed prior to
- * feedback. The rotation distance is incremented every RND_POOLWORDS
- * clocks, by a value that is relativly prime to the word size to try
- * to spread the bits throughout the pool quickly when the pool is
- * empty.
- *
- * Each LFSR thus takes its feedback from another LFSR, and is
- * effectively re-keyed by both that LFSR and the new data. Feedback
- * occurs with another XOR into the new LFSR, rather than assignment,
- * to avoid destroying any entropy in the destination.
- *
- * Even with zeros as input, the LFSR output data are never visible;
- * the contents of the pool are never divulged except via a hash of
- * the entire pool, so there is no information for correlation
- * attacks. With rotation-based rekeying, each LFSR runs at most a few
- * cycles before being permuted. However, beware of initial
- * conditions when no entropy has been added.
- *
- * The output function also stirs the generated hash back into the
- * pool, further permuting the LFSRs and spreading entropy through the
- * pool. Any unknown bits anywhere in the pool are thus reflected
- * across all the LFSRs after output.
- *
- * (The final XOR assignment into the pool for feedback is equivalent
- * to an additional LFSR tap of the MSB before shifting, in the case
- * where no rotation is done, once every 32 cycles. This LFSR runs for
- * at most one length.)
- */
-static inline void
-rndpool_add_one_word(rndpool_t *rp, u_int32_t val)
-{
- /*
- * Shifting is implemented using a cursor and taps as offsets,
- * added mod the size of the pool. For this reason,
- * RND_POOLWORDS must be a power of two.
- */
- val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
- val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
- val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
- val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
- val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
- if (rp->rotate != 0)
- val = ((val << rp->rotate) | (val >> (32 - rp->rotate)));
- rp->pool[rp->cursor++] ^= val;
-
- /*
- * If we have looped around the pool, increment the rotate
- * variable so the next value will get xored in rotated to
- * a different position.
- */
- if (rp->cursor == RND_POOLWORDS) {
- rp->cursor = 0;
- rp->rotate = (rp->rotate + 7) & 31;
- }
-}
-
-/*
- * Add a buffer's worth of data to the pool.
- */
-void
-rndpool_add_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t entropy)
-{
- u_int32_t val;
- u_int8_t *buf;
-
- buf = p;
-
- for (; len > 3; len -= 4) {
- val = *((u_int32_t *)buf);
-
- rndpool_add_one_word(rp, val);
- buf += 4;
- }
-
- if (len != 0) {
- val = 0;
- switch (len) {
- case 3:
- val = *buf++;
- case 2:
- val = val << 8 | *buf++;
- case 1:
- val = val << 8 | *buf++;
- }
-
- rndpool_add_one_word(rp, val);
- }
-
- rp->stats.curentropy += entropy;
- rp->stats.added += entropy;
-
- if (rp->stats.curentropy > RND_POOLBITS) {
- rp->stats.discarded += (rp->stats.curentropy - RND_POOLBITS);
- rp->stats.curentropy = RND_POOLBITS;
- rnd_full = 1;
- }
-}
-
-/*
- * Extract some number of bytes from the random pool, decreasing the
- * estimate of randomness as each byte is extracted.
- *
- * Do this by hashing the pool and returning a part of the hash as
- * randomness. Stir the hash back into the pool. Note that no
- * secrets going back into the pool are given away here since parts of
- * the hash are xored together before being returned.
- *
- * Honor the request from the caller to only return good data, any data,
- * etc. Note that we must have at least 64 bits of entropy in the pool
- * before we return anything in the high-quality modes.
- */
-u_int32_t
-rndpool_extract_data(rndpool_t *rp, void *p, u_int32_t len, u_int32_t mode)
-{
- u_int i;
- SHA1_CTX hash;
- u_char digest[SHA1_DIGEST_LENGTH];
- u_int32_t remain, deltae, count;
- u_int8_t *buf;
- int good;
-
- buf = p;
- remain = len;
-
- rnd_full = 0;
-
- if (mode == RND_EXTRACT_ANY)
- good = 1;
- else
- good = (rp->stats.curentropy >= (8 * RND_ENTROPY_THRESHOLD));
-
- KASSERT(RND_ENTROPY_THRESHOLD * 2 <= sizeof(digest));
-
- while (good && (remain != 0)) {
- /*
- * While bytes are requested, compute the hash of the pool,
- * and then "fold" the hash in half with XOR, keeping the
- * exact hash value secret, as it will be stirred back into
- * the pool.
- *
- * XXX this approach needs examination by competant
- * cryptographers! It's rather expensive per bit but
- * also involves every bit of the pool in the
- * computation of every output bit..
- */
- SHA1Init(&hash);
- SHA1Update(&hash, (u_int8_t *)rp->pool, RND_POOLWORDS * 4);
- SHA1Final(digest, &hash);
-
- /*
- * Stir the hash back into the pool. This guarantees
- * that the next hash will generate a different value
- * if no new values were added to the pool.
- */
- for (i = 0; i < 5; i++) {
- u_int32_t word;
- memcpy(&word, &digest[i * 4], 4);
- rndpool_add_one_word(rp, word);
- }
-
- count = min(remain, RND_ENTROPY_THRESHOLD);
-
- for (i = 0; i < count; i++)
- buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
-
- buf += count;
- deltae = count * 8;
- remain -= count;
-
- deltae = min(deltae, rp->stats.curentropy);
-
- rp->stats.removed += deltae;
- rp->stats.curentropy -= deltae;
-
- if (rp->stats.curentropy == 0)
- rp->stats.generated += (count * 8) - deltae;
-
- if (mode == RND_EXTRACT_GOOD)
- good = (rp->stats.curentropy >=
- (8 * RND_ENTROPY_THRESHOLD));
- }
-
- memset(&hash, 0, sizeof(hash));
- memset(digest, 0, sizeof(digest));
-
- return (len - remain);
-}