"Fossies" - the Fresh Open Source Software Archive

Member "openbgpd-6.5p0/compat/arc4random.c" (25 Apr 2019, 4656 Bytes) of package /linux/privat/openbgpd-6.5p0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*  $OpenBSD: arc4random.c,v 1.55 2019/03/24 17:56:54 deraadt Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1996, David Mazieres <dm@uun.org>
    5  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
    6  * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
    7  * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
    8  *
    9  * Permission to use, copy, modify, and distribute this software for any
   10  * purpose with or without fee is hereby granted, provided that the above
   11  * copyright notice and this permission notice appear in all copies.
   12  *
   13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   20  */
   21 
   22 /*
   23  * ChaCha based random number generator for OpenBSD.
   24  */
   25 
   26 #include <fcntl.h>
   27 #include <limits.h>
   28 #include <signal.h>
   29 #include <stdint.h>
   30 #include <stdlib.h>
   31 #include <string.h>
   32 #include <unistd.h>
   33 #include <sys/types.h>
   34 #include <sys/time.h>
   35 
   36 #define KEYSTREAM_ONLY
   37 #include "chacha_private.h"
   38 
   39 #define minimum(a, b) ((a) < (b) ? (a) : (b))
   40 
   41 #if defined(__GNUC__) || defined(_MSC_VER)
   42 #define inline __inline
   43 #else               /* __GNUC__ || _MSC_VER */
   44 #define inline
   45 #endif              /* !__GNUC__ && !_MSC_VER */
   46 
   47 #define KEYSZ   32
   48 #define IVSZ    8
   49 #define BLOCKSZ 64
   50 #define RSBUFSZ (16*BLOCKSZ)
   51 
   52 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
   53 static struct _rs {
   54     size_t      rs_have;    /* valid bytes at end of rs_buf */
   55     size_t      rs_count;   /* bytes till reseed */
   56 } *rs;
   57 
   58 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
   59 static struct _rsx {
   60     chacha_ctx  rs_chacha;  /* chacha context for random keystream */
   61     u_char      rs_buf[RSBUFSZ];    /* keystream blocks */
   62 } *rsx;
   63 
   64 static inline int _rs_allocate(struct _rs **, struct _rsx **);
   65 static inline void _rs_forkdetect(void);
   66 #include "arc4random.h"
   67 
   68 static inline void _rs_rekey(u_char *dat, size_t datlen);
   69 
   70 static inline void
   71 _rs_init(u_char *buf, size_t n)
   72 {
   73     if (n < KEYSZ + IVSZ)
   74         return;
   75 
   76     if (rs == NULL) {
   77         if (_rs_allocate(&rs, &rsx) == -1)
   78             _exit(1);
   79     }
   80 
   81     chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
   82     chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
   83 }
   84 
   85 static void
   86 _rs_stir(void)
   87 {
   88     u_char rnd[KEYSZ + IVSZ];
   89 
   90     if (getentropy(rnd, sizeof rnd) == -1)
   91         _getentropy_fail();
   92 
   93     if (!rs)
   94         _rs_init(rnd, sizeof(rnd));
   95     else
   96         _rs_rekey(rnd, sizeof(rnd));
   97     explicit_bzero(rnd, sizeof(rnd));   /* discard source seed */
   98 
   99     /* invalidate rs_buf */
  100     rs->rs_have = 0;
  101     memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
  102 
  103     rs->rs_count = 1600000;
  104 }
  105 
  106 static inline void
  107 _rs_stir_if_needed(size_t len)
  108 {
  109     _rs_forkdetect();
  110     if (!rs || rs->rs_count <= len)
  111         _rs_stir();
  112     if (rs->rs_count <= len)
  113         rs->rs_count = 0;
  114     else
  115         rs->rs_count -= len;
  116 }
  117 
  118 static inline void
  119 _rs_rekey(u_char *dat, size_t datlen)
  120 {
  121 #ifndef KEYSTREAM_ONLY
  122     memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
  123 #endif
  124     /* fill rs_buf with the keystream */
  125     chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
  126         rsx->rs_buf, sizeof(rsx->rs_buf));
  127     /* mix in optional user provided data */
  128     if (dat) {
  129         size_t i, m;
  130 
  131         m = minimum(datlen, KEYSZ + IVSZ);
  132         for (i = 0; i < m; i++)
  133             rsx->rs_buf[i] ^= dat[i];
  134     }
  135     /* immediately reinit for backtracking resistance */
  136     _rs_init(rsx->rs_buf, KEYSZ + IVSZ);
  137     memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
  138     rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
  139 }
  140 
  141 static inline void
  142 _rs_random_buf(void *_buf, size_t n)
  143 {
  144     u_char *buf = (u_char *)_buf;
  145     u_char *keystream;
  146     size_t m;
  147 
  148     _rs_stir_if_needed(n);
  149     while (n > 0) {
  150         if (rs->rs_have > 0) {
  151             m = minimum(n, rs->rs_have);
  152             keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
  153                 - rs->rs_have;
  154             memcpy(buf, keystream, m);
  155             memset(keystream, 0, m);
  156             buf += m;
  157             n -= m;
  158             rs->rs_have -= m;
  159         }
  160         if (rs->rs_have == 0)
  161             _rs_rekey(NULL, 0);
  162     }
  163 }
  164 
  165 static inline void
  166 _rs_random_u32(uint32_t *val)
  167 {
  168     u_char *keystream;
  169 
  170     _rs_stir_if_needed(sizeof(*val));
  171     if (rs->rs_have < sizeof(*val))
  172         _rs_rekey(NULL, 0);
  173     keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
  174     memcpy(val, keystream, sizeof(*val));
  175     memset(keystream, 0, sizeof(*val));
  176     rs->rs_have -= sizeof(*val);
  177 }
  178 
  179 uint32_t
  180 arc4random(void)
  181 {
  182     uint32_t val;
  183 
  184     _ARC4_LOCK();
  185     _rs_random_u32(&val);
  186     _ARC4_UNLOCK();
  187     return val;
  188 }
  189 
  190 void
  191 arc4random_buf(void *buf, size_t n)
  192 {
  193     _ARC4_LOCK();
  194     _rs_random_buf(buf, n);
  195     _ARC4_UNLOCK();
  196 }