4 Random number generator.
6 The random number generator collects data from the kernel and compressed
7 that data into a seed for a psuedo random number generator.
10 #include <minix/drivers.h>
11 #include "kernel/const.h"
16 #include "aes/rijndael.h"
20 #define MIN_SAMPLES 256 /* Number of samples needed in pool 0 for a
24 static unsigned long deriv
[TOTAL_SOURCES
][N_DERIV
];
25 static int pool_ind
[TOTAL_SOURCES
];
26 static SHA256_CTX pool_ctx
[NR_POOLS
];
27 static unsigned samples
= 0;
28 static int got_seeded
= 0;
29 static u8_t random_key
[2*AES_BLOCKSIZE
];
30 static u32_t count_lo
, count_hi
;
31 static u32_t reseed_count
;
33 static void add_sample(int source
, unsigned long sample
);
34 static void data_block(rd_keyinstance
*keyp
, void *data
);
35 static void reseed(void);
41 assert(&deriv
[TOTAL_SOURCES
-1][N_DERIV
-1] ==
42 &deriv
[0][0] + TOTAL_SOURCES
*N_DERIV
-1);
44 for (i
= 0; i
<TOTAL_SOURCES
; i
++)
46 for (j
= 0; j
<N_DERIV
; j
++)
50 for (i
= 0; i
<NR_POOLS
; i
++)
51 SHA256_Init(&pool_ctx
[i
]);
64 void random_update(source
, buf
, count
)
72 printf("random_update: got %d samples for source %d\n", count
, source
);
74 if (source
< 0 || source
>= TOTAL_SOURCES
)
75 panic("random_update: bad source: %d", source
);
76 for (i
= 0; i
<count
; i
++)
77 add_sample(source
, buf
[i
]);
81 void random_getbytes(buf
, size
)
88 u8_t output
[AES_BLOCKSIZE
];
90 r
= rijndael_makekey(&key
, sizeof(random_key
), random_key
);
100 data_block(&key
, output
);
101 memcpy(cp
, output
, n
);
104 data_block(&key
, cp
);
109 /* Generate new key */
110 assert(sizeof(random_key
) == 2*AES_BLOCKSIZE
);
111 data_block(&key
, random_key
);
112 data_block(&key
, random_key
+AES_BLOCKSIZE
);
115 void random_putbytes(buf
, size
)
119 /* Add bits to pool zero */
120 SHA256_Update(&pool_ctx
[0], buf
, size
);
122 /* Assume that these bits are truely random. Increment samples
123 * with the number of bits.
130 static void add_sample(source
, sample
)
132 unsigned long sample
;
135 unsigned long d
, v
, di
, min
;
137 /* Delete bad sample. Compute the Nth derivative. Delete the sample
138 * if any derivative is too small.
140 min
= (unsigned long)-1;
142 for (i
= 0; i
<N_DERIV
; i
++)
144 di
= deriv
[source
][i
];
146 /* Compute the difference */
159 printf("ignoring sample '%u' from source %d\n",
165 printf("accepting sample '%u' from source %d\n", sample
, source
);
168 pool_nr
= pool_ind
[source
];
169 assert(pool_nr
>= 0 && pool_nr
< NR_POOLS
);
171 SHA256_Update(&pool_ctx
[pool_nr
], (unsigned char *)&sample
,
176 if (pool_nr
>= NR_POOLS
)
178 pool_ind
[source
]= pool_nr
;
181 static void data_block(keyp
, data
)
182 rd_keyinstance
*keyp
;
186 u8_t input
[AES_BLOCKSIZE
];
188 memset(input
, '\0', sizeof(input
));
190 /* Do we want the output of the random numbers to be portable
191 * across platforms (for example for RSA signatures)? At the moment
192 * we don't do anything special. Encrypt the counter with the AES
195 assert(sizeof(count_lo
)+sizeof(count_hi
) <= AES_BLOCKSIZE
);
196 memcpy(input
, &count_lo
, sizeof(count_lo
));
197 memcpy(input
+sizeof(count_lo
), &count_hi
, sizeof(count_hi
));
198 r
= rijndael_ecb_encrypt(keyp
, input
, data
, AES_BLOCKSIZE
, NULL
);
199 assert(r
== AES_BLOCKSIZE
);
210 u8_t digest
[SHA256_DIGEST_LENGTH
];
212 if (samples
< MIN_SAMPLES
)
218 SHA256_Update(&ctx
, random_key
, sizeof(random_key
));
219 SHA256_Final(digest
, &pool_ctx
[0]);
220 SHA256_Update(&ctx
, digest
, sizeof(digest
));
221 SHA256_Init(&pool_ctx
[0]);
222 for (i
= 1; i
<NR_POOLS
; i
++)
224 if ((reseed_count
& (1UL << (i
-1))) != 0)
226 SHA256_Final(digest
, &pool_ctx
[i
]);
227 SHA256_Update(&ctx
, digest
, sizeof(digest
));
228 SHA256_Init(&pool_ctx
[i
]);
230 SHA256_Final(digest
, &ctx
);
231 assert(sizeof(random_key
) == sizeof(digest
));
232 memcpy(random_key
, &digest
, sizeof(random_key
));