455 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Library for the Infinite Noise Multiplier USB stick */
 | |
| 
 | |
| // Required to include clock_gettime
 | |
| #define _POSIX_C_SOURCE 200809L
 | |
| 
 | |
| #define INFNOISE_VENDOR_ID 0x0403
 | |
| #define INFNOISE_PRODUCT_ID 0x6015
 | |
| 
 | |
| #include <stdint.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| #include <string.h>
 | |
| #include <time.h>
 | |
| #include <sys/types.h>
 | |
| #include <ftdi.h>
 | |
| #include "libinfnoise_private.h"
 | |
| #include "KeccakF-1600-interface.h"
 | |
| 
 | |
| #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
 | |
| #include <fcntl.h>
 | |
| #endif
 | |
| 
 | |
| uint8_t keccakState[KeccakPermutationSizeInBytes];
 | |
| 
 | |
| bool initInfnoise(struct infnoise_context *context, char *serial, bool keccak, bool debug) {
 | |
|     context->message="";
 | |
|     prepareOutputBuffer();
 | |
| 
 | |
|     // initialize health check
 | |
|     if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, debug)) {
 | |
|         context->message = "Can't initialize health checker";
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // initialize USB
 | |
|     if (!initializeUSB(&context->ftdic, &context->message, serial)) {
 | |
|         // Sometimes have to do it twice - not sure why
 | |
|         if (!initializeUSB(&context->ftdic, &context->message, serial)) {
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // initialize keccak
 | |
|     if (keccak) {
 | |
|         KeccakInitialize();
 | |
|         KeccakInitializeState(keccakState);
 | |
|         //fprintf(stderr, "debug: keccak init: %s\n", context->message);
 | |
|     }
 | |
| 
 | |
|     // let healthcheck collect some data
 | |
|     uint32_t maxWarmupRounds = 500;
 | |
|     uint32_t warmupRounds = 0;
 | |
|     //bool errorFlag = false;
 | |
|     while (!inmHealthCheckOkToUseData()) {
 | |
|         readData(context, NULL, true, 0);
 | |
|         warmupRounds++;
 | |
|     }
 | |
| 
 | |
|     if (warmupRounds > maxWarmupRounds) {
 | |
|         context->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, char **message, bool *errorFlag) {
 | |
|     inmClearEntropyLevel();
 | |
|     uint32_t i;
 | |
|     for (i = 0u; i < BUFLEN / 8u; i++) {
 | |
|         uint32_t j;
 | |
|         uint8_t byte = 0u;
 | |
|         for (j = 0u; j < 8u; j++) {
 | |
|             uint8_t val = inBuf[i * 8u + j];
 | |
|             uint8_t evenBit = (val >> COMP2) & 1u;
 | |
|             uint8_t oddBit = (val >> COMP1) & 1u;
 | |
|             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)) {
 | |
|                 *message = "Health check of Infinite Noise Multiplier failed!";
 | |
|                 *errorFlag = true;
 | |
|                 fprintf(stderr, "Error: %s\n", *message);
 | |
|                 return 0;
 | |
|             }
 | |
|         }
 | |
|         bytes[i] = byte;
 | |
|     }
 | |
|     return inmGetEntropyLevel();
 | |
| }
 | |
| 
 | |
| // Whiten the output, if requested, with a Keccak sponge. Output bytes only if the health
 | |
| // checker says it's OK.  Using outputMultiplier > 1 is a nice way to generate a lot more
 | |
| // cryptographically secure pseudo-random data than the INM generates.  If
 | |
| // 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 *bytes, uint8_t *result, uint32_t *entropy,
 | |
|                       bool raw, uint32_t outputMultiplier, 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) {
 | |
|         *entropy = inmExpectedEntropyPerBit * BUFLEN / INM_ACCURACY;
 | |
|     }
 | |
|     if (raw) {
 | |
|         // In raw mode, we just output raw data from the INM.
 | |
|         if (result != NULL) {
 | |
|             memcpy(result, bytes, BUFLEN / 8u * sizeof(uint8_t));
 | |
|         }
 | |
|         return BUFLEN / 8u;
 | |
|     }
 | |
| 
 | |
|     // Note that BUFLEN has to be less than 1600 by enough to make the sponge secure,
 | |
|     // since outputting all 1600 bits would tell an attacker the Keccak state, allowing
 | |
|     // him to predict any further output, when outputMultiplier > 1, until the next call
 | |
|     // to processBytes.  All 512 bits are absorbed before squeezing data out to ensure that
 | |
|     // we instantly recover (reseed) from a state compromise, which is when an attacker
 | |
|     // gets a snapshot of the keccak state.  BUFLEN must be a multiple of 64, since
 | |
|     // Keccak-1600 uses 64-bit "lanes".
 | |
|     KeccakAbsorb(keccakState, bytes, BUFLEN / 64u);
 | |
| 
 | |
|     if (outputMultiplier == 0u) {
 | |
|         uint8_t dataOut[16u*8u]; // ???
 | |
|         // Output all the bytes of entropy we have
 | |
|         KeccakExtract(keccakState, dataOut, (*entropy + 63u) / 64u);
 | |
| 
 | |
|         if (result != NULL) {
 | |
|             memcpy(result, dataOut, *entropy / 8u * sizeof(uint8_t));
 | |
|         }
 | |
|         return *entropy / 8u;
 | |
|     }
 | |
| 
 | |
|     // Output 256*outputMultipler bits.
 | |
|     uint32_t numBits = outputMultiplier * 256u;
 | |
|     uint32_t bytesWritten = 0u;
 | |
|     uint8_t dataOut[outputMultiplier * 32u]; // ???
 | |
| 
 | |
|     while (numBits > 0u) {
 | |
|         // Write up to 1024 bits at a time.
 | |
|         uint32_t bytesToWrite = 1024u / 8u;
 | |
|         if (bytesToWrite > numBits / 8u) {
 | |
|             bytesToWrite = numBits / 8u;
 | |
|         }
 | |
|         KeccakExtract(keccakState, dataOut, bytesToWrite / 8u);
 | |
|         uint32_t entropyThisTime = *entropy;
 | |
|         if (entropyThisTime > 8u * bytesToWrite) {
 | |
|             entropyThisTime = 8u * bytesToWrite;
 | |
|         }
 | |
| //        memcpy(result + bytesWritten, dataOut, bytesToWrite * sizeof(uint8_t)); // ?
 | |
|         // alternative: loop through dataOut and append array elements to result..
 | |
|         if (result != NULL) {
 | |
|             for (uint32_t i = 0; i < bytesToWrite; i++) {
 | |
|                 result[bytesWritten + i] = dataOut[i];
 | |
|             }
 | |
|         }
 | |
|         //fprintf(stderr, "bytesWritten: %ul\n", bytesWritten);
 | |
|         //fprintf(stderr, "entropy: %ul\n", *entropy);
 | |
| 
 | |
|         bytesWritten += bytesToWrite;
 | |
|         numBits -= bytesToWrite * 8u;
 | |
|         //*entropy -= entropyThisTime;
 | |
|         if (numBits > 0u) {
 | |
|             KeccakPermutation(keccakState);
 | |
|         }
 | |
|     }
 | |
|     if (bytesWritten != outputMultiplier * (256u / 8u)) {
 | |
|         *message = "Internal error outputting bytes";
 | |
|         //fprintf(stderr, "ERROR: %ul", bytesWritten);
 | |
|         *errorFlag = true;
 | |
|         return 0;
 | |
|     }
 | |
|     fprintf(stderr, "bytesWritten_end: %ul\n", bytesWritten);
 | |
|     return bytesWritten;
 | |
| }
 | |
| 
 | |
| 
 | |
| // Return the difference in the times as a double in microseconds.
 | |
| double diffTime(struct timespec *start, struct timespec *end) {
 | |
|     uint32_t seconds = end->tv_sec - start->tv_sec;
 | |
|     int32_t nanoseconds = end->tv_nsec - start->tv_nsec;
 | |
|     return seconds * 1.0e6 + nanoseconds / 1000.0;
 | |
| }
 | |
| 
 | |
| bool isSuperUser(void) {
 | |
|     return (geteuid() == 0);
 | |
| }
 | |
| 
 | |
| // Return a list of all infinite noise multipliers found.
 | |
| devlist_node listUSBDevices(char **message) {
 | |
|     struct ftdi_context ftdic;
 | |
|     ftdi_init(&ftdic);
 | |
| 
 | |
|     struct ftdi_device_list *devlist;
 | |
|     struct ftdi_device_list *curdev;
 | |
|     char manufacturer[128], description[128], serial[128];
 | |
|     int i = 0;
 | |
| 
 | |
|     // search devices
 | |
|     int rc = ftdi_usb_find_all(&ftdic, &devlist, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID);
 | |
|     if (rc < 0) {
 | |
|         if (!isSuperUser()) {
 | |
|             *message = "Can't find Infinite Noise Multiplier.  Try running as super user?";
 | |
|         } else {
 | |
|             *message = "Can't find Infinite Noise Multiplier.";
 | |
|         }
 | |
|     }
 | |
|     devlist_node return_list = malloc(sizeof(struct infnoise_devlist_node));
 | |
|     devlist_node current_entry = return_list;
 | |
| 
 | |
|     for (curdev = devlist; curdev != NULL; i++) {
 | |
|         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?";
 | |
|                 return NULL;
 | |
|             }
 | |
|             //*message = "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic));
 | |
|             return NULL;
 | |
|         }
 | |
|         current_entry->id = i;
 | |
|         strcpy(current_entry->serial, serial);
 | |
|         strcpy(current_entry->manufacturer, manufacturer);
 | |
|         strcpy(current_entry->description, description);
 | |
|         if (curdev->next) {
 | |
|             current_entry->next = malloc(sizeof(struct infnoise_devlist_node));
 | |
|             current_entry = current_entry->next;
 | |
|         } else {
 | |
|             current_entry->next = NULL;
 | |
|         }
 | |
|         //printf("debug: Manufacturer: %s, Description: %s, Serial: %s\n", manufacturer, description, serial);
 | |
|         curdev = curdev->next;
 | |
|     }
 | |
|     return return_list;
 | |
| }
 | |
| 
 | |
| // Initialize the Infinite Noise Multiplier USB interface.
 | |
| bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) {
 | |
|     ftdi_init(ftdic);
 | |
|     struct ftdi_device_list *devlist;
 | |
| 
 | |
|     // 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";
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // only one found, or no serial given
 | |
|     if (rc >= 0) {
 | |
|         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!";
 | |
|             }
 | |
|             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?";
 | |
|                 } else {
 | |
| #ifdef LINUX
 | |
|                     *message = "Can't open Infinite Noise Multiplier.";
 | |
| #endif
 | |
| #if defined(__APPLE__)
 | |
| 
 | |
|                     *message = "Can't open Infinite Noise Multiplier. sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver ? sudo kextunload -b  com.apple.driver.AppleUSBFTDI ?";
 | |
| #endif
 | |
|                 }
 | |
|                 return false;
 | |
|             }
 | |
|         } else {
 | |
|             // serial specified
 | |
|             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?";
 | |
|                 } else {
 | |
|                     *message = "Can't find Infinite Noise Multiplier with given serial";
 | |
|                 }
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Set high baud rate
 | |
|     rc = ftdi_set_baudrate(ftdic, 30000);
 | |
|     if (rc == -1) {
 | |
|         *message = "Invalid baud rate";
 | |
|         return false;
 | |
|     } else if (rc == -2) {
 | |
|         *message = "Setting baud rate failed";
 | |
|         return false;
 | |
|     } else if (rc == -3) {
 | |
|         *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";
 | |
|         return false;
 | |
|     } else if (rc == -2) {
 | |
|         *message = "Infinite Noise Multiplier unavailable\n";
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // 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";
 | |
|         return false;
 | |
|     }
 | |
|     if (ftdi_read_data(ftdic, buf, 64) != 64) {
 | |
|         *message = "USB read failed";
 | |
|         return false;
 | |
|     }
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| uint32_t readData(struct infnoise_context *context, uint8_t *result, bool raw, uint32_t outputMultiplier) {
 | |
|     uint8_t inBuf[BUFLEN];
 | |
|     struct timespec start;
 | |
|     clock_gettime(CLOCK_REALTIME, &start);
 | |
| 
 | |
|     // write clock signal
 | |
|     if (ftdi_write_data(&context->ftdic, outBuf, BUFLEN) != BUFLEN) {
 | |
|         context->message = "USB write failed";
 | |
|         context->errorFlag = true;
 | |
|     }
 | |
| 
 | |
|     // and read 512 byte from the internal buffer (in synchronous bitbang mode)
 | |
|     if (ftdi_read_data(&context->ftdic, inBuf, BUFLEN) != BUFLEN) {
 | |
|         context->message = "USB read failed";
 | |
|         context->errorFlag = true;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     struct timespec end;
 | |
|     clock_gettime(CLOCK_REALTIME, &end);
 | |
|     uint32_t us = diffTime(&start, &end);
 | |
|     if (us <= MAX_MICROSEC_FOR_SAMPLES) {
 | |
|         uint8_t bytes[BUFLEN / 8u];
 | |
|         context->entropyThisTime = extractBytes(bytes, inBuf, &context->message, &context->errorFlag);
 | |
| 	if (context->errorFlag) {
 | |
|             //fprintf(stderr, "ERROR1: %ul\n", context->entropyThisTime);
 | |
|             return 0;
 | |
|         }
 | |
|         // call health check and return bytes if OK
 | |
|         if (inmHealthCheckOkToUseData() && inmEntropyOnTarget(context->entropyThisTime, BUFLEN)) {
 | |
|             return processBytes(bytes, result, &context->entropyThisTime, raw, outputMultiplier, &context->message,
 | |
|                                 &context->errorFlag);
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #ifdef LIB_EXAMPLE_PROGRAM_RAW
 | |
| // example use of libinfnoise - raw
 | |
| // TODO: rewrite!
 | |
| 
 | |
| int main() {
 | |
|     char *serial = NULL; // use any device, can be set to a specific serial
 | |
| 
 | |
|     // initialize USB
 | |
|     struct ftdi_context ftdic;
 | |
|     initInfnoise(&ftdic, serial);
 | |
| 
 | |
|     // parameters for readData(..):
 | |
|     bool rawOutput = true;
 | |
|     uint32_t multiplier = 10u;
 | |
| 
 | |
|     // calculate output size based on the parameters:
 | |
|     // when using the multiplier, we need a result array of 32*MULTIPLIER - otherwise 64(BUFLEN/8) bytes
 | |
|     uint32_t resultSize;
 | |
|     if (multiplier == 0 || rawOutput == true) {
 | |
|         resultSize = BUFLEN / 8u;
 | |
|     } else {
 | |
|         resultSize = multiplier * 32u;
 | |
|     }
 | |
| 
 | |
|     uint64_t totalBytesWritten = 0u;
 | |
| 
 | |
|     // read and print in a loop
 | |
|     while (totalBytesWritten < 100000) {
 | |
|         uint8_t result[resultSize];
 | |
|         uint64_t bytesWritten = 0u;
 | |
|         bytesWritten = readData(&ftdic, keccakState, result, multiplier);
 | |
| 
 | |
|         // check for -1, indicating an error
 | |
|         totalBytesWritten += bytesWritten;
 | |
| 
 | |
|         // make sure to only read as many bytes as readData returned. Only those have passed the health check in this round (usually all)
 | |
|         fwrite(result, 1, bytesWritten, stdout);
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #ifdef LIB_EXAMPLE_PROGRAM_WHITENED
 | |
| // example use of libinfnoise - with keccak
 | |
| // TODO: rewrite!
 | |
| 
 | |
| int main() {
 | |
|     char *serial = NULL; // use any device, can be set to a specific serial
 | |
| 
 | |
|     // initialize USB
 | |
|     struct ftdi_context ftdic;
 | |
|     initInfnoise(&ftdic, serial);
 | |
| 
 | |
|     // parameters for readData(..):
 | |
|     bool rawOutput = true;
 | |
|     uint32_t multiplier = 10u;
 | |
| 
 | |
|     // calculate output size based on the parameters:
 | |
|     // when using the multiplier, we need a result array of 32*MULTIPLIER - otherwise 64(BUFLEN/8) bytes
 | |
|     uint32_t resultSize;
 | |
|     if (multiplier == 0 || rawOutput) {
 | |
|         resultSize = BUFLEN / 8u;
 | |
|     } else {
 | |
|         resultSize = multiplier * 32u;
 | |
|     }
 | |
| 
 | |
|     uint64_t totalBytesWritten = 0u;
 | |
| 
 | |
|     // read and print in a loop
 | |
|     while (totalBytesWritten < 100000) {
 | |
|         uint8_t result[resultSize];
 | |
|         uint64_t bytesWritten = 0u;
 | |
|         bytesWritten = readData(&ftdic, keccakState, result, multiplier);
 | |
| 
 | |
|         // check for -1, indicating an error
 | |
|         totalBytesWritten += bytesWritten;
 | |
| 
 | |
|         // make sure to only read as many bytes as readData returned. Only those have passed the health check in this round (usually all)
 | |
|         fwrite(result, 1, bytesWritten, stdout);
 | |
|     }
 | |
| }
 | |
| #endif
 |