minix/drivers/random/random.c

238 lines
4.6 KiB
C
Raw Normal View History

2005-07-18 17:40:24 +02:00
/*
random.c
Random number generator.
The random number generator collects data from the kernel and compressed
that data into a seed for a psuedo random number generator.
*/
#include <minix/drivers.h>
2010-04-02 00:22:33 +02:00
#include "kernel/const.h"
2005-07-18 17:40:24 +02:00
#include "assert.h"
#include "random.h"
Build NetBSD libc library in world in ELF mode. 3 sets of libraries are built now: . ack: all libraries that ack can compile (/usr/lib/i386/) . clang+elf: all libraries with minix headers (/usr/lib/) . clang+elf: all libraries with netbsd headers (/usr/netbsd/) Once everything can be compiled with netbsd libraries and headers, the /usr/netbsd hierarchy will be obsolete and its libraries compiled with netbsd headers will be installed in /usr/lib, and its headers in /usr/include. (i.e. minix libc and current minix headers set will be gone.) To use the NetBSD libc system (libraries + headers) before it is the default libc, see: http://wiki.minix3.org/en/DevelopersGuide/UsingNetBSDCode This wiki page also documents the maintenance of the patch files of minix-specific changes to imported NetBSD code. Changes in this commit: . libsys: Add NBSD compilation and create a safe NBSD-based libc. . Port rest of libraries (except libddekit) to new header system. . Enable compilation of libddekit with new headers. . Enable kernel compilation with new headers. . Enable drivers compilation with new headers. . Port legacy commands to new headers and libc. . Port servers to new headers. . Add <sys/sigcontext.h> in compat library. . Remove dependency file in tree. . Enable compilation of common/lib/libc/atomic in libsys . Do not generate RCSID strings in libc. . Temporarily disable zoneinfo as they are incompatible with NetBSD format . obj-nbsd for .gitignore . Procfs: use only integer arithmetic. (Antoine Leca) . Increase ramdisk size to create NBSD-based images. . Remove INCSYMLINKS handling hack. . Add nbsd_include/sys/exec_elf.h . Enable ELF compilation with NBSD libc. . Add 'make nbsdsrc' in tools to download reference NetBSD sources. . Automate minix-port.patch creation. . Avoid using fstavfs() as it is *extremely* slow and unneeded. . Set err() as PRIVATE to avoid name clash with libc. . [NBSD] servers/vm: remove compilation warnings. . u32 is not a long in NBSD headers. . UPDATING info on netbsd hierarchy . commands fixes for netbsd libc
2011-04-27 15:00:52 +02:00
#include <sys/sha2.h>
2005-07-18 17:40:24 +02:00
#include "aes/rijndael.h"
#define N_DERIV 16
#define NR_POOLS 32
#define MIN_SAMPLES 256 /* Number of samples needed in pool 0 for a
* re-seed.
*/
2012-03-25 20:25:53 +02:00
static unsigned long deriv[TOTAL_SOURCES][N_DERIV];
static int pool_ind[TOTAL_SOURCES];
static SHA256_CTX pool_ctx[NR_POOLS];
static unsigned samples= 0;
static int got_seeded= 0;
static u8_t random_key[2*AES_BLOCKSIZE];
static u32_t count_lo, count_hi;
static u32_t reseed_count;
static void add_sample(int source, unsigned long sample);
static void data_block(rd_keyinstance *keyp, void *data);
static void reseed(void);
void random_init()
2005-07-18 17:40:24 +02:00
{
int i, j;
assert(&deriv[TOTAL_SOURCES-1][N_DERIV-1] ==
&deriv[0][0] + TOTAL_SOURCES*N_DERIV -1);
2005-07-18 17:40:24 +02:00
for (i= 0; i<TOTAL_SOURCES; i++)
2005-07-18 17:40:24 +02:00
{
for (j= 0; j<N_DERIV; j++)
deriv[i][j]= 0;
pool_ind[i]= 0;
}
for (i= 0; i<NR_POOLS; i++)
SHA256_Init(&pool_ctx[i]);
count_lo= 0;
count_hi= 0;
reseed_count= 0;
}
2012-03-25 20:25:53 +02:00
int random_isseeded()
2005-07-18 17:40:24 +02:00
{
if (got_seeded)
return 1;
return 0;
2005-07-18 17:40:24 +02:00
}
2012-03-25 20:25:53 +02:00
void random_update(source, buf, count)
2005-07-18 17:40:24 +02:00
int source;
rand_t *buf;
2005-07-18 17:40:24 +02:00
int count;
{
int i;
#if 0
printf("random_update: got %d samples for source %d\n", count, source);
#endif
if (source < 0 || source >= TOTAL_SOURCES)
panic("random_update: bad source: %d", source);
2005-07-18 17:40:24 +02:00
for (i= 0; i<count; i++)
add_sample(source, buf[i]);
reseed();
2005-07-18 17:40:24 +02:00
}
2012-03-25 20:25:53 +02:00
void random_getbytes(buf, size)
2005-07-18 17:40:24 +02:00
void *buf;
size_t size;
{
int n, r;
u8_t *cp;
rd_keyinstance key;
u8_t output[AES_BLOCKSIZE];
r= rijndael_makekey(&key, sizeof(random_key), random_key);
assert(r == 0);
cp= buf;
while (size > 0)
{
n= AES_BLOCKSIZE;
if (n > size)
{
n= size;
data_block(&key, output);
memcpy(cp, output, n);
}
else
data_block(&key, cp);
cp += n;
size -= n;
}
/* Generate new key */
assert(sizeof(random_key) == 2*AES_BLOCKSIZE);
data_block(&key, random_key);
data_block(&key, random_key+AES_BLOCKSIZE);
}
2012-03-25 20:25:53 +02:00
void random_putbytes(buf, size)
2005-07-18 17:40:24 +02:00
void *buf;
size_t size;
{
/* Add bits to pool zero */
SHA256_Update(&pool_ctx[0], buf, size);
/* Assume that these bits are truely random. Increment samples
* with the number of bits.
*/
samples += size*8;
reseed();
2005-07-18 17:40:24 +02:00
}
2012-03-25 20:25:53 +02:00
static void add_sample(source, sample)
2005-07-18 17:40:24 +02:00
int source;
unsigned long sample;
{
int i, pool_nr;
unsigned long d, v, di, min;
/* Delete bad sample. Compute the Nth derivative. Delete the sample
* if any derivative is too small.
*/
min= (unsigned long)-1;
v= sample;
for (i= 0; i<N_DERIV; i++)
{
di= deriv[source][i];
/* Compute the difference */
if (v >= di)
d= v-di;
else
d= di-v;
deriv[source][i]= v;
v= d;
if (v <min)
min= v;
}
if (min < 2)
{
#if 0
printf("ignoring sample '%u' from source %d\n",
sample, source);
#endif
return;
}
#if 0
printf("accepting sample '%u' from source %d\n", sample, source);
#endif
pool_nr= pool_ind[source];
assert(pool_nr >= 0 && pool_nr < NR_POOLS);
SHA256_Update(&pool_ctx[pool_nr], (unsigned char *)&sample,
sizeof(sample));
if (pool_nr == 0)
samples++;
pool_nr++;
if (pool_nr >= NR_POOLS)
pool_nr= 0;
pool_ind[source]= pool_nr;
}
2012-03-25 20:25:53 +02:00
static void data_block(keyp, data)
2005-07-18 17:40:24 +02:00
rd_keyinstance *keyp;
void *data;
{
int r;
u8_t input[AES_BLOCKSIZE];
memset(input, '\0', sizeof(input));
/* Do we want the output of the random numbers to be portable
* across platforms (for example for RSA signatures)? At the moment
* we don't do anything special. Encrypt the counter with the AES
* key.
*/
assert(sizeof(count_lo)+sizeof(count_hi) <= AES_BLOCKSIZE);
memcpy(input, &count_lo, sizeof(count_lo));
memcpy(input+sizeof(count_lo), &count_hi, sizeof(count_hi));
r= rijndael_ecb_encrypt(keyp, input, data, AES_BLOCKSIZE, NULL);
assert(r == AES_BLOCKSIZE);
count_lo++;
if (count_lo == 0)
count_hi++;
}
2012-03-25 20:25:53 +02:00
static void reseed()
{
int i;
SHA256_CTX ctx;
u8_t digest[SHA256_DIGEST_LENGTH];
if (samples < MIN_SAMPLES)
return;
reseed_count++;
SHA256_Init(&ctx);
if (got_seeded)
SHA256_Update(&ctx, random_key, sizeof(random_key));
SHA256_Final(digest, &pool_ctx[0]);
SHA256_Update(&ctx, digest, sizeof(digest));
SHA256_Init(&pool_ctx[0]);
for (i= 1; i<NR_POOLS; i++)
{
if ((reseed_count & (1UL << (i-1))) != 0)
break;
SHA256_Final(digest, &pool_ctx[i]);
SHA256_Update(&ctx, digest, sizeof(digest));
SHA256_Init(&pool_ctx[i]);
}
SHA256_Final(digest, &ctx);
assert(sizeof(random_key) == sizeof(digest));
memcpy(random_key, &digest, sizeof(random_key));
samples= 0;
got_seeded= 1;
}