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"
18 #include <minix/sha2.h>
20 #include "aes/rijndael.h"
24 #define MIN_SAMPLES 256 /* Number of samples needed in pool 0 for a
28 static unsigned long deriv
[TOTAL_SOURCES
][N_DERIV
];
29 static int pool_ind
[TOTAL_SOURCES
];
30 static SHA256_CTX pool_ctx
[NR_POOLS
];
31 static unsigned samples
= 0;
32 static int got_seeded
= 0;
33 static u8_t random_key
[2*AES_BLOCKSIZE
];
34 static u32_t count_lo
, count_hi
;
35 static u32_t reseed_count
;
37 static void add_sample(int source
, unsigned long sample
);
38 static void data_block(rd_keyinstance
*keyp
, void *data
);
39 static void reseed(void);
45 assert(&deriv
[TOTAL_SOURCES
-1][N_DERIV
-1] ==
46 &deriv
[0][0] + TOTAL_SOURCES
*N_DERIV
-1);
48 for (i
= 0; i
<TOTAL_SOURCES
; i
++)
50 for (j
= 0; j
<N_DERIV
; j
++)
54 for (i
= 0; i
<NR_POOLS
; i
++)
55 SHA256_Init(&pool_ctx
[i
]);
68 void random_update(source
, buf
, count
)
76 printf("random_update: got %d samples for source %d\n", count
, source
);
78 if (source
< 0 || source
>= TOTAL_SOURCES
)
79 panic("random_update: bad source: %d", source
);
80 for (i
= 0; i
<count
; i
++)
81 add_sample(source
, buf
[i
]);
85 void random_getbytes(buf
, size
)
92 u8_t output
[AES_BLOCKSIZE
];
94 r
= rijndael_makekey(&key
, sizeof(random_key
), random_key
);
104 data_block(&key
, output
);
105 memcpy(cp
, output
, n
);
108 data_block(&key
, cp
);
113 /* Generate new key */
114 assert(sizeof(random_key
) == 2*AES_BLOCKSIZE
);
115 data_block(&key
, random_key
);
116 data_block(&key
, random_key
+AES_BLOCKSIZE
);
119 void random_putbytes(buf
, size
)
123 /* Add bits to pool zero */
124 SHA256_Update(&pool_ctx
[0], buf
, size
);
126 /* Assume that these bits are truely random. Increment samples
127 * with the number of bits.
134 static void add_sample(source
, sample
)
136 unsigned long sample
;
139 unsigned long d
, v
, di
, min
;
141 /* Delete bad sample. Compute the Nth derivative. Delete the sample
142 * if any derivative is too small.
144 min
= (unsigned long)-1;
146 for (i
= 0; i
<N_DERIV
; i
++)
148 di
= deriv
[source
][i
];
150 /* Compute the difference */
163 printf("ignoring sample '%u' from source %d\n",
169 printf("accepting sample '%u' from source %d\n", sample
, source
);
172 pool_nr
= pool_ind
[source
];
173 assert(pool_nr
>= 0 && pool_nr
< NR_POOLS
);
175 SHA256_Update(&pool_ctx
[pool_nr
], (unsigned char *)&sample
,
180 if (pool_nr
>= NR_POOLS
)
182 pool_ind
[source
]= pool_nr
;
185 static void data_block(keyp
, data
)
186 rd_keyinstance
*keyp
;
190 u8_t input
[AES_BLOCKSIZE
];
192 memset(input
, '\0', sizeof(input
));
194 /* Do we want the output of the random numbers to be portable
195 * across platforms (for example for RSA signatures)? At the moment
196 * we don't do anything special. Encrypt the counter with the AES
199 assert(sizeof(count_lo
)+sizeof(count_hi
) <= AES_BLOCKSIZE
);
200 memcpy(input
, &count_lo
, sizeof(count_lo
));
201 memcpy(input
+sizeof(count_lo
), &count_hi
, sizeof(count_hi
));
202 r
= rijndael_ecb_encrypt(keyp
, input
, data
, AES_BLOCKSIZE
, NULL
);
203 assert(r
== AES_BLOCKSIZE
);
214 u8_t digest
[SHA256_DIGEST_LENGTH
];
216 if (samples
< MIN_SAMPLES
)
222 SHA256_Update(&ctx
, random_key
, sizeof(random_key
));
223 SHA256_Final(digest
, &pool_ctx
[0]);
224 SHA256_Update(&ctx
, digest
, sizeof(digest
));
225 SHA256_Init(&pool_ctx
[0]);
226 for (i
= 1; i
<NR_POOLS
; i
++)
228 if ((reseed_count
& (1UL << (i
-1))) != 0)
230 SHA256_Final(digest
, &pool_ctx
[i
]);
231 SHA256_Update(&ctx
, digest
, sizeof(digest
));
232 SHA256_Init(&pool_ctx
[i
]);
234 SHA256_Final(digest
, &ctx
);
235 assert(sizeof(random_key
) == sizeof(digest
));
236 memcpy(random_key
, &digest
, sizeof(random_key
));