"Fossies" - the Fresh Open Source Software Archive

Member "sudo-1.9.11p3/lib/util/arc4random.c" (12 Jun 2022, 4784 Bytes) of package /linux/misc/sudo-1.9.11p3.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. For more information about "arc4random.c" see the Fossies "Dox" file reference documentation.

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