Added capability to write entropy to /dev/random
This commit is contained in:
		| @@ -1,7 +1,7 @@ | ||||
| all: infnoise healthcheck findlongest | ||||
|  | ||||
| infnoise: infnoise.c healthcheck.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 | ||||
| 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 writeentropy.c Keccak/KeccakF-1600-reference.c -lftdi -lm | ||||
|  | ||||
| healthcheck: healthcheck.c | ||||
| 	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 <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <time.h> | ||||
| #include "healthcheck.h" | ||||
| #include "infnoise.h" | ||||
|  | ||||
| #define INM_MIN_DATA 80000 | ||||
| #define INM_MIN_SAMPLE_SIZE 100 | ||||
| @@ -242,17 +240,13 @@ bool inmHealthCheckOkToUseData(void) { | ||||
| } | ||||
|  | ||||
| // Just return the entropy level added so far in bytes; | ||||
| uint32_t inmHealthCheckGetEntropyLevel(void) { | ||||
|     return inmEntropyLevel/8; | ||||
| uint32_t inmGetEntropyLevel(void) { | ||||
|     return inmEntropyLevel; | ||||
| } | ||||
|  | ||||
| // Reduce the entropy level by numBytes. | ||||
| void inmHealthCheckReduceEntropyLevel(uint32_t numBytes) { | ||||
|     if(numBytes*8 > inmEntropyLevel) { | ||||
|         fprintf(stderr, "Entropy pool underflow\n"); | ||||
|         exit(1); | ||||
|     } | ||||
|     inmEntropyLevel -=  numBytes*8; | ||||
| void inmClearEntropyLevel(void) { | ||||
|     inmEntropyLevel = 0; | ||||
| } | ||||
|  | ||||
| #ifdef TEST_HEALTHCHECK | ||||
|   | ||||
| @@ -4,6 +4,8 @@ bool inmHealthCheckAddBit(bool bit, bool even); | ||||
| bool inmHealthCheckOkToUseData(void); | ||||
| double inmHealthCheckEstimateK(void); | ||||
| double inmHealthCheckEstimateEntropyPerBit(void); | ||||
|  | ||||
| // Returns number of bytes of entropy added so far | ||||
| uint32_t inmHealthCheckGetEntropyLevel(void); | ||||
| void inmHealthCheckReduceEntropyLevel(uint32_t numBytes); | ||||
| uint32_t inmGetEntropyLevel(void); | ||||
| void inmClearEntropyLevel(void); | ||||
| void inmWriteEntropyToPool(uint8_t bytes, uint32_t length, uint32_t entropy); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <ftdi.h> | ||||
| #include "healthcheck.h" | ||||
| #include "infnoise.h" | ||||
| #include "KeccakF-1600-interface.h" | ||||
|  | ||||
| // 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 | ||||
| // 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. | ||||
| static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) { | ||||
| // per byte read.  Feed bits from the INM to the health checker.  Return the expected | ||||
| // bits of entropy. | ||||
| static uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) { | ||||
|     inmClearEntropyLevel(); | ||||
|     uint32_t i; | ||||
|     for(i = 0; i < BUFLEN/8; i++) { | ||||
|         uint32_t j; | ||||
| @@ -38,7 +40,7 @@ static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) { | ||||
|             byte = (byte << 1) | bit; | ||||
|             // This is a good place to feed the bit from the INM to the health checker. | ||||
|             //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"); | ||||
|                 exit(1); | ||||
|             } | ||||
| @@ -46,41 +48,39 @@ static void extractBytes(uint8_t *bytes, uint8_t *inBuf, bool raw) { | ||||
|         //printf("extracted byte:%x\n", 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. | ||||
| // 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. | ||||
| 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) { | ||||
|         // In raw mode, we disable the health check and whitening, and just output raw | ||||
|         // data from the INM. | ||||
|         if(fwrite(bytes, 1, BUFLEN/8, stdout) != BUFLEN/8) { | ||||
|             fprintf(stderr, "Unable to write output from Infinite Noise Multiplier\n"); | ||||
|             exit(1); | ||||
|         } | ||||
|         // In raw mode, we just output raw data from the INM. | ||||
|         outputBytes(bytes, BUFLEN/8, entropy, writeDevRandom); | ||||
|         return; | ||||
|     } | ||||
|     uint32_t i; | ||||
|     for(i = 0; i < BUFLEN/64; i++) { | ||||
|         // It's always OK to absorb bytes, even if they are not verified for randomness | ||||
|         KeccakAbsorb(keccakState, bytes + i*8, 1); | ||||
|         if(inmHealthCheckOkToUseData() && inmHealthCheckGetEntropyLevel() >= 16) { | ||||
|             // Only output byes if we have enough entropy and health check passes | ||||
|             // Also, we output data at 1/2 the rate of entropy added to the sponge | ||||
|             //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); | ||||
|         } | ||||
|     } | ||||
|     KeccakAbsorb(keccakState, bytes, BUFLEN/64); | ||||
|     KeccakPermutation(keccakState); | ||||
|     // Only output byes if we have enough entropy and health check passes | ||||
|     // Also, we output data at 1/2 the rate of entropy added to the sponge | ||||
|     uint8_t dataOut[BUFLEN/8]; | ||||
|     KeccakExtract(keccakState, dataOut, BUFLEN/64); | ||||
|     outputBytes(dataOut, BUFLEN/8, entropy, writeDevRandom); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| @@ -88,27 +88,41 @@ int main(int argc, char **argv) | ||||
|     struct ftdi_context ftdic; | ||||
|     bool raw = false; | ||||
|     bool debug = false; | ||||
|     bool writeDevRandom = false; | ||||
|     bool noOutput = false; | ||||
|  | ||||
|     // Process arguments | ||||
|     if(argc > 2) { | ||||
|         fprintf(stderr, "Usage: infnoise [--raw]\n" | ||||
|                         "       infnoise --debug\n"); | ||||
|         return 1; | ||||
|     } | ||||
|     if(argc == 2) { | ||||
|         if(!strcmp(argv[1], "--raw")) { | ||||
|     while(argc > 1) { | ||||
|         argc--; | ||||
|         if(!strcmp(argv[argc], "--raw")) { | ||||
|             raw = true; | ||||
|         } else if(!strcmp(argv[1], "--debug")) { | ||||
|         } else if(!strcmp(argv[argc], "--debug")) { | ||||
|             debug = true; | ||||
|         } else if(!strcmp(argv[argc], "--dev-random")) { | ||||
|             writeDevRandom = true; | ||||
|         } else if(!strcmp(argv[argc], "--no-output")) { | ||||
|             noOutput = true; | ||||
|         } else { | ||||
|             fprintf(stderr, "Usage: infnoise [--raw]\n" | ||||
|                             "       infnoise --debug\n"); | ||||
|             fprintf(stderr, "Usage: infnoise [options]\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; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if(debug && !writeDevRandom) { | ||||
|         // No sense writing data to stdout if debug is on | ||||
|         noOutput = true; | ||||
|     } | ||||
|  | ||||
|     // Initialize FTDI context | ||||
|     ftdi_init(&ftdic); | ||||
|     if(writeDevRandom) { | ||||
|         inmWriteEntropyStart(BUFLEN/8, debug); | ||||
|     } | ||||
|     if(!inmHealthCheckStart(14, 1.82, debug)) { | ||||
|         puts("Can't intialize health checker\n"); | ||||
|         return 1; | ||||
| @@ -177,9 +191,9 @@ int main(int argc, char **argv) | ||||
|             return -1; | ||||
|         } | ||||
|         uint8_t bytes[BUFLEN/8]; | ||||
|         extractBytes(bytes, inBuf, raw); | ||||
|         if(!debug) { | ||||
|             processBytes(keccakState, bytes, raw); | ||||
|         uint32_t entropy = extractBytes(bytes, inBuf, raw); | ||||
|         if(!noOutput && inmHealthCheckOkToUseData()) { | ||||
|             processBytes(keccakState, bytes, entropy, raw, writeDevRandom); | ||||
|         } | ||||
|     } | ||||
|     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