/* $NetBSD$ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Taylor R. Campbell. * * 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 __KERNEL_RCSID(0, "$NetBSD$"); #include #include #include #include /* * entpool_enter: Enter len bytes of data from buf into the entropy * pool ep, permuting the state as necessary when the internal buffer * fills up. */ void entpool_enter(struct entpool *ep, const void *buf, size_t len) { const uint8_t *p = buf; size_t n = len; /* If we don't have any room, stir. */ if (ep->ep_inleft == 0) entpool_stir(ep); /* Enter the data. */ while (0 < n) { /* Provide framing for the sample. */ KASSERT(0 < ep->ep_inleft); CTASSERT(ENTPOOL_INRATE_BYTES < 0x100); KASSERT(ep->ep_inleft <= ENTPOOL_INRATE_BYTES); --ep->ep_inleft; ep->ep_state.u8[rate - ep->ep_inleft] ^= MIN(n, ep->ep_inleft) + 1; /* Don't let anyone see output now without stirring first. */ ep->ep_outleft = 0; /* Enter as many bytes as we can into the buffer. */ while (0 < MIN(n, ep->ep_nleft)) { ep->ep_state.u8[rate - --ep->ep_inleft] ^= *p++; n--; } /* If we filled the buffer, stir now. */ if (ep->ep_nleft == 0) entpool_stir(ep); } } /* * entpool_enter_nostir: Enter up to len bytes from buf into the * entropy pool without stirring it. Return the number of bytes * actually used. * * Stirring takes about 2300 cycles on Intel Ivy Bridge, which is a bit * much for an interrupt handler. */ size_t entpool_enter_nostir(struct entpool *ep, const void *buf, size_t len) { const uint8_t *p = buf; size_t n = len; if (ep->ep_inleft == 0) return 0; /* Provide framing for the sample. */ CTASSERT(ENTPOOL_INRATE_BYTES < 0x100); KASSERT(ep->ep_inleft <= ENTPOOL_INRATE_BYTES); --ep->ep_inleft; ep->ep_state.u8[rate - ep->ep_inleft] ^= MIN(n, ep->ep_inleft) + 1; /* Don't let anyone see output now without stirring first. */ ep->ep_outleft = 0; /* Xor as much of the sample into the state as we can. */ while (0 < MIN(n, ep->ep_inleft)) { ep->ep_state.u8[rate - --ep->ep_inleft] ^= *p++; n--; } /* n is number of bytes left; return number of bytes used. */ return len - n; } /* * entpool_stir: Permute the Keccak state and mark the input buffer * empty and the output buffer full. Since keccakf1600 is a * permutation, applying it never loses information. */ void entpool_stir(struct entpool *ep) { keccakf1600(ep->ep_state.u64); ep->ep_inleft = ENTPOOL_INRATE_BYTES; ep->ep_outleft = ENTPOOL_OUTRATE_BYTES; } /* * entpool_extract: Extract len bytes of data into buf from the entropy * pool ep, permuting the state as necessary when the internal buffer * empties, and permuting after filling buf. */ void entpool_extract(struct entpool *ep, void *buf, size_t len) { const unsigned rate = ENTPOOL_OUTRATE_BYTES; uint8_t *p = buf; size_t n = len; KASSERT(len <= ENTPOOL_OUTRATE_BYTES); KASSERT(ep->ep_outleft <= ENTPOOL_OUTRATE_BYTES); /* Extract byte by byte, stirring if we run out. */ while (0 < n) { if (ep->ep_outleft == 0) entpool_stir(ep); *p++ = ep->ep_state.u8[rate - --ep->ep_outleft]; n--; } /* * Stir once more for key erasure / forward secrecy / * backtracking resistance. */ entpool_stir(ep); }