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
|