00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "../drivers.h"
00011 #include "../../kernel/const.h"
00012 #include "assert.h"
00013
00014 #include "random.h"
00015 #include "sha2.h"
00016 #include "aes/rijndael.h"
00017
00018 #define N_DERIV 16
00019 #define NR_POOLS 32
00020 #define MIN_SAMPLES 256
00021
00022
00023
00024 PRIVATE unsigned long deriv[RANDOM_SOURCES][N_DERIV];
00025 PRIVATE int pool_ind[RANDOM_SOURCES];
00026 PRIVATE SHA256_CTX pool_ctx[NR_POOLS];
00027 PRIVATE unsigned samples= 0;
00028 PRIVATE int got_seeded= 0;
00029 PRIVATE u8_t random_key[2*AES_BLOCKSIZE];
00030 PRIVATE u32_t count_lo, count_hi;
00031 PRIVATE u32_t reseed_count;
00032
00033 FORWARD _PROTOTYPE( void add_sample, (int source, unsigned long sample) );
00034 FORWARD _PROTOTYPE( void data_block, (rd_keyinstance *keyp,
00035 void *data) );
00036 FORWARD _PROTOTYPE( void reseed, (void) );
00037
00038 PUBLIC void random_init()
00039 {
00040 int i, j;
00041
00042 assert(&deriv[RANDOM_SOURCES-1][N_DERIV-1] ==
00043 &deriv[0][0] + RANDOM_SOURCES*N_DERIV -1);
00044
00045 for (i= 0; i<RANDOM_SOURCES; i++)
00046 {
00047 for (j= 0; j<N_DERIV; j++)
00048 deriv[i][j]= 0;
00049 pool_ind[i]= 0;
00050 }
00051 for (i= 0; i<NR_POOLS; i++)
00052 SHA256_Init(&pool_ctx[i]);
00053 count_lo= 0;
00054 count_hi= 0;
00055 reseed_count= 0;
00056 }
00057
00058 PUBLIC int random_isseeded()
00059 {
00060 if (got_seeded)
00061 return 1;
00062 return 0;
00063 }
00064
00065 PUBLIC void random_update(source, buf, count)
00066 int source;
00067 unsigned short *buf;
00068 int count;
00069 {
00070 int i;
00071
00072 #if 0
00073 printf("random_update: got %d samples for source %d\n", count, source);
00074 #endif
00075 if (source < 0 || source >= RANDOM_SOURCES)
00076 panic("memory", "random_update: bad source", source);
00077 for (i= 0; i<count; i++)
00078 add_sample(source, buf[i]);
00079 reseed();
00080 }
00081
00082 PUBLIC void random_getbytes(buf, size)
00083 void *buf;
00084 size_t size;
00085 {
00086 int n, r;
00087 u8_t *cp;
00088 rd_keyinstance key;
00089 u8_t output[AES_BLOCKSIZE];
00090
00091 r= rijndael_makekey(&key, sizeof(random_key), random_key);
00092 assert(r == 0);
00093
00094 cp= buf;
00095 while (size > 0)
00096 {
00097 n= AES_BLOCKSIZE;
00098 if (n > size)
00099 {
00100 n= size;
00101 data_block(&key, output);
00102 memcpy(cp, output, n);
00103 }
00104 else
00105 data_block(&key, cp);
00106 cp += n;
00107 size -= n;
00108 }
00109
00110
00111 assert(sizeof(random_key) == 2*AES_BLOCKSIZE);
00112 data_block(&key, random_key);
00113 data_block(&key, random_key+AES_BLOCKSIZE);
00114 }
00115
00116 PUBLIC void random_putbytes(buf, size)
00117 void *buf;
00118 size_t size;
00119 {
00120
00121 SHA256_Update(&pool_ctx[0], buf, size);
00122
00123
00124
00125
00126 samples += size*8;
00127
00128 reseed();
00129 }
00130
00131 PRIVATE void add_sample(source, sample)
00132 int source;
00133 unsigned long sample;
00134 {
00135 int i, pool_nr;
00136 unsigned long d, v, di, min;
00137
00138
00139
00140
00141 min= (unsigned long)-1;
00142 v= sample;
00143 for (i= 0; i<N_DERIV; i++)
00144 {
00145 di= deriv[source][i];
00146
00147
00148 if (v >= di)
00149 d= v-di;
00150 else
00151 d= di-v;
00152 deriv[source][i]= v;
00153 v= d;
00154 if (v <min)
00155 min= v;
00156 }
00157 if (min < 2)
00158 {
00159 #if 0
00160 printf("ignoring sample '%u' from source %d\n",
00161 sample, source);
00162 #endif
00163 return;
00164 }
00165 #if 0
00166 printf("accepting sample '%u' from source %d\n", sample, source);
00167 #endif
00168
00169 pool_nr= pool_ind[source];
00170 assert(pool_nr >= 0 && pool_nr < NR_POOLS);
00171
00172 SHA256_Update(&pool_ctx[pool_nr], (unsigned char *)&sample,
00173 sizeof(sample));
00174 if (pool_nr == 0)
00175 samples++;
00176 pool_nr++;
00177 if (pool_nr >= NR_POOLS)
00178 pool_nr= 0;
00179 pool_ind[source]= pool_nr;
00180 }
00181
00182 PRIVATE void data_block(keyp, data)
00183 rd_keyinstance *keyp;
00184 void *data;
00185 {
00186 int r;
00187 u8_t input[AES_BLOCKSIZE];
00188
00189 memset(input, '\0', sizeof(input));
00190
00191
00192
00193
00194
00195
00196 assert(sizeof(count_lo)+sizeof(count_hi) <= AES_BLOCKSIZE);
00197 memcpy(input, &count_lo, sizeof(count_lo));
00198 memcpy(input+sizeof(count_lo), &count_hi, sizeof(count_hi));
00199 r= rijndael_ecb_encrypt(keyp, input, data, AES_BLOCKSIZE, NULL);
00200 assert(r == AES_BLOCKSIZE);
00201
00202 count_lo++;
00203 if (count_lo == 0)
00204 count_hi++;
00205 }
00206
00207 PRIVATE void reseed()
00208 {
00209 int i;
00210 SHA256_CTX ctx;
00211 u8_t digest[SHA256_DIGEST_LENGTH];
00212
00213 if (samples < MIN_SAMPLES)
00214 return;
00215
00216 reseed_count++;
00217 SHA256_Init(&ctx);
00218 if (got_seeded)
00219 SHA256_Update(&ctx, random_key, sizeof(random_key));
00220 SHA256_Final(digest, &pool_ctx[0]);
00221 SHA256_Update(&ctx, digest, sizeof(digest));
00222 SHA256_Init(&pool_ctx[0]);
00223 for (i= 1; i<NR_POOLS; i++)
00224 {
00225 if ((reseed_count & (1UL << (i-1))) != 0)
00226 break;
00227 SHA256_Final(digest, &pool_ctx[i]);
00228 SHA256_Update(&ctx, digest, sizeof(digest));
00229 SHA256_Init(&pool_ctx[i]);
00230 }
00231 SHA256_Final(digest, &ctx);
00232 assert(sizeof(random_key) == sizeof(digest));
00233 memcpy(random_key, &digest, sizeof(random_key));
00234 samples= 0;
00235
00236 got_seeded= 1;
00237 }
00238