diff --git a/software/infnoise.c b/software/infnoise.c index cde89bd..7dd83d4 100644 --- a/software/infnoise.c +++ b/software/infnoise.c @@ -148,44 +148,42 @@ int main(int argc, char **argv) return 0; } - char *message; + char *message = "no data?"; + bool errorFlag = false; if (opts.listDevices) { if(!listUSBDevices(&ftdic, &message)) { fputs(message, stderr); return 1; } + //fputs(message, stdout); // todo: put list of devices to &message and print here, not in libinfnoise return 0; } if (opts.devRandom) { - inmWriteEntropyStart(BUFLEN/8u, opts.debug); // todo: create method in libinfnoise.h for this - // also todo: check if superUser in this mode (it will fail silently if not :-/) + inmWriteEntropyStart(BUFLEN/8u, opts.debug); // todo: create method in libinfnoise.h for this? + // also todo: check superUser in this mode (it will fail silently if not :-/) } // Optionally run in the background and optionally write a PID-file startDaemon(&opts); - // initialize USB device and health check - if (initInfnoise(&ftdic, opts.serial, &message, opts.debug) != true) { + // initialize USB device, health check and Keccak state (see libinfnoise) + if (initInfnoise(&ftdic, opts.serial, &message, !opts.raw, opts.debug) != true) { fputs(message, stderr); - return 1; // ERROR (message still goes to stderr) + return 1; // ERROR } - // initialize keccak - KeccakInitialize(); - uint8_t keccakState[KeccakPermutationSizeInBytes]; - KeccakInitializeState(keccakState); - + // endless loop uint64_t totalBytesWritten = 0u; while(true) { uint64_t prevTotalBytesWritten = totalBytesWritten; - uint64_t bytesWritten = readData_private(&ftdic, keccakState, NULL, &message, opts.noOutput, opts.raw, opts.outputMultiplier, opts.devRandom); // calling libinfnoise's private readData method + totalBytesWritten += readData_private(&ftdic, NULL, &message, &errorFlag, opts.noOutput, opts.raw, opts.outputMultiplier, opts.devRandom); // calling libinfnoise's private readData method - if (totalBytesWritten == (unsigned long)-1) { - fputs(message, stderr); + if (errorFlag) { + fprintf(stderr, "%s\n", message); return 1; } - totalBytesWritten += bytesWritten; + if(opts.debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) { fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten); } diff --git a/software/libinfnoise.c b/software/libinfnoise.c index fa7c443..0dc654d 100644 --- a/software/libinfnoise.c +++ b/software/libinfnoise.c @@ -1,4 +1,4 @@ -/* Driver for the Infinite Noise Multiplier USB stick */ +/* Library for the Infinite Noise Multiplier USB stick */ // Required to include clock_gettime #define _POSIX_C_SOURCE 200809L @@ -18,11 +18,61 @@ #include "libinfnoise.h" #include "KeccakF-1600-interface.h" +uint8_t keccakState[KeccakPermutationSizeInBytes]; +bool initInfnoise(struct ftdi_context *ftdic,char *serial, char **message, bool keccak, bool debug) { + prepareOutputBuffer(); + + // initialize health check + if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, debug)) { + *message="Can't initialize health checker"; + return false; + } + + // initialize USB + if(!initializeUSB(ftdic, message, serial)) { + // Sometimes have to do it twice - not sure why + if(!initializeUSB(ftdic, message, serial)) { + return false; + } + } + + // initialize keccak + if (keccak) { + KeccakInitialize(); + KeccakInitializeState(keccakState); + } + + // let healthcheck collect some data + uint32_t maxWarmupRounds = 500; + uint32_t warmupRounds = 0; + bool errorFlag = false; + while(!inmHealthCheckOkToUseData()) { + readData_private(ftdic, NULL, message, &errorFlag, false, true, 0, false); + warmupRounds++; + } + if (warmupRounds > maxWarmupRounds) { + *message = "Unable to collect enough entropy to initialize health checker."; + return false; + } + return true; +} + +uint8_t outBuf[BUFLEN]; +void prepareOutputBuffer() { + uint32_t i; + + // Endless loop: set SW1EN and SW2EN alternately + for(i = 0u; i < BUFLEN; i++) { + // Alternate Ph1 and Ph2 + outBuf[i] = i & 1? (1 << SWEN2) : (1 << SWEN1); + } +} + // 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. Return the expected // bits of entropy. -uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf) { +uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, char **message, bool *errorFlag) { inmClearEntropyLevel(); uint32_t i; for(i = 0u; i < BUFLEN/8u; i++) { @@ -35,10 +85,12 @@ uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf) { bool even = j & 1u; // Use the even bit if j is odd uint8_t bit = even? evenBit : oddBit; byte = (byte << 1u) | bit; + // This is a good place to feed the bit from the INM to the health checker. if(!inmHealthCheckAddBit(evenBit, oddBit, even)) { - fputs("Health check of Infinite Noise Multiplier failed!\n", stderr); - exit(1); + *message = "Health check of Infinite Noise Multiplier failed!"; + *errorFlag = true; + return 0; } } bytes[i] = byte; @@ -54,16 +106,17 @@ double diffTime(struct timespec *start, struct timespec *end) { } // Write the bytes to either stdout, or /dev/random. -void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom) { +bool outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom, char **message) { if(!writeDevRandom) { if(fwrite(bytes, 1, length, stdout) != length) { - fputs("Unable to write output from Infinite Noise Multiplier\n", stderr); - exit(1); + *message = "Unable to write output from Infinite Noise Multiplier"; + return false; } } else { inmWaitForPoolToHaveRoom(); inmWriteEntropyToPool(bytes, length, entropy); } + return true; } bool isSuperUser(void) { @@ -76,8 +129,9 @@ bool isSuperUser(void) { // outputMultiplier is 0, we output only as many bits as we measure in entropy. // This allows a user to generate hundreds of MiB per second if needed, for use // as cryptographic keys. -uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uint32_t entropy, bool raw, - bool writeDevRandom, uint32_t outputMultiplier, bool noOutput) { +uint32_t processBytes(uint8_t *bytes, uint8_t *result, uint32_t entropy, + bool raw, bool writeDevRandom, uint32_t outputMultiplier, bool noOutput, + char **message, bool *errorFlag) { //Use the lower of the measured entropy and the provable lower bound on //average entropy. if(entropy > inmExpectedEntropyPerBit*BUFLEN/INM_ACCURACY) { @@ -86,7 +140,10 @@ uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uin if(raw) { // In raw mode, we just output raw data from the INM. if (!noOutput) { - outputBytes(bytes, BUFLEN/8u, entropy, writeDevRandom); + if (!outputBytes(bytes, BUFLEN/8u, entropy, writeDevRandom, message)) { + *errorFlag = true; + return 0; // write failed + } } else { if (result != NULL) { memcpy(result, bytes, BUFLEN/8u * sizeof(uint8_t)); @@ -108,7 +165,10 @@ uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uin // Output all the bytes of entropy we have KeccakExtract(keccakState, dataOut, (entropy + 63u)/64u); if (!noOutput) { - outputBytes(dataOut, entropy/8u, entropy & 0x7u, writeDevRandom); + if (!outputBytes(dataOut, entropy/8u, entropy & 0x7u, writeDevRandom, message)) { + *errorFlag = true; + return 0; + } } else { if (result != NULL) { memcpy(result, dataOut, entropy/8u * sizeof(uint8_t)); @@ -133,7 +193,10 @@ uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uin entropyThisTime = 8u*bytesToWrite; } if (!noOutput) { - outputBytes(dataOut, bytesToWrite, entropyThisTime, writeDevRandom); + if (!outputBytes(dataOut, bytesToWrite, entropyThisTime, writeDevRandom, message)) { + *errorFlag = true; + return 0; + } } else { //memcpy(result + bytesWritten, dataOut, bytesToWrite * sizeof(uint8_t)); //doesn't work? // alternative: loop through dataOut and append array elements to result.. @@ -151,8 +214,9 @@ uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uin } } if(bytesWritten != outputMultiplier*(256u/8u)) { - fprintf(stderr, "Internal error outputing bytes\n"); - exit(1); + *message = "Internal error outputing bytes"; + *errorFlag = true; + return 0; } return bytesWritten; } @@ -171,9 +235,9 @@ bool listUSBDevices(struct ftdi_context *ftdic, char** message) { if (rc < 0) { if (!isSuperUser()) { - *message = "Can't find Infinite Noise Multiplier. Try running as super user?\n"; + *message = "Can't find Infinite Noise Multiplier. Try running as super user?"; } else { - *message = "Can't find Infinite Noise Multiplier\n"; + *message = "Can't find Infinite Noise Multiplier"; } } @@ -182,7 +246,7 @@ bool listUSBDevices(struct ftdi_context *ftdic, char** message) { rc = ftdi_usb_get_strings(ftdic, curdev->dev, manufacturer, 128, description, 128, serial, 128); if (rc < 0) { if (!isSuperUser()) { - *message = "Can't find Infinite Noise Multiplier. Try running as super user?\n"; + *message = "Can't find Infinite Noise Multiplier. Try running as super user?"; return false; } //*message = "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic)); @@ -190,7 +254,7 @@ bool listUSBDevices(struct ftdi_context *ftdic, char** message) { } // print to stdout - printf("Manufacturer: %s, Description: %s, Serial: %s\n", manufacturer, description, serial); + printf("Manufacturer: %s, Description: %s, Serial: %s", manufacturer, description, serial); curdev = curdev->next; } @@ -205,7 +269,7 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { // search devices int rc = 0; if ((rc = ftdi_usb_find_all(ftdic, &devlist, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID)) < 0) { - *message = "Can't find Infinite Noise Multiplier\n"; + *message = "Can't find Infinite Noise Multiplier"; return false; } @@ -214,13 +278,13 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { if (serial == NULL) { // more than one found AND no serial given if (rc >= 2) { - *message = "Multiple Infnoise TRNGs found and serial not specified, using the first one!\n"; + *message = "Multiple Infnoise TRNGs found and serial not specified, using the first one!"; } if (ftdi_usb_open(ftdic, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID) < 0) { if(!isSuperUser()) { - *message = "Can't open Infinite Noise Multiplier. Try running as super user?\n"; + *message = "Can't open Infinite Noise Multiplier. Try running as super user?"; } else { - *message = "Can't open Infinite Noise Multiplier\n"; + *message = "Can't open Infinite Noise Multiplier"; } return false; } @@ -229,9 +293,9 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { rc = ftdi_usb_open_desc(ftdic, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID, NULL, serial); if (rc < 0) { if(!isSuperUser()) { - *message = "Can't find Infinite Noise Multiplier. Try running as super user?\n"; + *message = "Can't find Infinite Noise Multiplier. Try running as super user?"; } else { - *message = "Can't find Infinite Noise Multiplier with given serial\n"; + *message = "Can't find Infinite Noise Multiplier with given serial"; } return false; } @@ -241,18 +305,18 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { // Set high baud rate rc = ftdi_set_baudrate(ftdic, 30000); if(rc == -1) { - *message = "Invalid baud rate\n"; + *message = "Invalid baud rate"; return false; } else if(rc == -2) { - *message = "Setting baud rate failed\n"; + *message = "Setting baud rate failed"; return false; } else if(rc == -3) { - *message = "Infinite Noise Multiplier unavailable\n"; + *message = "Infinite Noise Multiplier unavailable"; return false; } rc = ftdi_set_bitmode(ftdic, MASK, BITMODE_SYNCBB); if(rc == -1) { - *message = "Can't enable bit-bang mode\n"; + *message = "Can't enable bit-bang mode"; return false; } else if(rc == -2) { *message = "Infinite Noise Multiplier unavailable\n"; @@ -262,51 +326,40 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { // Just test to see that we can write and read. uint8_t buf[64u] = {0u,}; if(ftdi_write_data(ftdic, buf, 64) != 64) { - *message = "USB write failed\n"; + *message = "USB write failed"; return false; } if(ftdi_read_data(ftdic, buf, 64) != 64) { - *message = "USB read failed\n"; + *message = "USB read failed"; return false; } return true; } - -uint64_t readRawData(struct ftdi_context *ftdic, uint8_t *result, char **message) { - return readData_private(ftdic, NULL, result, message, false, true, 0, false); +uint32_t readRawData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag) { + return readData_private(ftdic, result, message, errorFlag, false, true, 0, false); } -uint64_t readData(struct ftdi_context *ftdic, uint8_t *keccakState, uint8_t *result, char **message, uint32_t outputMultiplier) { - return readData_private(ftdic, keccakState, result, message, false, false, outputMultiplier, false); +uint32_t readData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag, uint32_t outputMultiplier) { + return readData_private(ftdic, result, message, errorFlag, false, false, outputMultiplier, false); } -uint8_t outBuf[BUFLEN]; -void prepareOutputBuffer() { - uint32_t i; - - // Endless loop: set SW1EN and SW2EN alternately - for(i = 0u; i < BUFLEN; i++) { - // Alternate Ph1 and Ph2 - outBuf[i] = i & 1? (1 << SWEN2) : (1 << SWEN1); - } -} - -uint64_t readData_private(struct ftdi_context *ftdic, uint8_t *keccakState, uint8_t *result, char **message, bool noOutput, bool raw, uint32_t outputMultiplier, bool devRandom) { +uint32_t readData_private(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag, + bool noOutput, bool raw, uint32_t outputMultiplier, bool devRandom) { uint8_t inBuf[BUFLEN]; - uint64_t totalBytesWritten = 0u; struct timespec start; clock_gettime(CLOCK_REALTIME, &start); // write clock signal if(ftdi_write_data(ftdic, outBuf, BUFLEN) != BUFLEN) { *message = "USB write failed"; - return -1; + *errorFlag = true; } + // and read 512 byte from the internal buffer (in synchronous bitbang mode) if(ftdi_read_data(ftdic, inBuf, BUFLEN) != BUFLEN) { *message = "USB read failed"; - return -1; + *errorFlag = true; } struct timespec end; @@ -314,37 +367,15 @@ uint64_t readData_private(struct ftdi_context *ftdic, uint8_t *keccakState, uint uint32_t us = diffTime(&start, &end); if(us <= MAX_MICROSEC_FOR_SAMPLES) { uint8_t bytes[BUFLEN/8u]; - uint32_t entropy = extractBytes(bytes, inBuf); + uint32_t entropy = extractBytes(bytes, inBuf, message, errorFlag); // call health check and process bytes if OK - if(!noOutput && inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) { - totalBytesWritten += processBytes(keccakState, bytes, result, entropy, raw, devRandom, outputMultiplier, noOutput); + if (inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) { + uint32_t byteswritten = processBytes(bytes, result, entropy, raw, devRandom, outputMultiplier, noOutput, message, errorFlag); + return byteswritten; } } - return totalBytesWritten; -} - -uint8_t keccakState[KeccakPermutationSizeInBytes]; -bool initInfnoise(struct ftdi_context *ftdic,char *serial, char **message, bool debug) { - prepareOutputBuffer(); - // initialize health check - if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, debug)) { - *message="Can't initialize health checker"; - return false; - } - - // initialize USB - if(!initializeUSB(ftdic, message, serial)) { - // Sometimes have to do it twice - not sure why - if(!initializeUSB(ftdic, message, serial)) { - return false; - } - } - return true; - - // initialize keccak - KeccakInitialize(); - KeccakInitializeState(keccakState); + return 0; } #ifdef LIB_EXAMPLE_PROGRAM @@ -368,7 +399,6 @@ int main() { } else { resultSize = multiplier*32u; } - fprintf(stderr, "%d\n", resultSize); uint64_t totalBytesWritten = 0u; diff --git a/software/libinfnoise_private.h b/software/libinfnoise_private.h index 524545a..80478ef 100644 --- a/software/libinfnoise_private.h +++ b/software/libinfnoise_private.h @@ -47,18 +47,18 @@ void inmWriteEntropyStart(uint32_t bufLen, bool debug); void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy); void inmWaitForPoolToHaveRoom(void); void inmDumpStats(void); -//bool isSuperUser(void); extern double inmK, inmExpectedEntropyPerBit; + +bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial); +void prepareOutputBuffer(); + struct timespec; double diffTime(struct timespec *start, struct timespec *end); -uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf); -void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom); -uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uint32_t entropy, bool raw, - bool writeDevRandom, uint32_t outputMultiplier, bool noOutput); +uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, char **message, bool *errorFlag); -uint64_t readData_private(struct ftdi_context *ftdic, uint8_t *keccakState, uint8_t *result, char **message, - bool noOutput, bool raw, uint32_t outputMultiplier, bool devRandom); - -//void add_to_list(struct inm_devlist *list, struct infnoise_device *dev); +bool outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom, char **message); +uint32_t processBytes(uint8_t *bytes, uint8_t *result, uint32_t entropy, bool raw, + bool writeDevRandom, uint32_t outputMultiplier, bool noOutput, char **message, bool *errorFlag); +uint32_t readData_private(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag, bool noOutput, bool raw, uint32_t outputMultiplier, bool devRandom);