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