//
//random.c
//
//
//
//todo: noting of entropy sources and testing for actual bit quality
//
#include "misc/compat.h"
#include <stdlib.h>
//#include <stdio.h>
#include <limits.h>
#include <time.h>
#include "crypt/random.h"
#include "base/dblock.h"
#include "crypt/entropy.h"
#include "crypt/rand-key.h"
#include "base/str.h"
#include "file/file.h"
#ifdef _WINDOZE_
#define random() rand()
#define srandom(x) srand(x)
#endif
int fastpoolselect = 0;
EntropyPool *fastpool = NULL;
EntropyPool *slowpool = NULL;
RandomKey *randomkey = NULL;
char defaultrandomseedfilename[] = DEFAULT_RANDOMSEEDFILENAME;
char *randomseedfilename = NULL;
int randomentropyneeded = 1;
uint8 tempbuffer[8];
char *randomGetSeedFilename(void) {
if(randomseedfilename != NULL) {
return randomseedfilename;
} else {
return defaultrandomseedfilename;
}
}
void randomSetSeedFilename(char *filename) {
stringFree(randomseedfilename);
randomseedfilename = NULL;
if(filename == NULL) {
return;
}
randomseedfilename = stringCopy(filename);
}
void randomReadSeed(void) {
DataBlock *db;
FileHandle *fh;
int i;
fh = fileOpen(randomGetSeedFilename(), "rb");
if(fh == NULL) {
return;
}
db = dblockMake(RANDOM_SEED_SIZE, RANDOM_SEED_SIZE, "randomseed");
db->size = fileRead(fh, db->data, RANDOM_SEED_SIZE);
for(i = 0; i <db->size; i += 4) {
randomAddEntropyBuffer(&db->data[i], 4, 32);
}
if(db->size >= RANDOM_SEED_SIZE) {
randomentropyneeded = 0;
}
fileClose(fh);
dblockFree(db);
}
void randomWriteSeed(void) {
DataBlock *db;
FileHandle *fh;
fh = fileOpen(randomGetSeedFilename(), "wb");
if(fh == NULL) {
return;
}
db = randomDBlock(RANDOM_SEED_SIZE);
fileWrite(fh, db->data, db->size);
dblockFree(db);
fileClose(fh);
randomentropyneeded = 0;
}
//reseed the generator key by
//calling makekey with (fastpool + generator key)
void randomFastPoolReseed(void) {
DataBlock *db = entropyGetDigest(fastpool, NULL);
db = dblockAppendBlock(db, randomkey->key);
randomkeyMakeKey(randomkey, db);
dblockFree(db);
}
//reseed the generator key by
//calling makekey with (fastpool + slowpool + generator key)
void randomSlowPoolReseed(void) {
DataBlock *db = entropyGetDigest(fastpool, NULL);
DataBlock *dbs = entropyGetDigest(slowpool, NULL);
db = dblockAppendBlock(db, dbs);
db = dblockAppendBlock(db, randomkey->key);
entropyAddDBlock(fastpool, dbs, dbs->size * 8);
randomkeyMakeKey(randomkey, db);
dblockFree(dbs);
dblockFree(db);
// DataBlock *db = entropyGetDigest(slowpool, NULL);
// entropyAddDBlock(fastpool, db, db->size * 8);
// randomFastPoolReseed();
// dblockFree(db);
randomWriteSeed();
}
void randomReseedDecide(void) {
if(fastpoolselect) {
if(fastpool->PoolSize > FAST_THRESHOLD) {
randomFastPoolReseed();
}
} else {
if(slowpool->PoolSize > SLOW_THRESHOLD * 2) {
//todo: testing of individual sub-pool sizes of random sources
randomSlowPoolReseed();
}
}
}
void randomAddEntropy(int v, int bits) {
fastpoolselect = !fastpoolselect;
if(bits > sizeof(v) * 8) {
bits = sizeof(v) * 8;
}
if(fastpoolselect) {
entropyAddInt(fastpool, v, bits);
} else {
entropyAddInt(slowpool, v, bits);
}
randomReseedDecide();
}
void randomAddEntropyBuffer(uint8 *buffer, int length, int bits) {
fastpoolselect = !fastpoolselect;
if(bits > length * 8) {
bits = length * 8;
}
if(fastpoolselect) {
entropyAddBuffer(fastpool, buffer, length, bits);
} else {
entropyAddBuffer(slowpool, buffer, length, bits);
}
randomReseedDecide();
}
//todo: revisit: this is probably not the best way to do it
void randomAddEntropyClock(int bits) {
randomAddEntropy((int) clock(), bits);
}
void randomInit(void) {
DataBlock *db;
srandom(time(NULL));
if(fastpool == NULL) {
fastpool = entropyMake();
}
if(slowpool == NULL) {
slowpool = entropyMake();
}
if(randomkey == NULL) {
randomkey = randomkeyMake();
db = dblockMake(sizeof(time_t) + sizeof(clock_t), sizeof(int), "randominit");
*((time_t *)(db->data)) = time(NULL); //very weak but guards against the entropy/random system being completely empty
*((clock_t *)((time_t *)(db->data) + 1)) = clock();
randomkeyMakeKey(randomkey, db);
dblockFree(db);
}
randomReadSeed();
}
//returns an integer from 0 to (max - 1)
//returns 0 if the parameter is 0
unsigned int randomint(unsigned int i) {
//return random() % i;
if(i == 0) {
return 0;
}
do {
randomkeyGetBuffer(randomkey, tempbuffer, sizeof(unsigned int));
} while (*((unsigned int *)tempbuffer) < (UINT_MAX - i + 1U) % i);
return (*((unsigned int *)tempbuffer)) % i;
}
//fill an existing buffer with length bytes of random data
void randomBuffer(char *dstbuffer, int length) {
//int i;
//for(i = 0; i < length; i++) {
/// dstbuffer[i] = randomint(256);
//}
randomkeyGetBuffer(randomkey, dstbuffer, length);
}
//create a datablock with length bytes of random data.
DataBlock *randomDBlock(int length) {
DataBlock *db = dblockMake(length, length, "randomDBlock");
randomBuffer(db->data, length);
return db;
}
syntax highlighted by Code2HTML, v. 0.9.1