"Fossies" - the Fresh Open Source Software Archive

Member "dhcpcd-9.4.1/compat/arc4random.c" (22 Oct 2021, 4036 Bytes) of package /linux/misc/dhcpcd-9.4.1.tar.xz:


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 /*
    2  * Arc4 random number generator for OpenBSD.
    3  * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
    4  *
    5  * Modification and redistribution in source and binary forms is
    6  * permitted provided that due credit is given to the author and the
    7  * OpenBSD project by leaving this copyright notice intact.
    8  */
    9 
   10 /*
   11  * This code is derived from section 17.1 of Applied Cryptography,
   12  * second edition, which describes a stream cipher allegedly
   13  * compatible with RSA Labs "RC4" cipher (the actual description of
   14  * which is a trade secret).  The same algorithm is used as a stream
   15  * cipher called "arcfour" in Tatu Ylonen's ssh package.
   16  *
   17  * Here the stream cipher has been modified always to include the time
   18  * when initializing the state.  That makes it impossible to
   19  * regenerate the same random sequence twice, so this can't be used
   20  * for encryption, but will generate good random numbers.
   21  *
   22  * RC4 is a registered trademark of RSA Laboratories.
   23  */
   24 
   25 #include <sys/time.h>
   26 
   27 #include <fcntl.h>
   28 #include <stdint.h>
   29 #include <stdlib.h>
   30 #include <unistd.h>
   31 
   32 #include "arc4random.h"
   33 
   34 struct arc4_stream {
   35     uint8_t i;
   36     uint8_t j;
   37     uint8_t s[256];
   38     size_t count;
   39     pid_t stir_pid;
   40     int fd;
   41 };
   42 
   43 #define S(n) (n)
   44 #define S4(n) S(n), S(n + 1), S(n + 2), S(n + 3)
   45 #define S16(n) S4(n), S4(n + 4), S4(n + 8), S4(n + 12)
   46 #define S64(n) S16(n), S16(n + 16), S16(n + 32), S16(n + 48)
   47 #define S256 S64(0), S64(64), S64(128), S64(192)
   48 
   49 static struct arc4_stream rs = { .i = 0xff, .j = 0, .s = { S256 },
   50                     .count = 0, .stir_pid = 0, .fd = -1 };
   51 
   52 #undef S
   53 #undef S4
   54 #undef S16
   55 #undef S64
   56 #undef S256
   57 
   58 static void
   59 arc4_addrandom(struct arc4_stream *as, unsigned char *dat, int datlen)
   60 {
   61     int n;
   62     uint8_t si;
   63 
   64     as->i--;
   65     for (n = 0; n < 256; n++) {
   66         as->i = (uint8_t)(as->i + 1);
   67         si = as->s[as->i];
   68         as->j = (uint8_t)(as->j + si + dat[n % datlen]);
   69         as->s[as->i] = as->s[as->j];
   70         as->s[as->j] = si;
   71     }
   72     as->j = as->i;
   73 }
   74 
   75 static uint8_t
   76 arc4_getbyte(struct arc4_stream *as)
   77 {
   78     uint8_t si, sj;
   79 
   80     as->i = (uint8_t)(as->i + 1);
   81     si = as->s[as->i];
   82     as->j = (uint8_t)(as->j + si);
   83     sj = as->s[as->j];
   84     as->s[as->i] = sj;
   85     as->s[as->j] = si;
   86     return (as->s[(si + sj) & 0xff]);
   87 }
   88 
   89 static uint32_t
   90 arc4_getword(struct arc4_stream *as)
   91 {
   92     int val;
   93 
   94     val = (int)((unsigned int)arc4_getbyte(as) << 24);
   95     val |= arc4_getbyte(as) << 16;
   96     val |= arc4_getbyte(as) << 8;
   97     val |= arc4_getbyte(as);
   98     return (uint32_t)val;
   99 }
  100 
  101 /* We don't care about any error on read, just use what we have
  102  * on the stack. So mask off this GCC warning. */
  103 #pragma GCC diagnostic ignored "-Wunused-result"
  104 static void
  105 arc4_stir(struct arc4_stream *as)
  106 {
  107     struct {
  108         struct timeval tv;
  109         unsigned int rnd[(128 - sizeof(struct timeval)) /
  110             sizeof(unsigned int)];
  111     }       rdat;
  112     size_t n;
  113 
  114     gettimeofday(&rdat.tv, NULL);
  115     if (as->fd == -1) {
  116 #ifndef O_CLOEXEC
  117         int fd_opts;
  118 #endif
  119 
  120         as->fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK
  121 #ifdef O_CLOEXEC
  122         | O_CLOEXEC
  123 #endif
  124         );
  125 #ifndef O_CLOEXEC
  126         if (as->fd != -1 &&
  127             (fd_opts = fcntl(as->fd, F_GETFD)))
  128             fcntl(as->fd, F_SETFD, fd_opts | FD_CLOEXEC);
  129 #endif
  130     }
  131 
  132     if (as->fd != -1) {
  133         /* If there is an error reading, just use what is
  134          * on the stack. */
  135         /* coverity[check_return] */
  136         (void)read(as->fd, rdat.rnd, sizeof(rdat.rnd));
  137     }
  138 
  139     /* fd < 0?  Ah, what the heck. We'll just take
  140      * whatever was on the stack... */
  141     /* coverity[uninit_use_in_call] */
  142     arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
  143 
  144     /*
  145      * Throw away the first N words of output, as suggested in the
  146      * paper "Weaknesses in the Key Scheduling Algorithm of RC4"
  147      * by Fluher, Mantin, and Shamir.  (N = 256 in our case.)
  148      */
  149     for (n = 0; n < 256 * sizeof(uint32_t); n++)
  150         arc4_getbyte(as);
  151     as->count = 1600000;
  152 }
  153 
  154 static void
  155 arc4_stir_if_needed(struct arc4_stream *as)
  156 {
  157     pid_t pid;
  158 
  159     pid = getpid();
  160     if (as->count <= sizeof(uint32_t) || as->stir_pid != pid) {
  161         as->stir_pid = pid;
  162         arc4_stir(as);
  163     } else
  164         as->count -= sizeof(uint32_t);
  165 }
  166 
  167 uint32_t
  168 arc4random()
  169 {
  170 
  171     arc4_stir_if_needed(&rs);
  172     return arc4_getword(&rs);
  173 }