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/drivers/random/random.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 random.c
    3 
    4 Random number generator.
    5 
    6 The random number generator collects data from the kernel and compressed
    7 that data into a seed for a psuedo random number generator.
    8 */
    9 
   10 #include "../drivers.h"
   11 #include "../../kernel/const.h"
   12 #include "assert.h"
   13 
   14 #include "random.h"
   15 #include "sha2.h"
   16 #include "aes/rijndael.h"
   17 
   18 #define N_DERIV 16
   19 #define NR_POOLS 32
   20 #define MIN_SAMPLES     256     /* Number of samples needed in pool 0 for a
   21                                  * re-seed.
   22                                  */
   23 
   24 PRIVATE unsigned long deriv[RANDOM_SOURCES][N_DERIV];
   25 PRIVATE int pool_ind[RANDOM_SOURCES];
   26 PRIVATE SHA256_CTX pool_ctx[NR_POOLS];
   27 PRIVATE unsigned samples= 0;
   28 PRIVATE int got_seeded= 0;
   29 PRIVATE u8_t random_key[2*AES_BLOCKSIZE];
   30 PRIVATE u32_t count_lo, count_hi;
   31 PRIVATE u32_t reseed_count;
   32 
   33 FORWARD _PROTOTYPE( void add_sample, (int source, unsigned long sample) );
   34 FORWARD _PROTOTYPE( void data_block, (rd_keyinstance *keyp,
   35                                                         void *data)     );
   36 FORWARD _PROTOTYPE( void reseed, (void)                                 );
   37 
   38 PUBLIC void random_init()
   39 {
   40         int i, j;
   41 
   42         assert(&deriv[RANDOM_SOURCES-1][N_DERIV-1] ==
   43                 &deriv[0][0] + RANDOM_SOURCES*N_DERIV -1);
   44 
   45         for (i= 0; i<RANDOM_SOURCES; i++)
   46         {
   47                 for (j= 0; j<N_DERIV; j++)
   48                         deriv[i][j]= 0;
   49                 pool_ind[i]= 0;
   50         }
   51         for (i= 0; i<NR_POOLS; i++)
   52                 SHA256_Init(&pool_ctx[i]);
   53         count_lo= 0;
   54         count_hi= 0;
   55         reseed_count= 0;
   56 }
   57 
   58 PUBLIC int random_isseeded()
   59 {
   60         if (got_seeded)
   61                 return 1;
   62         return 0;
   63 }
   64 
   65 PUBLIC void random_update(source, buf, count)
   66 int source;
   67 unsigned short *buf;
   68 int count;
   69 {
   70         int i;
   71 
   72 #if 0
   73         printf("random_update: got %d samples for source %d\n", count, source);
   74 #endif
   75         if (source < 0 || source >= RANDOM_SOURCES)
   76                 panic("memory", "random_update: bad source", source);
   77         for (i= 0; i<count; i++)
   78                 add_sample(source, buf[i]);
   79         reseed();
   80 }
   81 
   82 PUBLIC void random_getbytes(buf, size)
   83 void *buf;
   84 size_t size;
   85 {
   86         int n, r;
   87         u8_t *cp;
   88         rd_keyinstance key;
   89         u8_t output[AES_BLOCKSIZE];
   90 
   91         r= rijndael_makekey(&key, sizeof(random_key), random_key);
   92         assert(r == 0);
   93 
   94         cp= buf;
   95         while (size > 0)
   96         {
   97                 n= AES_BLOCKSIZE;
   98                 if (n > size)
   99                 {
  100                         n= size;
  101                         data_block(&key, output);
  102                         memcpy(cp, output, n);
  103                 }
  104                 else
  105                         data_block(&key, cp);
  106                 cp += n;
  107                 size -= n;
  108         }
  109 
  110         /* Generate new key */
  111         assert(sizeof(random_key) == 2*AES_BLOCKSIZE);
  112         data_block(&key, random_key);
  113         data_block(&key, random_key+AES_BLOCKSIZE);
  114 }
  115 
  116 PUBLIC void random_putbytes(buf, size)
  117 void *buf;
  118 size_t size;
  119 {
  120         /* Add bits to pool zero */
  121         SHA256_Update(&pool_ctx[0], buf, size);
  122 
  123         /* Assume that these bits are truely random. Increment samples
  124          * with the number of bits.
  125          */
  126         samples += size*8;
  127 
  128         reseed();
  129 }
  130 
  131 PRIVATE void add_sample(source, sample)
  132 int source;
  133 unsigned long sample;
  134 {
  135         int i, pool_nr;
  136         unsigned long d, v, di, min;
  137 
  138         /* Delete bad sample. Compute the Nth derivative. Delete the sample
  139          * if any derivative is too small.
  140          */
  141         min= (unsigned long)-1;
  142         v= sample;
  143         for (i= 0; i<N_DERIV; i++)
  144         {
  145                 di= deriv[source][i];
  146 
  147                 /* Compute the difference */
  148                 if (v >= di)
  149                         d= v-di;
  150                 else
  151                         d= di-v;
  152                 deriv[source][i]= v;
  153                 v= d;
  154                 if (v <min)
  155                         min= v;
  156         }
  157         if (min < 2)
  158         {
  159 #if 0
  160                 printf("ignoring sample '%u' from source %d\n",
  161                         sample, source);
  162 #endif
  163                 return;
  164         }
  165 #if 0
  166         printf("accepting sample '%u' from source %d\n", sample, source);
  167 #endif
  168 
  169         pool_nr= pool_ind[source];
  170         assert(pool_nr >= 0 && pool_nr < NR_POOLS);
  171 
  172         SHA256_Update(&pool_ctx[pool_nr], (unsigned char *)&sample,
  173                 sizeof(sample));
  174         if (pool_nr == 0)
  175                 samples++;
  176         pool_nr++;
  177         if (pool_nr >= NR_POOLS)
  178                 pool_nr= 0;
  179         pool_ind[source]= pool_nr;
  180 }
  181 
  182 PRIVATE void data_block(keyp, data)
  183 rd_keyinstance *keyp;
  184 void *data;
  185 {
  186         int r;
  187         u8_t input[AES_BLOCKSIZE];
  188 
  189         memset(input, '\0', sizeof(input));
  190 
  191         /* Do we want the output of the random numbers to be portable 
  192          * across platforms (for example for RSA signatures)? At the moment
  193          * we don't do anything special. Encrypt the counter with the AES
  194          * key.
  195          */
  196         assert(sizeof(count_lo)+sizeof(count_hi) <= AES_BLOCKSIZE);
  197         memcpy(input, &count_lo, sizeof(count_lo));
  198         memcpy(input+sizeof(count_lo), &count_hi, sizeof(count_hi));
  199         r= rijndael_ecb_encrypt(keyp, input, data, AES_BLOCKSIZE, NULL);
  200         assert(r == AES_BLOCKSIZE);
  201 
  202         count_lo++;
  203         if (count_lo == 0)
  204                 count_hi++;
  205 }
  206 
  207 PRIVATE void reseed()
  208 {
  209         int i;
  210         SHA256_CTX ctx;
  211         u8_t digest[SHA256_DIGEST_LENGTH];
  212 
  213         if (samples < MIN_SAMPLES)
  214                 return;
  215 
  216         reseed_count++;
  217         SHA256_Init(&ctx);
  218         if (got_seeded)
  219                 SHA256_Update(&ctx, random_key, sizeof(random_key));
  220         SHA256_Final(digest, &pool_ctx[0]);
  221         SHA256_Update(&ctx, digest, sizeof(digest));
  222         SHA256_Init(&pool_ctx[0]);
  223         for (i= 1; i<NR_POOLS; i++)
  224         {
  225                 if ((reseed_count & (1UL << (i-1))) != 0)
  226                         break;
  227                 SHA256_Final(digest, &pool_ctx[i]);
  228                 SHA256_Update(&ctx, digest, sizeof(digest));
  229                 SHA256_Init(&pool_ctx[i]);
  230         }
  231         SHA256_Final(digest, &ctx);
  232         assert(sizeof(random_key) == sizeof(digest));
  233         memcpy(random_key, &digest, sizeof(random_key));
  234         samples= 0;
  235 
  236         got_seeded= 1;
  237 }
  238 

Cache object: 0a95c05b261d3d663379a765773d79a1


[ 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.