Added capability to write entropy to /dev/random
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
all: infnoise healthcheck findlongest
|
all: infnoise healthcheck findlongest
|
||||||
|
|
||||||
infnoise: infnoise.c healthcheck.c Keccak/KeccakF-1600-reference.c Keccak/brg_endian.h
|
infnoise: infnoise.c infnoise.h healthcheck.c writeentropy.c Keccak/KeccakF-1600-reference.c Keccak/brg_endian.h
|
||||||
gcc -Wall -std=c11 -O3 -m64 -march=native -I Keccak -o infnoise infnoise.c healthcheck.c Keccak/KeccakF-1600-reference.c -lftdi -lm
|
gcc -Wall -std=c11 -O3 -m64 -march=native -I Keccak -o infnoise infnoise.c healthcheck.c writeentropy.c Keccak/KeccakF-1600-reference.c -lftdi -lm
|
||||||
|
|
||||||
healthcheck: healthcheck.c
|
healthcheck: healthcheck.c
|
||||||
gcc -Wall -std=c11 -O3 -m64 -march=native -D TEST_HEALTHCHECK -o healthcheck healthcheck.c -lm
|
gcc -Wall -std=c11 -O3 -m64 -march=native -D TEST_HEALTHCHECK -o healthcheck healthcheck.c -lm
|
||||||
|
|||||||
@@ -20,13 +20,11 @@ confirmed.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "healthcheck.h"
|
#include "infnoise.h"
|
||||||
|
|
||||||
#define INM_MIN_DATA 80000
|
#define INM_MIN_DATA 80000
|
||||||
#define INM_MIN_SAMPLE_SIZE 100
|
#define INM_MIN_SAMPLE_SIZE 100
|
||||||
@@ -242,17 +240,13 @@ bool inmHealthCheckOkToUseData(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Just return the entropy level added so far in bytes;
|
// Just return the entropy level added so far in bytes;
|
||||||
uint32_t inmHealthCheckGetEntropyLevel(void) {
|
uint32_t inmGetEntropyLevel(void) {
|
||||||
return inmEntropyLevel/8;
|
return inmEntropyLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the entropy level by numBytes.
|
// Reduce the entropy level by numBytes.
|
||||||
void inmHealthCheckReduceEntropyLevel(uint32_t numBytes) {
|
void inmClearEntropyLevel(void) {
|
||||||
if(numBytes*8 > inmEntropyLevel) {
|
inmEntropyLevel = 0;
|
||||||
fprintf(stderr, "Entropy pool underflow\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
inmEntropyLevel -= numBytes*8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TEST_HEALTHCHECK
|
#ifdef TEST_HEALTHCHECK
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ bool inmHealthCheckAddBit(bool bit, bool even);
|
|||||||
bool inmHealthCheckOkToUseData(void);
|
bool inmHealthCheckOkToUseData(void);
|
||||||
double inmHealthCheckEstimateK(void);
|
double inmHealthCheckEstimateK(void);
|
||||||
double inmHealthCheckEstimateEntropyPerBit(void);
|
double inmHealthCheckEstimateEntropyPerBit(void);
|
||||||
|
|
||||||
// Returns number of bytes of entropy added so far
|
// Returns number of bytes of entropy added so far
|
||||||
uint32_t inmHealthCheckGetEntropyLevel(void);
|
uint32_t inmGetEntropyLevel(void);
|
||||||
void inmHealthCheckReduceEntropyLevel(uint32_t numBytes);
|
void inmClearEntropyLevel(void);
|
||||||
|
void inmWriteEntropyToPool(uint8_t bytes, uint32_t length, uint32_t entropy);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
#include "healthcheck.h"
|
#include "infnoise.h"
|
||||||
#include "KeccakF-1600-interface.h"
|
#include "KeccakF-1600-interface.h"
|
||||||
|
|
||||||
// The FT240X has a 512 byte buffer. Must be multiple of 64
|
// The FT240X has a 512 byte buffer. Must be multiple of 64
|
||||||
@@ -20,8 +20,10 @@
|
|||||||
|
|
||||||
// Extract the INM output from the data received. Basically, either COMP1 or COMP2
|
// Extract the INM output from the data received. Basically, either COMP1 or COMP2
|
||||||
// changes, not both, so alternate reading bits from them. We get 1 INM bit of output
|
// changes, not both, so alternate reading bits from them. We get 1 INM bit of output
|
||||||
// per byte read. Feed bits from the INM to the health checker.
|
// per byte read. Feed bits from the INM to the health checker. Return the expected
|
||||||
static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) {
|
// bits of entropy.
|
||||||
|
static uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) {
|
||||||
|
inmClearEntropyLevel();
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for(i = 0; i < BUFLEN/8; i++) {
|
for(i = 0; i < BUFLEN/8; i++) {
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
@@ -38,7 +40,7 @@ static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) {
|
|||||||
byte = (byte << 1) | bit;
|
byte = (byte << 1) | bit;
|
||||||
// This is a good place to feed the bit from the INM to the health checker.
|
// This is a good place to feed the bit from the INM to the health checker.
|
||||||
//printf("Adding bit %u\n", bit);
|
//printf("Adding bit %u\n", bit);
|
||||||
if(!raw && !inmHealthCheckAddBit(bit, j & 1)) {
|
if(!inmHealthCheckAddBit(bit, j & 1)) {
|
||||||
fprintf(stderr, "Health check of Infinite Noise Multiplier failed!\n");
|
fprintf(stderr, "Health check of Infinite Noise Multiplier failed!\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -46,41 +48,39 @@ static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) {
|
|||||||
//printf("extracted byte:%x\n", byte);
|
//printf("extracted byte:%x\n", byte);
|
||||||
bytes[i] = byte;
|
bytes[i] = byte;
|
||||||
}
|
}
|
||||||
|
return inmGetEntropyLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the bytes to either stdout, or /dev/random. Cut the entropy estimate in half to
|
||||||
|
// be conservative.
|
||||||
|
static void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom) {
|
||||||
|
if(!writeDevRandom) {
|
||||||
|
if(fwrite(bytes, 1, length, stdout) != length) {
|
||||||
|
fprintf(stderr, "Unable to write output from Infinite Noise Multiplier\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inmWaitForPoolToHaveRoom();
|
||||||
|
inmWriteEntropyToPool(bytes, length, entropy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the new bytes through the health checker and also into the Keccak sponge.
|
// Send the new bytes through the health checker and also into the Keccak sponge.
|
||||||
// Output bytes from the sponge only if the health checker says it's OK, and only
|
// Output bytes from the sponge only if the health checker says it's OK, and only
|
||||||
// output half the entropy we get from the INM, just to be paranoid.
|
// output half the entropy we get from the INM, just to be paranoid.
|
||||||
static void processBytes(uint8_t *keccakState, uint8_t *bytes, bool raw) {
|
static void processBytes(uint8_t *keccakState, uint8_t *bytes, uint32_t entropy, bool raw, bool writeDevRandom) {
|
||||||
if(raw) {
|
if(raw) {
|
||||||
// In raw mode, we disable the health check and whitening, and just output raw
|
// In raw mode, we just output raw data from the INM.
|
||||||
// data from the INM.
|
outputBytes(bytes, BUFLEN/8, entropy, writeDevRandom);
|
||||||
if(fwrite(bytes, 1, BUFLEN/8, stdout) != BUFLEN/8) {
|
|
||||||
fprintf(stderr, "Unable to write output from Infinite Noise Multiplier\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t i;
|
KeccakAbsorb(keccakState, bytes, BUFLEN/64);
|
||||||
for(i = 0; i < BUFLEN/64; i++) {
|
KeccakPermutation(keccakState);
|
||||||
// It's always OK to absorb bytes, even if they are not verified for randomness
|
// Only output byes if we have enough entropy and health check passes
|
||||||
KeccakAbsorb(keccakState, bytes + i*8, 1);
|
// Also, we output data at 1/2 the rate of entropy added to the sponge
|
||||||
if(inmHealthCheckOkToUseData() && inmHealthCheckGetEntropyLevel() >= 16) {
|
uint8_t dataOut[BUFLEN/8];
|
||||||
// Only output byes if we have enough entropy and health check passes
|
KeccakExtract(keccakState, dataOut, BUFLEN/64);
|
||||||
// Also, we output data at 1/2 the rate of entropy added to the sponge
|
outputBytes(dataOut, BUFLEN/8, entropy, writeDevRandom);
|
||||||
//uint32_t j;
|
|
||||||
//for(j = 0; j < 1 << 24; j++) {
|
|
||||||
uint8_t dataOut[8];
|
|
||||||
KeccakPermutation(keccakState);
|
|
||||||
KeccakExtract(keccakState, dataOut, 1);
|
|
||||||
if(fwrite(dataOut, 1, 8, stdout) != 8) {
|
|
||||||
fprintf(stderr, "Unable to write output from Infinite Noise Multiplier\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
inmHealthCheckReduceEntropyLevel(16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@@ -88,27 +88,41 @@ int main(int argc, char **argv)
|
|||||||
struct ftdi_context ftdic;
|
struct ftdi_context ftdic;
|
||||||
bool raw = false;
|
bool raw = false;
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
|
bool writeDevRandom = false;
|
||||||
|
bool noOutput = false;
|
||||||
|
|
||||||
// Process arguments
|
// Process arguments
|
||||||
if(argc > 2) {
|
while(argc > 1) {
|
||||||
fprintf(stderr, "Usage: infnoise [--raw]\n"
|
argc--;
|
||||||
" infnoise --debug\n");
|
if(!strcmp(argv[argc], "--raw")) {
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if(argc == 2) {
|
|
||||||
if(!strcmp(argv[1], "--raw")) {
|
|
||||||
raw = true;
|
raw = true;
|
||||||
} else if(!strcmp(argv[1], "--debug")) {
|
} else if(!strcmp(argv[argc], "--debug")) {
|
||||||
debug = true;
|
debug = true;
|
||||||
|
} else if(!strcmp(argv[argc], "--dev-random")) {
|
||||||
|
writeDevRandom = true;
|
||||||
|
} else if(!strcmp(argv[argc], "--no-output")) {
|
||||||
|
noOutput = true;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Usage: infnoise [--raw]\n"
|
fprintf(stderr, "Usage: infnoise [options]\n"
|
||||||
" infnoise --debug\n");
|
"Options are:\n"
|
||||||
|
" --debug - turn on some debug output\n"
|
||||||
|
" --dev-random - write entropy to /dev/random instead of stdout\n"
|
||||||
|
" --raw - do not whiten the output\n"
|
||||||
|
" --no-output - do not write random output data\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(debug && !writeDevRandom) {
|
||||||
|
// No sense writing data to stdout if debug is on
|
||||||
|
noOutput = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize FTDI context
|
// Initialize FTDI context
|
||||||
ftdi_init(&ftdic);
|
ftdi_init(&ftdic);
|
||||||
|
if(writeDevRandom) {
|
||||||
|
inmWriteEntropyStart(BUFLEN/8, debug);
|
||||||
|
}
|
||||||
if(!inmHealthCheckStart(14, 1.82, debug)) {
|
if(!inmHealthCheckStart(14, 1.82, debug)) {
|
||||||
puts("Can't intialize health checker\n");
|
puts("Can't intialize health checker\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -177,9 +191,9 @@ int main(int argc, char **argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
uint8_t bytes[BUFLEN/8];
|
uint8_t bytes[BUFLEN/8];
|
||||||
extractBytes(bytes, inBuf, raw);
|
uint32_t entropy = extractBytes(bytes, inBuf, raw);
|
||||||
if(!debug) {
|
if(!noOutput && inmHealthCheckOkToUseData()) {
|
||||||
processBytes(keccakState, bytes, raw);
|
processBytes(keccakState, bytes, entropy, raw, writeDevRandom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
14
software/infnoise.h
Normal file
14
software/infnoise.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
bool inmHealthCheckStart(uint8_t N, double K, bool debug);
|
||||||
|
void inmHealthCheckStop(void);
|
||||||
|
bool inmHealthCheckAddBit(bool bit, bool even);
|
||||||
|
bool inmHealthCheckOkToUseData(void);
|
||||||
|
double inmHealthCheckEstimateK(void);
|
||||||
|
double inmHealthCheckEstimateEntropyPerBit(void);
|
||||||
|
uint32_t inmGetEntropyLevel(void);
|
||||||
|
void inmClearEntropyLevel(void);
|
||||||
|
void inmWriteEntropyStart(uint32_t bufLen, bool debug);
|
||||||
|
void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy);
|
||||||
|
void inmWaitForPoolToHaveRoom(void);
|
||||||
90
software/writeentropy.c
Normal file
90
software/writeentropy.c
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// This writes entropy to the Linux /dev/random pool using ioctl, so that entropy increases.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include "infnoise.h"
|
||||||
|
|
||||||
|
#define SIZE_PROC_FILENAME "/proc/sys/kernel/random/poolsize"
|
||||||
|
#define FILL_PROC_FILENAME "/proc/sys/kernel/random/write_wakeup_threshold"
|
||||||
|
|
||||||
|
static uint32_t inmBufLen;
|
||||||
|
static bool inmDebug;
|
||||||
|
static int inmDevRandomFD;
|
||||||
|
static uint32_t inmFillWatermark;
|
||||||
|
static struct rand_pool_info *inmPoolInfo;
|
||||||
|
|
||||||
|
// Find the entropy pool size.
|
||||||
|
static uint32_t readNumberFromFile(char *fileName) {
|
||||||
|
FILE *file = fopen(fileName, "r");
|
||||||
|
if(file == NULL) {
|
||||||
|
fprintf(stderr, "Unable to open %s\n", fileName);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
char buf[42];
|
||||||
|
uint32_t i = 0;
|
||||||
|
int c = getc(file);
|
||||||
|
while(c != EOF) {
|
||||||
|
buf[i++] = c;
|
||||||
|
c = getc(file);
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
uint32_t value = atoi(buf);
|
||||||
|
fclose(file);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open /dev/random
|
||||||
|
void inmWriteEntropyStart(uint32_t bufLen, bool debug) {
|
||||||
|
inmBufLen = bufLen;
|
||||||
|
inmDebug = debug;
|
||||||
|
//inmDevRandomFD = open("/dev/random", O_WRONLY);
|
||||||
|
inmDevRandomFD = open("/dev/random", O_RDWR);
|
||||||
|
if(inmDevRandomFD < 0) {
|
||||||
|
fprintf(stderr, "Unable to open /dev/random\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inmPoolInfo = calloc(1, sizeof(struct rand_pool_info) + bufLen);
|
||||||
|
if(inmPoolInfo == NULL) {
|
||||||
|
fprintf(stderr, "Unable to allocate memory\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inmFillWatermark = readNumberFromFile(FILL_PROC_FILENAME);
|
||||||
|
if(inmDebug) {
|
||||||
|
printf("Entropy pool size:%u\n", readNumberFromFile(SIZE_PROC_FILENAME));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block until either the entropy pool has room, or 1 second has passed.
|
||||||
|
void inmWaitForPoolToHaveRoom(void) {
|
||||||
|
printf("starting select\n");
|
||||||
|
int ent_count;
|
||||||
|
struct pollfd pfd = {
|
||||||
|
fd: inmDevRandomFD,
|
||||||
|
events: POLLOUT,
|
||||||
|
};
|
||||||
|
int64_t timeout_usec;
|
||||||
|
if (ioctl(inmDevRandomFD, RNDGETENTCNT, &ent_count) == 0 && ent_count < inmFillWatermark) {
|
||||||
|
printf("Not full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timeout_usec = 1000; // One second
|
||||||
|
poll(&pfd, 1, timeout_usec);
|
||||||
|
printf("Finished select\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the bytes to the entropy pool. This can be unwhitenened, but the estimated bits of
|
||||||
|
// entropy needs to be accurate or pessimistic. Return false if the Linux entropy pool is
|
||||||
|
// full after writing.
|
||||||
|
void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy) {
|
||||||
|
inmPoolInfo->entropy_count = entropy;
|
||||||
|
inmPoolInfo->buf_size = length;
|
||||||
|
memcpy(inmPoolInfo->buf, bytes, length);
|
||||||
|
//printf("Writing %u bytes with %u bits of entropy to /dev/random\n", length, entropy);
|
||||||
|
ioctl(inmDevRandomFD, RNDADDENTROPY, inmPoolInfo);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user