// //random.c // // // //todo: noting of entropy sources and testing for actual bit quality // #include "misc/compat.h" #include //#include #include #include #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 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; }