first shot for a libinfnoise approach
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
GIT_VERSION := $(shell git --no-pager describe --tags --always)
|
||||
GIT_COMMIT := $(shell git rev-parse --verify HEAD)
|
||||
GIT_DATE := $(firstword $(shell git --no-pager show --date=iso-strict --format="%ad" --name-only))
|
||||
BUILD_DATE := $(shell date --iso=seconds)
|
||||
|
||||
PREFIX = $(DESTDIR)/usr/local
|
||||
|
||||
@@ -9,7 +8,6 @@ CFLAGS = -Wall -Wextra -Werror -std=c99 -O3 -I Keccak -I /usr/include/libftdi1 \
|
||||
-DGIT_VERSION=\"$(GIT_VERSION)\"\
|
||||
-DGIT_COMMIT=\"$(GIT_COMMIT)\"\
|
||||
-DGIT_DATE=\"$(GIT_DATE)\"\
|
||||
-DBUILD_DATE=\"$(BUILD_DATE)\"
|
||||
|
||||
FOUND = $(shell ldconfig -p | grep --silent libftdi.so && echo found)
|
||||
ifeq ($(FOUND), found)
|
||||
@@ -18,13 +16,22 @@ else
|
||||
FTDI= -lftdi1
|
||||
endif
|
||||
|
||||
all: infnoise
|
||||
all: libinfnoise.a infnoise
|
||||
|
||||
infnoise: infnoise.c infnoise.h healthcheck.c writeentropy.c daemon.c Keccak/KeccakF-1600-reference.c Keccak/brg_endian.h
|
||||
$(CC) $(CFLAGS) -o infnoise infnoise.c healthcheck.c writeentropy.c daemon.c Keccak/KeccakF-1600-reference.c $(FTDI) -lm -lrt
|
||||
infnoise: infnoise.c infnoise.h libinfnoise.a healthcheck.c writeentropy.c daemon.c
|
||||
$(CC) $(CFLAGS) -o infnoise infnoise.c writeentropy.c healthcheck.c daemon.c $(FTDI) -lm -lrt -L . -linfnoise
|
||||
|
||||
libinfnoise.a: libinfnoise.c libinfnoise.h healthcheck.c healthcheck.h Keccak/brg_endian.h Keccak/KeccakF-1600-reference.c
|
||||
$(CC) $(CFLAGS) -c libinfnoise.c libinfnoise.h healthcheck.c Keccak/KeccakF-1600-reference.c $(FTDI) -lm
|
||||
ar rcs libinfnoise.a libinfnoise.o healthcheck.o KeccakF-1600-reference.o
|
||||
|
||||
libs: libinfnoise.a
|
||||
|
||||
libinfnoise-example: libinfnoise.c libinfnoise.h
|
||||
$(CC) $(CFLAGS) -D LIB_EXAMPLE_PROGRAM -o libinfnoise-example libinfnoise.c libinfnoise.h healthcheck.c writeentropy.c daemon.c Keccak/KeccakF-1600-reference.c $(FTDI) -lm -lrt
|
||||
|
||||
clean:
|
||||
$(RM) infnoise
|
||||
$(RM) infnoise *.o *.a libinfnoise-example
|
||||
|
||||
install:
|
||||
install -d $(PREFIX)/sbin
|
||||
|
||||
@@ -24,7 +24,7 @@ confirmed.
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "infnoise.h"
|
||||
#include "libinfnoise.h"
|
||||
|
||||
#define INM_MIN_DATA 80000u
|
||||
#define INM_MIN_SAMPLE_SIZE 100u
|
||||
@@ -91,11 +91,11 @@ static void resetStats(void) {
|
||||
// Initialize the health check. N is the number of bits used to predict the next bit.
|
||||
// At least 8 bits must be used, and no more than 30. In general, we should use bits
|
||||
// large enough so that INM output will be uncorrelated with bits N samples back in time.
|
||||
bool inmHealthCheckStart(uint8_t N, double K, struct opt_struct *opts) {
|
||||
bool inmHealthCheckStart(uint8_t N, double K, bool debug) {
|
||||
if(N < 1u || N > 30u) {
|
||||
return false;
|
||||
}
|
||||
inmDebug = opts->debug;
|
||||
inmDebug = debug;
|
||||
inmNumBitsOfEntropy = 0u;
|
||||
inmCurrentProbability = 1.0;
|
||||
inmK = K;
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
// 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>
|
||||
@@ -13,224 +10,9 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <ftdi.h>
|
||||
#include "infnoise.h"
|
||||
#include "libinfnoise.h"
|
||||
#include "KeccakF-1600-interface.h"
|
||||
|
||||
// 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.
|
||||
static uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf) {
|
||||
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)) {
|
||||
fputs("Health check of Infinite Noise Multiplier failed!\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
bytes[i] = byte;
|
||||
}
|
||||
return inmGetEntropyLevel();
|
||||
}
|
||||
|
||||
// Write the bytes to either stdout, or /dev/random.
|
||||
static void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, struct opt_struct *opts) {
|
||||
if(!opts->devRandom) {
|
||||
if(fwrite(bytes, 1, length, stdout) != length) {
|
||||
fputs("Unable to write output from Infinite Noise Multiplier\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
inmWaitForPoolToHaveRoom();
|
||||
inmWriteEntropyToPool(bytes, length, entropy);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 cryptogrpahic keys.
|
||||
static uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint32_t entropy, struct opt_struct* opts) {
|
||||
//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(opts->raw) {
|
||||
// In raw mode, we just output raw data from the INM.
|
||||
outputBytes(bytes, BUFLEN/8u, entropy, opts);
|
||||
return BUFLEN/8u;
|
||||
}
|
||||
// Note that BUFLEN has to be less than 1600 by enough to make the sponge secure,
|
||||
// since outputing 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 sqeezing data out to insure 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);
|
||||
uint8_t dataOut[16u*8u];
|
||||
if(opts->outputMultiplier == 0u) {
|
||||
// Output all the bytes of entropy we have
|
||||
KeccakExtract(keccakState, dataOut, (entropy + 63u)/64u);
|
||||
outputBytes(dataOut, entropy/8u, entropy & 0x7u, opts);
|
||||
return entropy/8u;
|
||||
}
|
||||
|
||||
// Output 256*outputMultipler bytes.
|
||||
uint32_t numBits = opts->outputMultiplier*256u;
|
||||
uint32_t bytesWritten = 0u;
|
||||
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;
|
||||
}
|
||||
outputBytes(dataOut, bytesToWrite, entropyThisTime, opts);
|
||||
bytesWritten += bytesToWrite;
|
||||
numBits -= bytesToWrite*8u;
|
||||
entropy -= entropyThisTime;
|
||||
if(numBits > 0u) {
|
||||
KeccakPermutation(keccakState);
|
||||
}
|
||||
}
|
||||
if(bytesWritten != opts->outputMultiplier*(256u/8u)) {
|
||||
fprintf(stderr, "Internal error outputing bytes\n");
|
||||
exit(1);
|
||||
}
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
// Return a list of all infinite noise multipliers found.
|
||||
static bool listUSBDevices(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()) {
|
||||
fprintf(stderr, "Can't find Infinite Noise Multiplier. Try running as super user?\n");
|
||||
} else {
|
||||
fprintf(stderr, "Can't find Infinite Noise Multiplier\n");
|
||||
}
|
||||
}
|
||||
for (curdev = devlist; curdev != NULL; i++) {
|
||||
printf("Device: %d, ", i);
|
||||
rc = ftdi_usb_get_strings(ftdic, curdev->dev, manufacturer, 128, description, 128, serial, 128);
|
||||
if (rc < 0) {
|
||||
if (!isSuperUser()) {
|
||||
fprintf(stderr, "Can't find Infinite Noise Multiplier. Try running as super user?\n");
|
||||
}
|
||||
fprintf(stderr, "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic));
|
||||
return false;
|
||||
}
|
||||
printf("Manufacturer: %s, Description: %s, Serial: %s\n", manufacturer, description, serial);
|
||||
curdev = curdev->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Initialize the Infinite Noise Multiplier USB interface.
|
||||
static 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\n";
|
||||
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) {
|
||||
fprintf(stderr,"Multiple Infnoise TRNGs found and serial not specified, using the first one!\n");
|
||||
}
|
||||
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";
|
||||
} else {
|
||||
*message = "Can't open Infinite Noise Multiplier\n";
|
||||
}
|
||||
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?\n";
|
||||
} else {
|
||||
*message = "Can't find Infinite Noise Multiplier with given serial\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set high baud rate
|
||||
rc = ftdi_set_baudrate(ftdic, 30000);
|
||||
if(rc == -1) {
|
||||
*message = "Invalid baud rate\n";
|
||||
return false;
|
||||
} else if(rc == -2) {
|
||||
*message = "Setting baud rate failed\n";
|
||||
return false;
|
||||
} else if(rc == -3) {
|
||||
*message = "Infinite Noise Multiplier unavailable\n";
|
||||
return false;
|
||||
}
|
||||
rc = ftdi_set_bitmode(ftdic, MASK, BITMODE_SYNCBB);
|
||||
if(rc == -1) {
|
||||
*message = "Can't enable bit-bang mode\n";
|
||||
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\n";
|
||||
return false;
|
||||
}
|
||||
if(ftdi_read_data(ftdic, buf, 64) != 64) {
|
||||
*message = "USB read failed\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void initOpts(struct opt_struct *opts) {
|
||||
opts->outputMultiplier = 0u;
|
||||
opts->daemon =
|
||||
@@ -246,13 +28,6 @@ static void initOpts(struct opt_struct *opts) {
|
||||
opts->serial = NULL;
|
||||
}
|
||||
|
||||
// Return the differnece in the times as a double in microseconds.
|
||||
static 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;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ftdi_context ftdic;
|
||||
@@ -331,7 +106,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read environment variables, not overriding command line options
|
||||
if (opts.serial == NULL) {
|
||||
if (getenv("INFNOISE_SERIAL") != NULL) {
|
||||
@@ -367,12 +141,26 @@ int main(int argc, char **argv)
|
||||
printf("GIT VERSION - %s\n", GIT_VERSION);
|
||||
printf("GIT COMMIT - %s\n", GIT_COMMIT);
|
||||
printf("GIT DATE - %s\n", GIT_DATE);
|
||||
printf("BUILD DATE - %s\n", BUILD_DATE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *message;
|
||||
if (opts.listDevices) {
|
||||
listUSBDevices(&ftdic);
|
||||
struct inm_devlist *device_list;
|
||||
device_list = malloc(sizeof(struct inm_devlist));
|
||||
|
||||
if(!listUSBDevices(&ftdic, &device_list, &message)) {
|
||||
fputs(message, stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct inm_devlist_node *tmp;
|
||||
for ( tmp = device_list->head; tmp != NULL; tmp=tmp->next) {
|
||||
if (tmp->device->serial != NULL) {
|
||||
printf("%s\n", tmp->device->serial);
|
||||
}
|
||||
//tmp = tmp->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -380,18 +168,17 @@ int main(int argc, char **argv)
|
||||
startDaemon(&opts);
|
||||
|
||||
if (opts.devRandom) {
|
||||
inmWriteEntropyStart(BUFLEN/8u, &opts);
|
||||
inmWriteEntropyStart(BUFLEN/8u, opts.debug);
|
||||
}
|
||||
|
||||
if(!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, &opts)) {
|
||||
fputs("Can't intialize health checker\n", stderr);
|
||||
if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, opts.debug)) {
|
||||
fputs("Can't initialize health checker\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
KeccakInitialize();
|
||||
uint8_t keccakState[KeccakPermutationSizeInBytes];
|
||||
KeccakInitializeState(keccakState);
|
||||
|
||||
char *message;
|
||||
if(!initializeUSB(&ftdic, &message, opts.serial)) {
|
||||
// Sometimes have to do it twice - not sure why
|
||||
if(!initializeUSB(&ftdic, &message, opts.serial)) {
|
||||
@@ -429,7 +216,9 @@ int main(int argc, char **argv)
|
||||
uint32_t entropy = extractBytes(bytes, inBuf);
|
||||
if(!opts.noOutput && inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) {
|
||||
uint64_t prevTotalBytesWritten = totalBytesWritten;
|
||||
totalBytesWritten += processBytes(keccakState, bytes, entropy, &opts);
|
||||
totalBytesWritten += processBytes(keccakState, bytes, NULL, entropy, opts.raw,
|
||||
opts.devRandom, opts.outputMultiplier, opts.noOutput);
|
||||
|
||||
if(opts.debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) {
|
||||
fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten);
|
||||
}
|
||||
|
||||
@@ -2,34 +2,6 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Required accuracy of estimated vs measured entropy in health monitor
|
||||
#define INM_ACCURACY 1.03
|
||||
|
||||
// The FT240X has a 512 byte buffer. Must be multiple of 64
|
||||
// We also write this in one go to the Keccak sponge, which is at most 1600 bits
|
||||
#define BUFLEN 512u
|
||||
|
||||
// This is how many previous bits are used to predict the next bit from the INM
|
||||
#define PREDICTION_BITS 14u
|
||||
|
||||
// This is the maximum time we allow to pass to perform the I/O operations, since long
|
||||
// delays can reduce entropy from the INM.
|
||||
#define MAX_MICROSEC_FOR_SAMPLES 5000u
|
||||
|
||||
// This is the gain of each of the two op-amp stages in the INM
|
||||
#define DESIGN_K 1.84
|
||||
|
||||
#define BITMODE_SYNCBB 0x4
|
||||
|
||||
// This defines which pins on the FT240X are used
|
||||
#define COMP1 1u
|
||||
#define COMP2 4u
|
||||
#define SWEN1 2u
|
||||
#define SWEN2 0u
|
||||
|
||||
// All data bus bits of the FT240X are outputs, except COMP1 and COMP2
|
||||
#define MASK (0xffu & ~(1u << COMP1) & ~(1u << COMP2))
|
||||
|
||||
// Structure for parsed command line options
|
||||
struct opt_struct {
|
||||
uint32_t outputMultiplier; // We output all the entropy when outputMultiplier == 0
|
||||
@@ -46,9 +18,9 @@ struct opt_struct {
|
||||
char *serial; // Name of selected device
|
||||
};
|
||||
|
||||
bool inmHealthCheckStart(uint8_t N, double K, struct opt_struct *opts);
|
||||
void inmHealthCheckStop(void);
|
||||
bool inmHealthCheckAddBit(bool evenBit, bool oddBit, bool even);
|
||||
//bool inmHealthCheckStart(uint8_t N, double K, struct opt_struct *opts);
|
||||
//void inmHealthCheckStop(void);
|
||||
/*bool inmHealthCheckAddBit(bool evenBit, bool oddBit, bool even);
|
||||
bool inmHealthCheckOkToUseData(void);
|
||||
double inmHealthCheckEstimateK(void);
|
||||
double inmHealthCheckEstimateEntropyPerBit(void);
|
||||
@@ -59,7 +31,10 @@ void inmWriteEntropyStart(uint32_t bufLen, struct opt_struct *opts);
|
||||
void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy);
|
||||
void inmWaitForPoolToHaveRoom(void);
|
||||
void inmDumpStats(void);
|
||||
*/
|
||||
void startDaemon(struct opt_struct *opts);
|
||||
bool isSuperUser(void);
|
||||
|
||||
extern double inmK, inmExpectedEntropyPerBit;
|
||||
|
||||
//extern double inmK, inmExpectedEntropyPerBit;
|
||||
|
||||
|
||||
404
software/libinfnoise.c
Normal file
404
software/libinfnoise.c
Normal file
@@ -0,0 +1,404 @@
|
||||
/* Driver 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 <ftdi.h>
|
||||
#include "libinfnoise.h"
|
||||
#include "KeccakF-1600-interface.h"
|
||||
|
||||
// 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) {
|
||||
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)) {
|
||||
fputs("Health check of Infinite Noise Multiplier failed!\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
bytes[i] = byte;
|
||||
}
|
||||
return inmGetEntropyLevel();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Write the bytes to either stdout, or /dev/random.
|
||||
void outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom) {
|
||||
if(!writeDevRandom) {
|
||||
if(fwrite(bytes, 1, length, stdout) != length) {
|
||||
fputs("Unable to write output from Infinite Noise Multiplier\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
inmWaitForPoolToHaveRoom();
|
||||
inmWriteEntropyToPool(bytes, length, entropy);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 *keccakState, uint8_t *bytes, uint8_t *result, uint32_t entropy, bool raw,
|
||||
bool writeDevRandom, uint32_t outputMultiplier, bool noOutput) {
|
||||
//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 (!noOutput) {
|
||||
outputBytes(bytes, BUFLEN/8u, entropy, writeDevRandom);
|
||||
} else {
|
||||
memcpy(result, bytes, BUFLEN/8u * sizeof(uint8_t));
|
||||
//result=bytes;
|
||||
}
|
||||
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);
|
||||
uint8_t dataOut[16u*8u];
|
||||
if(outputMultiplier == 0u) {
|
||||
// Output all the bytes of entropy we have
|
||||
KeccakExtract(keccakState, dataOut, (entropy + 63u)/64u);
|
||||
outputBytes(dataOut, entropy/8u, entropy & 0x7u, writeDevRandom);
|
||||
return entropy/8u;
|
||||
} // todo: write to result array
|
||||
|
||||
// Output 256*outputMultipler bits.
|
||||
uint32_t numBits = outputMultiplier*256u;
|
||||
uint32_t bytesWritten = 0u;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!noOutput) {
|
||||
outputBytes(dataOut, bytesToWrite, entropyThisTime, writeDevRandom);
|
||||
} else {
|
||||
// append data in result array until we have finished squeezing the keccak sponge
|
||||
// its important to have an result array of the approriate size: outputMultiplier*32
|
||||
fprintf(stderr, "bytes written: %d\n", bytesWritten);
|
||||
fprintf(stderr, "bytes to write: %d\n", bytesToWrite);
|
||||
|
||||
//memcpy(result + bytesWritten, dataOut, bytesToWrite * sizeof(uint8_t)); //doesn't work
|
||||
// alternative: loop through dataOut and append array elements to result..
|
||||
for (uint32_t i =0; i < bytesToWrite; i++ ) {
|
||||
fprintf(stderr, " result[%d] = dataOut[%d];\n", bytesWritten + i, i);
|
||||
result[bytesWritten + i] = dataOut[i];
|
||||
}
|
||||
}
|
||||
bytesWritten += bytesToWrite;
|
||||
numBits -= bytesToWrite*8u;
|
||||
entropy -= entropyThisTime;
|
||||
if(numBits > 0u) {
|
||||
KeccakPermutation(keccakState);
|
||||
}
|
||||
}
|
||||
if(bytesWritten != outputMultiplier*(256u/8u)) {
|
||||
fprintf(stderr, "Internal error outputing bytes\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "bytes written: %d\n", bytesWritten);
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
void add_to_list(struct inm_devlist **list, struct infnoise_device **dev) {
|
||||
struct inm_devlist_node *tmp = malloc(sizeof(struct inm_devlist_node ) );
|
||||
tmp->device = (*dev);
|
||||
printf("added serial1: %s\n", (*dev)->serial);
|
||||
tmp->next = (*list)->head;
|
||||
printf("added serial2: %s\n", tmp->device->serial);
|
||||
(*list)->head = tmp;
|
||||
printf("added serial3: %s\n", (*list)->head->device->serial);
|
||||
}
|
||||
|
||||
// Return a list of all infinite noise multipliers found.
|
||||
bool listUSBDevices(struct ftdi_context *ftdic, struct inm_devlist **result, char** message) {
|
||||
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?\n";
|
||||
} else {
|
||||
*message = "Can't find Infinite Noise Multiplier\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (curdev = devlist; curdev != NULL; i++) {
|
||||
//printf("Device: %d, ", 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?\n";
|
||||
}
|
||||
//todo: fprintf(stderr, "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic));
|
||||
return false;
|
||||
}
|
||||
|
||||
// build struct of device descriptor & add to list
|
||||
printf("Manufacturer: %s, Description: %s, Serial: %s\n", manufacturer, description, serial);
|
||||
|
||||
struct infnoise_device *result_dev = malloc(sizeof(struct infnoise_device));
|
||||
|
||||
result_dev->index = i;
|
||||
result_dev->manufacturer = manufacturer;
|
||||
result_dev->product = description;
|
||||
result_dev->serial = serial;
|
||||
|
||||
//printf("debug: %s\n", result_dev);
|
||||
add_to_list(result, &result_dev);
|
||||
|
||||
struct inm_devlist_node *tmp;
|
||||
for ( tmp = (*result)->head; tmp != NULL; tmp=tmp->next) {
|
||||
if (tmp->device->serial != NULL) {
|
||||
printf("%s\n", tmp->device->serial);
|
||||
}
|
||||
//tmp = tmp->next;
|
||||
}
|
||||
|
||||
curdev = curdev->next;
|
||||
}
|
||||
struct inm_devlist_node *tmp;
|
||||
for ( tmp = (*result)->head; tmp != NULL; tmp=tmp->next) {
|
||||
if (tmp->device->serial != NULL) {
|
||||
printf("%s\n", tmp->device->serial);
|
||||
}
|
||||
//tmp = tmp->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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\n";
|
||||
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!\n";
|
||||
}
|
||||
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";
|
||||
} else {
|
||||
*message = "Can't open Infinite Noise Multiplier\n";
|
||||
}
|
||||
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?\n";
|
||||
} else {
|
||||
*message = "Can't find Infinite Noise Multiplier with given serial\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set high baud rate
|
||||
rc = ftdi_set_baudrate(ftdic, 30000);
|
||||
if(rc == -1) {
|
||||
*message = "Invalid baud rate\n";
|
||||
return false;
|
||||
} else if(rc == -2) {
|
||||
*message = "Setting baud rate failed\n";
|
||||
return false;
|
||||
} else if(rc == -3) {
|
||||
*message = "Infinite Noise Multiplier unavailable\n";
|
||||
return false;
|
||||
}
|
||||
rc = ftdi_set_bitmode(ftdic, MASK, BITMODE_SYNCBB);
|
||||
if(rc == -1) {
|
||||
*message = "Can't enable bit-bang mode\n";
|
||||
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\n";
|
||||
return false;
|
||||
}
|
||||
if(ftdi_read_data(ftdic, buf, 64) != 64) {
|
||||
*message = "USB read failed\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t readData(struct ftdi_context *ftdic, uint8_t *keccakState, uint8_t *result, bool raw, uint32_t outputMultiplier, bool debug) {
|
||||
// Endless loop: set SW1EN and SW2EN alternately
|
||||
uint32_t i;
|
||||
uint8_t outBuf[BUFLEN], inBuf[BUFLEN];
|
||||
for(i = 0u; i < BUFLEN; i++) {
|
||||
// Alternate Ph1 and Ph2
|
||||
outBuf[i] = i & 1? (1 << SWEN2) : (1 << SWEN1);
|
||||
}
|
||||
|
||||
uint64_t totalBytesWritten = 0u;
|
||||
struct timespec start;
|
||||
clock_gettime(CLOCK_REALTIME, &start);
|
||||
|
||||
// write clock signal
|
||||
if(ftdi_write_data(ftdic, outBuf, BUFLEN) != BUFLEN) {
|
||||
fputs("USB write failed\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
// and read 512 byte from the internal buffer (in synchronous bitbang mode)
|
||||
if(ftdi_read_data(ftdic, inBuf, BUFLEN) != BUFLEN) {
|
||||
fputs("USB read failed\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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];
|
||||
uint32_t entropy = extractBytes(bytes, inBuf);
|
||||
|
||||
if(inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) {
|
||||
uint64_t prevTotalBytesWritten = totalBytesWritten;
|
||||
totalBytesWritten += processBytes(keccakState, bytes, result, entropy, raw, false, outputMultiplier, true);
|
||||
fprintf(stderr, "bw3: %lu\n", (unsigned long)totalBytesWritten);
|
||||
|
||||
if(debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) {
|
||||
fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalBytesWritten;
|
||||
}
|
||||
|
||||
#ifdef LIB_EXAMPLE_PROGRAM
|
||||
// example use of libinfnoise
|
||||
int main() {
|
||||
// initialize health check
|
||||
if (!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, false)) {
|
||||
fputs("Can't initialize health checker\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// initialize keccak
|
||||
KeccakInitialize();
|
||||
uint8_t keccakState[KeccakPermutationSizeInBytes];
|
||||
KeccakInitializeState(keccakState);
|
||||
|
||||
// initialize USB
|
||||
struct ftdi_context ftdic;
|
||||
char *message;
|
||||
char *serial=NULL; // use any device, can be set to a specific serial
|
||||
if(!initializeUSB(&ftdic, &message, serial)) {
|
||||
// Sometimes have to do it twice - not sure why
|
||||
if(!initializeUSB(&ftdic, &message, serial)) {
|
||||
fputs(message, stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t totalBytesWritten = 0u;
|
||||
|
||||
// parameters for readData(..):
|
||||
bool rawOutput = true;
|
||||
uint32_t multiplier = 10u;
|
||||
bool debug = false;
|
||||
|
||||
// calculate output size based on the parameters:
|
||||
// when using the multiplier, we need a result array of multiplier*32 bytes - otherwise the full buffer size (512 bytes)
|
||||
uint32_t resultSize;
|
||||
if (multiplier == 0 || rawOutput == true) {
|
||||
resultSize = BUFLEN;
|
||||
} else {
|
||||
resultSize = multiplier*32;
|
||||
}
|
||||
fprintf(stderr, "%d\n", resultSize);
|
||||
|
||||
// read and print
|
||||
while (totalBytesWritten < 100000) {
|
||||
fprintf(stderr, "%lu\n", (unsigned long)totalBytesWritten);
|
||||
uint8_t result[resultSize];
|
||||
//uint8_t *result = malloc(resultSize * sizeof(uint8_t)); // array to hold the (whitened) result
|
||||
|
||||
uint64_t bytesWritten = 0u;
|
||||
bytesWritten = readData(&ftdic, keccakState, result, rawOutput, multiplier, debug);
|
||||
fprintf(stderr, "bw2: %lu\n", (unsigned long)bytesWritten);
|
||||
|
||||
totalBytesWritten += bytesWritten;
|
||||
fwrite(result, 1, bytesWritten, stdout);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
111
software/libinfnoise.h
Normal file
111
software/libinfnoise.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <ftdi.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define INFNOISE_VENDOR_ID 0x0403
|
||||
#define INFNOISE_PRODUCT_ID 0x6015
|
||||
|
||||
// Required accuracy of estimated vs measured entropy in health monitor
|
||||
#define INM_ACCURACY 1.03
|
||||
|
||||
// The FT240X has a 512 byte buffer. Must be multiple of 64
|
||||
// We also write this in one go to the Keccak sponge, which is at most 1600 bits
|
||||
#define BUFLEN 512u
|
||||
|
||||
// This is how many previous bits are used to predict the next bit from the INM
|
||||
#define PREDICTION_BITS 14u
|
||||
|
||||
// This is the maximum time we allow to pass to perform the I/O operations, since long
|
||||
// delays can reduce entropy from the INM.
|
||||
#define MAX_MICROSEC_FOR_SAMPLES 5000u
|
||||
|
||||
// This is the gain of each of the two op-amp stages in the INM
|
||||
#define DESIGN_K 1.84
|
||||
|
||||
#define BITMODE_SYNCBB 0x4
|
||||
|
||||
// This defines which pins on the FT240X are used
|
||||
#define COMP1 1u
|
||||
#define COMP2 4u
|
||||
#define SWEN1 2u
|
||||
#define SWEN2 0u
|
||||
|
||||
// All data bus bits of the FT240X are outputs, except COMP1 and COMP2
|
||||
#define MASK (0xffu & ~(1u << COMP1) & ~(1u << COMP2))
|
||||
|
||||
// Structure for parsed command line options
|
||||
struct opt_struct {
|
||||
uint32_t outputMultiplier; // We output all the entropy when outputMultiplier == 0
|
||||
bool daemon; // Run as daemon?
|
||||
bool debug; // Print debugging info?
|
||||
bool devRandom; // Feed /dev/random?
|
||||
bool noOutput; // Supress output?
|
||||
bool listDevices; // List possible USB-devices?
|
||||
bool help; // Show help
|
||||
bool none; // set to true when no valid arguments where detected
|
||||
bool raw; // No whitening?
|
||||
bool version; // Show version
|
||||
char *pidFileName; // Name of optional PID-file
|
||||
char *serial; // Name of selected device
|
||||
};
|
||||
|
||||
// struct for ftdi_device_descriptor
|
||||
struct infnoise_device {
|
||||
uint8_t index;
|
||||
char *manufacturer;
|
||||
char *product;
|
||||
char *serial;
|
||||
};
|
||||
|
||||
|
||||
struct inm_devlist_node
|
||||
{
|
||||
struct infnoise_device *device;
|
||||
struct inm_devlist_node *next;
|
||||
};
|
||||
|
||||
struct inm_devlist
|
||||
{
|
||||
struct inm_devlist_node *head;
|
||||
};
|
||||
|
||||
// struct for list of devices
|
||||
struct infnoise_device_list {
|
||||
struct infnoise_device device;
|
||||
struct infnoise_device_list * next;
|
||||
};
|
||||
|
||||
bool inmHealthCheckStart(uint8_t N, double K, bool debug);
|
||||
void inmHealthCheckStop(void);
|
||||
bool inmHealthCheckAddBit(bool evenBit, bool oddBit, bool even);
|
||||
bool inmHealthCheckOkToUseData(void);
|
||||
double inmHealthCheckEstimateK(void);
|
||||
double inmHealthCheckEstimateEntropyPerBit(void);
|
||||
uint32_t inmGetEntropyLevel(void);
|
||||
void inmClearEntropyLevel(void);
|
||||
bool inmEntropyOnTarget(uint32_t entropy, uint32_t bits);
|
||||
void inmWriteEntropyStart(uint32_t bufLen, bool debug);
|
||||
void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy);
|
||||
void inmWaitForPoolToHaveRoom(void);
|
||||
void inmDumpStats(void);
|
||||
void startDaemon(struct opt_struct *opts);
|
||||
bool isSuperUser(void);
|
||||
|
||||
extern double inmK, inmExpectedEntropyPerBit;
|
||||
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);
|
||||
bool listUSBDevices(struct ftdi_context *ftdic, struct inm_devlist **result, char** message);
|
||||
bool initializeUSB(struct ftdi_context* ftdic, char **message, char *serial);
|
||||
uint32_t processBytes(uint8_t *keccakState, uint8_t *bytes, uint8_t *result, uint32_t entropy, bool raw,
|
||||
bool writeDevRandom, uint32_t outputMultiplier, bool noOutput);
|
||||
BIN
software/libinfnoise.h.gch
Normal file
BIN
software/libinfnoise.h.gch
Normal file
Binary file not shown.
Reference in New Issue
Block a user