The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/random/fenestrasX/fx_rng.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/fail.h>
   33 #include <sys/limits.h>
   34 #include <sys/lock.h>
   35 #include <sys/kernel.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mutex.h>
   38 #include <sys/random.h>
   39 #include <sys/sdt.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/systm.h>
   42 
   43 #include <machine/cpu.h>
   44 #include <machine/stdarg.h>
   45 
   46 #define CHACHA_EMBED
   47 #define KEYSTREAM_ONLY
   48 #define CHACHA_NONCE0_CTR128
   49 #include <crypto/chacha20/chacha.h>
   50 #include <crypto/rijndael/rijndael-api-fst.h>
   51 #include <crypto/sha2/sha256.h>
   52 
   53 #include <dev/random/hash.h>
   54 #include <dev/random/randomdev.h>
   55 #include <dev/random/random_harvestq.h>
   56 #include <dev/random/uint128.h>
   57 
   58 #include <dev/random/fenestrasX/fx_hash.h>
   59 #include <dev/random/fenestrasX/fx_priv.h>
   60 #include <dev/random/fenestrasX/fx_rng.h>
   61 
   62 _Static_assert(FX_CHACHA20_KEYSIZE == RANDOM_KEYSIZE, "");
   63 
   64 #include <crypto/chacha20/chacha.c>
   65 
   66 static void
   67 fxrng_rng_keystream_internal(struct chacha_ctx *prf, void *buf, size_t nbytes)
   68 {
   69         size_t chunklen;
   70 
   71         while (nbytes > 0) {
   72                 chunklen = MIN(nbytes,
   73                     rounddown((size_t)UINT32_MAX, CHACHA_BLOCKLEN));
   74 
   75                 chacha_encrypt_bytes(prf, NULL, buf, chunklen);
   76                 buf = (uint8_t *)buf + chunklen;
   77                 nbytes -= chunklen;
   78         }
   79 }
   80 
   81 /*
   82  * This subroutine pulls the counter out of Chacha, which for whatever reason
   83  * always encodes and decodes counters in a little endian format, and adds
   84  * 'addend' to it, saving the result in Chacha.
   85  */
   86 static void
   87 fxrng_chacha_nonce_add64(struct chacha_ctx *ctx, uint64_t addend)
   88 {
   89         uint128_t ctr;  /* Native-endian. */
   90 #if BYTE_ORDER == BIG_ENDIAN
   91         uint128_t lectr;
   92 
   93         chacha_ctrsave(ctx, (void *)&lectr);
   94         ctr = le128dec(&lectr);
   95 #else
   96         chacha_ctrsave(ctx, (void *)&ctr);
   97 #endif
   98 
   99         uint128_add64(&ctr, addend);
  100 
  101         /* chacha_ivsetup() does not modify the key, and we rely on that. */
  102 #if BYTE_ORDER == BIG_ENDIAN
  103         le128enc(&lectr, ctr);
  104         chacha_ivsetup(ctx, NULL, (const void *)&lectr);
  105         explicit_bzero(&lectr, sizeof(lectr));
  106 #else
  107         chacha_ivsetup(ctx, NULL, (const void *)&ctr);
  108 #endif
  109         explicit_bzero(&ctr, sizeof(ctr));
  110 }
  111 
  112 /*
  113  * Generate from the unbuffered source PRNG.
  114  *
  115  * Handles fast key erasure (rekeys the PRF with a generated key under lock).
  116  *
  117  * RNG lock is required on entry.  If return_unlocked is true, RNG lock will
  118  * be dropped on return.
  119  */
  120 void
  121 fxrng_rng_genrandom_internal(struct fxrng_basic_rng *rng, void *buf,
  122     size_t nbytes, bool return_unlocked)
  123 {
  124         struct chacha_ctx ctx_copy, *p_ctx;
  125         uint8_t newkey[FX_CHACHA20_KEYSIZE];
  126         size_t blockcount;
  127 
  128         FXRNG_RNG_ASSERT(rng);
  129 
  130         /* Save off the initial output of the generator for rekeying. */
  131         fxrng_rng_keystream_internal(&rng->rng_prf, newkey, sizeof(newkey));
  132 
  133         if (return_unlocked) {
  134                 memcpy(&ctx_copy, &rng->rng_prf, sizeof(ctx_copy));
  135                 p_ctx = &ctx_copy;
  136 
  137                 /*
  138                  * Forward the Chacha counter state over the blocks we promise
  139                  * to generate for the caller without the lock.
  140                  */
  141                 blockcount = howmany(nbytes, CHACHA_BLOCKLEN);
  142                 fxrng_chacha_nonce_add64(&rng->rng_prf, blockcount);
  143 
  144                 /* Re-key before dropping the lock. */
  145                 chacha_keysetup(&rng->rng_prf, newkey, sizeof(newkey) * 8);
  146                 explicit_bzero(newkey, sizeof(newkey));
  147 
  148                 FXRNG_RNG_UNLOCK(rng);
  149         } else {
  150                 p_ctx = &rng->rng_prf;
  151         }
  152 
  153         fxrng_rng_keystream_internal(p_ctx, buf, nbytes);
  154 
  155         if (return_unlocked) {
  156                 explicit_bzero(&ctx_copy, sizeof(ctx_copy));
  157                 FXRNG_RNG_ASSERT_NOT(rng);
  158         } else {
  159                 /* Re-key before exit. */
  160                 chacha_keysetup(&rng->rng_prf, newkey, sizeof(newkey) * 8);
  161                 explicit_bzero(newkey, sizeof(newkey));
  162                 FXRNG_RNG_ASSERT(rng);
  163         }
  164 }
  165 
  166 /*
  167  * Helper to reseed the root RNG, incorporating the existing RNG state.
  168  *
  169  * The root RNG is locked on entry and locked on return.
  170  */
  171 static void
  172 fxrng_rng_reseed_internal(struct fxrng_basic_rng *rng, bool seeded,
  173     const void *src, size_t sz, ...)
  174 {
  175         union {
  176                 uint8_t root_state[FX_CHACHA20_KEYSIZE];
  177                 uint8_t hash_out[FXRNG_HASH_SZ];
  178         } u;
  179         struct fxrng_hash mix;
  180         va_list ap;
  181 
  182         _Static_assert(FX_CHACHA20_KEYSIZE <= FXRNG_HASH_SZ, "");
  183 
  184         FXRNG_RNG_ASSERT(rng);
  185 
  186         fxrng_hash_init(&mix);
  187         if (seeded) {
  188                 fxrng_rng_keystream_internal(&rng->rng_prf, u.root_state,
  189                     sizeof(u.root_state));
  190                 fxrng_hash_update(&mix, u.root_state, sizeof(u.root_state));
  191         }
  192         fxrng_hash_update(&mix, src, sz);
  193 
  194         va_start(ap, sz);
  195         while (true) {
  196                 src = va_arg(ap, const void *);
  197                 if (src == NULL)
  198                         break;
  199                 sz = va_arg(ap, size_t);
  200                 fxrng_hash_update(&mix, src, sz);
  201         }
  202         va_end(ap);
  203 
  204         fxrng_hash_finish(&mix, u.hash_out, sizeof(u.hash_out));
  205 
  206         /*
  207          * Take the first keysize (32) bytes of our digest (64 bytes).  It is
  208          * also possible to just have Blake2 emit fewer bytes, but our wrapper
  209          * API doesn't provide that functionality and there isn't anything
  210          * obviously wrong with emitting more hash bytes.
  211          *
  212          * keysetup does not reset the embedded counter, and we rely on that
  213          * property.
  214          */
  215         chacha_keysetup(&rng->rng_prf, u.hash_out, FX_CHACHA20_KEYSIZE * 8);
  216 
  217         /* 'mix' zeroed by fxrng_hash_finish(). */
  218         explicit_bzero(u.hash_out, sizeof(u.hash_out));
  219 
  220         FXRNG_RNG_ASSERT(rng);
  221 }
  222 
  223 /*
  224  * Directly reseed the root RNG from a first-time entropy source,
  225  * incorporating the existing RNG state, called by fxrng_brng_src_reseed.
  226  *
  227  * The root RNG is locked on entry and locked on return.
  228  */
  229 void
  230 fxrng_rng_src_reseed(struct fxrng_basic_rng *rng,
  231     const struct harvest_event *event)
  232 {
  233         fxrng_rng_reseed_internal(rng, true, &event->he_somecounter,
  234             sizeof(event->he_somecounter), (const void *)event->he_entropy,
  235             (size_t)event->he_size, NULL);
  236 }
  237 
  238 /*
  239  * Reseed the root RNG from pooled entropy, incorporating the existing RNG
  240  * state, called by fxrng_brng_reseed.
  241  *
  242  * The root RNG is locked on entry and locked on return.
  243  */
  244 void
  245 fxrng_rng_reseed(struct fxrng_basic_rng *rng, bool seeded, const void *entr,
  246     size_t sz)
  247 {
  248         fxrng_rng_reseed_internal(rng, seeded, entr, sz, NULL);
  249 }

Cache object: f77d90e310da30b487a519b5ab0b83fb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.