Fix merge

This commit is contained in:
Patrick Siegl
2018-06-27 21:57:33 -04:00
25 changed files with 991 additions and 343 deletions

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "software/tests/test_helper/bats-support"]
path = software/tests/test_helper/bats-support
url = https://github.com/ztombol/bats-support
[submodule "software/tests/test_helper/bats-assert"]
path = software/tests/test_helper/bats-assert
url = https://github.com/ztombol/bats-assert

View File

@@ -4,11 +4,10 @@ GIT_DATE := $(firstword $(shell git --no-pager show --date=iso-strict --forma
PREFIX = $(DESTDIR)/usr/local PREFIX = $(DESTDIR)/usr/local
CFLAGS = -Wall -Wextra -Werror -std=c99 -O3 -I Keccak -I /usr/include/libftdi1 \ CFLAGS = -Wall -Wextra -Werror -std=c99 -O3 -fPIC -I Keccak -I /usr/include/libftdi1 \
-DGIT_VERSION=\"$(GIT_VERSION)\"\ -DGIT_VERSION=\"$(GIT_VERSION)\"\
-DGIT_COMMIT=\"$(GIT_COMMIT)\"\ -DGIT_COMMIT=\"$(GIT_COMMIT)\"\
-DGIT_DATE=\"$(GIT_DATE)\"\ -DGIT_DATE=\"$(GIT_DATE)\"\
-DBUILD_DATE=\"$(BUILD_DATE)\"
FOUND = $(shell /sbin/ldconfig -p | grep --silent libftdi.so && echo found) FOUND = $(shell /sbin/ldconfig -p | grep --silent libftdi.so && echo found)
ifeq ($(FOUND), found) ifeq ($(FOUND), found)
@@ -17,15 +16,42 @@ else
FTDI= -lftdi1 FTDI= -lftdi1
endif endif
all: infnoise all: libinfnoise.a libinfnoise.so infnoise
infnoise: infnoise.c infnoise.h healthcheck.c writeentropy.c daemon.c Keccak/KeccakF-1600-reference.c Keccak/brg_endian.h infnoise: libinfnoise.a infnoise.o daemon.o
$(CC) $(CFLAGS) -o infnoise infnoise.c healthcheck.c writeentropy.c daemon.c Keccak/KeccakF-1600-reference.c $(FTDI) -lm -lrt $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -lrt -L. -linfnoise
%.o: %.c infnoise.h libinfnoise.h
$(CC) -c -o $@ $< $(CFLAGS)
KeccakF-1600-reference.o: Keccak/KeccakF-1600-reference.c Keccak/KeccakF-1600-interface.h Keccak/brg_endian.h
$(CC) -c -o $@ $< $(CFLAGS)
# static lib compiled into infnoise binary
libinfnoise.o: libinfnoise.c libinfnoise.h libinfnoise_private.h healthcheck.c
$(CC) $(CFLAGS) -c libinfnoise.c
libinfnoise.a: libinfnoise.o healthcheck.o KeccakF-1600-reference.o writeentropy.o
ar rcs libinfnoise.a libinfnoise.o healthcheck.o KeccakF-1600-reference.o writeentropy.o
ranlib libinfnoise.a
# shared lib
libinfnoise.so: libinfnoise.o healthcheck.o KeccakF-1600-reference.o writeentropy.o
$(CC) $(CFLAGS) -fvisibility=hidden -o libinfnoise.so libinfnoise.o healthcheck.o KeccakF-1600-reference.o writeentropy.o -Wl,--version-script=libinfnoise.version $(FTDI) -lm -shared
libs: libinfnoise.a
clean: clean:
$(RM) infnoise $(RM) infnoise *.o *.a *.gch *.so libinfnoise-example
install: install-lib: libinfnoise.so
install -d $(PREFIX)/include
install -m 0644 libinfnoise.h $(PREFIX)/include
install -d $(PREFIX)/lib
install -m 0644 libinfnoise.so $(PREFIX)/lib
ldconfig $(PREFIX)/lib
install: infnoise
install -d $(PREFIX)/sbin install -d $(PREFIX)/sbin
install -m 0755 infnoise $(PREFIX)/sbin/ install -m 0755 infnoise $(PREFIX)/sbin/
install -d $(PREFIX)/lib/udev/rules.d/ install -d $(PREFIX)/lib/udev/rules.d/

View File

@@ -7,7 +7,7 @@ and can create packages of the following types:
- RPM (CentOS, Fedora) - RPM (CentOS, Fedora)
- ArchLinux - ArchLinux
The packages get signed afterwards and made available as Github releases The packages are signed and made available as Github releases
and via the apt repository described in software/README. and via the apt repository described in software/README.
During the build the GitHub release and version information are compiled into the binary. During the build the GitHub release and version information are compiled into the binary.

View File

@@ -59,3 +59,24 @@ echo "Architecture: $ARCH" >> build/DEBIAN/control
dpkg -b build/ infnoise-tools_${VERSION}_${ARCH}.deb dpkg -b build/ infnoise-tools_${VERSION}_${ARCH}.deb
rm -rf build rm -rf build
cd ..
### build libinfnoise ###
rm -rf build
mkdir -p build/usr/lib
mkdir -p build/usr/include
make libinfnoise.so
cp libinfnoise.so build/usr/lib/
cp libinfnoise.h build/usr/include
mkdir -p build/DEBIAN
cp build-scripts/control.debian.lib build/DEBIAN/control
echo "Version: $VERSION" >> build/DEBIAN/control
echo "Architecture: $ARCH" >> build/DEBIAN/control
dpkg -b build/ libinfnoise_${VERSION}_${ARCH}.deb
rm -rf build

View File

@@ -0,0 +1,8 @@
Package: libinfnoise
Essential: no
Section: security
Depends: libftdi1
Priority: optional
Maintainer: Manuel Domke
Installed-Size: 12K
Description: Infinite Noise TRNG library

View File

@@ -48,6 +48,3 @@ void startDaemon(struct opt_struct* opts) {
// Child // Child
} }
bool isSuperUser(void) {
return (geteuid() == 0);
}

View File

@@ -0,0 +1,26 @@
# Usage examples for Infinite Noise
## Integrate the binary to python
See the python examples `serial-numbers.py` and `randomserver.py` to see how you could integrate it with python.
#### serial-numbers.py
An extended version of this script was used to generate the serial numbers of all Infinite Noise's made by 13-37.org. The numbers generated by this simpler one are not guaranteed to be unique, thats why I use the UNIQUE constraint of a database when storing them.
This simple version just prints the serials to stdout. Call like this:
$ ./serial-numbers.py -c 3 -l 8
0A8BBA15
0341F762
813DC0BD
#### randomserver.py
A simple webserver based on the web.py framework to serve random data via a REST interface. An example is hosted at https://rng.13-37.org (running on a Raspberry Pi in Amsterdam, thanks to pcextreme.nl!)
It has only two resources: `/get` and `/status`.
## libinfnoise
TODO

View File

@@ -0,0 +1,26 @@
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))
PREFIX = $(DESTDIR)/usr/local
CFLAGS = -Wall -Wextra -Werror -std=c99 -O3 -fPIC -I Keccak -I /usr/include/libftdi1 \
-DGIT_VERSION=\"$(GIT_VERSION)\"\
-DGIT_COMMIT=\"$(GIT_COMMIT)\"\
-DGIT_DATE=\"$(GIT_DATE)\"\
LDFLAGS= -shared
FTDI := $(shell libftdi-config --libs)
all: libinfnoise-example libinfnoise-example-raw
libinfnoise-example: example.c
$(CC) $(CFLAGS) -o libinfnoise-example example.c $(FTDI) -lm -lrt -linfnoise
libinfnoise-example-raw: example.c
$(CC) $(CFLAGS) -o libinfnoise-example-raw example-raw.c $(FTDI) -lm -lrt -linfnoise
clean:
$(RM) libinfnoise-example* *.o

View File

@@ -0,0 +1,46 @@
/*
This is a very simple example to use libinfnoise in raw output mode.
*/
#include <stdio.h>
#include <ftdi.h>
#include <libinfnoise.h>
int main()
{
// parameters
char *serial=NULL; // can be set to a specific serial, NULL uses the first found device
bool debug=true; // debug mode (health monitor writes to stderr)
char *message;
bool errorFlag = false;
// initialize hardware and health monitor
struct ftdi_context ftdic;
if (!initInfnoise(&ftdic, serial, &message, false, debug)) {
fputs(message, stderr);
return 1; // ERROR
}
// read and print in a loop (until 1M)
uint32_t totalBytesWritten = 0;
while (totalBytesWritten < 1000000) {
uint8_t result[64];// result is always 64 bytes in raw mode
// read data returns the number of bytes written to result array
uint64_t bytesWritten = readRawData(&ftdic, result, &message, &errorFlag);
totalBytesWritten += bytesWritten;
// check for errors
// note: bytesWritten is also 0 in this case, but an errorFlag is needed as
// bytesWritten can also be 0 when data hasn't passed the health monitor.
if (errorFlag) {
fprintf(stderr, "Error: %s\n", message);
return 1;
}
// print bytes to stdout
fwrite(result, 1, bytesWritten, stdout);
}
return 0;
}

View File

@@ -0,0 +1,57 @@
/*
This is a simple example to use libinfnoise with whitened and multiplied output.
*/
#include <stdio.h>
#include <ftdi.h>
#include <libinfnoise.h>
int main()
{
// parameters
char *serial=NULL; // can be set to a specific serial, NULL uses the first found device
bool initKeccak = true; // initialize Keccak sponge (used for whitening)
uint32_t multiplier = 10u; // multiplier for whitening
bool debug = false; // debug mode (health monitor writes to stderr)
char *message;
bool errorFlag = false;
// initialize hardware and health monitor
struct ftdi_context ftdic;
if (!initInfnoise(&ftdic, serial, &message, true, debug)) {
fputs(message, stderr);
return 1; // ERROR
}
// 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 || initKeccak == false) {
resultSize = BUFLEN/8u;
} else {
resultSize = multiplier*32u;
}
// read and print in a loop (until 1M is read)
uint64_t totalBytesWritten = 0u;
while (totalBytesWritten < 1000000) {
uint8_t result[resultSize];
// readRawData returns the number of bytes written to result array
uint64_t bytesWritten = readData(&ftdic, result, &message, &errorFlag, multiplier);
totalBytesWritten += bytesWritten;
// check for errors
// note: bytesWritten is also 0 in this case, but an errorFlag is needed as
// bytesWritten can also be 0 when data hasn't passed the health monitor.
if (errorFlag) {
fprintf(stderr, "Error: %s\n", message);
return 1;
}
// print as many bytes
fwrite(result, 1, bytesWritten, stdout);
}
return 0;
}

View File

@@ -0,0 +1,94 @@
#!/usr/bin/python
import shlex
import subprocess
from threading import Thread
import time
import web
urls = (
'/', 'help',
'/get', 'GetRandomData',
# '/reg', 'Register',
'/status', 'GetPoolStatus'
)
RESPONSE_SIZE=8192
MIN_POOL_SIZE=1 # in MB
MAX_POOL_SIZE=32 # in MB
class help:
def GET(self):
message= "<html><head>"
message+= "<title>Infinite Noise webservice</title></head>"
message+= "<body><h1>Usage:</h1><table border=1>"
message+= "<tr><td><b>request</b></td><td><b>help</b></td></tr>"
message+= "<tr><td>/status</td><td>show current buffer status</td></tr>"
message+= "<tr><td>/get</td><td>get " + str(RESPONSE_SIZE) + "bytes (binary format)</td></tr>"
# print "<td><tr>/reg</tr><tr>todo</tr></td>"
message+= "</table>"
message+= "</body></html>"
return message
class GetRandomData:
def GET(self):
return POOL.getData()
class GetPoolStatus:
def GET(self):
return POOL.getStatus()
class RandPool(object):
minPoolSize = (MIN_POOL_SIZE * 1024 * 1024) / RESPONSE_SIZE
maxPoolSize = (MAX_POOL_SIZE * 1024 * 1024) / RESPONSE_SIZE
poolFillmark = -1
randomPool = list()
process = None
do_run = True
def __init__(self):
command = "sudo /usr/sbin/infnoise --multiplier 10"
self.process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
for i in range(0, self.minPoolSize):
self.randomPool.append(self.process.stdout.read(RESPONSE_SIZE))
self.poolFillmark+= 1
thread2 = Thread(target=self.monitorPool)
thread2.start()
def monitorPool(self):
while getattr(self, "do_run", True):
if self.poolFillmark < self.maxPoolSize: # keep pool at 100%
print(str(self.poolFillmark)+ "/" + str(self.maxPoolSize))
self.__refill_pool__()
time.sleep(1)
print("Stopping as you wish.")
self.process.kill()
def __refill_pool__(self):
print("refilling pool - current level: " + str(self.poolFillmark))
for i in range(self.poolFillmark, self.maxPoolSize):
self.randomPool.append(self.process.stdout.read(RESPONSE_SIZE))
self.poolFillmark += 1
self.randomPool.reverse()
print("refilled pool - new level: " + str(self.poolFillmark))
def getData(self):
if self.poolFillmark <= 0:
web.ctx.status = '503 Service currently unavailable - Out of entropy error'
return "0"
value = self.randomPool[self.poolFillmark]
self.randomPool[self.poolFillmark] = None
self.poolFillmark -= 1
return value
def getStatus(self):
return str(self.poolFillmark) + "/" + str(self.maxPoolSize)
POOL = RandPool()
if __name__ == '__main__':
app = web.application(urls, globals())
app.run()
POOL.do_run = False

View File

@@ -0,0 +1,36 @@
#!/usr/bin/python
import subprocess
import argparse
parser = argparse.ArgumentParser(description='Generate random serial numbers')
parser.add_argument('-l', dest='length', action='store', default=8,
help='length of each serial number', type=int)
parser.add_argument('-c', dest='count', action='store', default=10,
help='length of each serial number', type=int)
def main():
args = parser.parse_args() # parse arguments
unique_serials_generated = 0 # counter for serials inserted successfully.
while unique_serials_generated < args.count: # loop until enough unique serials are created (because some could fail)
serials_list = readHexStrings(args.count - unique_serials_generated, args.length) # read $count hex-strings of fixed $length
for serial in serials_list:
if ("\n" in serial) or (" " in serial):
continue # dont use serials with newlines or spaces
unique_serials_generated += 1 # counter for serials
serial = serial.upper()
print(serial)
def readHexStrings(count, length):
list = []
infnoise_proc = subprocess.Popen(["infnoise"], stdout=subprocess.PIPE) # run infinite noise driver and
bin2hex_proc = subprocess.Popen(["infnoise-bin2hex"], stdin=infnoise_proc.stdout, # feed its stdout to the bin2hex utility,
stdout=subprocess.PIPE) # you could also skip this and do the bin2hex conversion in python
while len(list) < count and infnoise_proc.poll() == None:
list.append(bin2hex_proc.stdout.read(length))
infnoise_proc.terminate()
bin2hex_proc.terminate()
return list
if __name__ == '__main__':
main()

View File

@@ -24,7 +24,7 @@ confirmed.
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "infnoise.h" #include "libinfnoise_private.h"
#define INM_MIN_DATA 80000u #define INM_MIN_DATA 80000u
#define INM_MIN_SAMPLE_SIZE 100u #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. // 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 // 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. // 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) { if(N < 1u || N > 30u) {
return false; return false;
} }
inmDebug = opts->debug; inmDebug = debug;
inmNumBitsOfEntropy = 0u; inmNumBitsOfEntropy = 0u;
inmCurrentProbability = 1.0; inmCurrentProbability = 1.0;
inmK = K; inmK = K;
@@ -297,6 +297,7 @@ bool inmEntropyOnTarget(uint32_t entropy, uint32_t numBits) {
} }
#ifdef TEST_HEALTHCHECK #ifdef TEST_HEALTHCHECK
#include "infnoise.h"
// Compare the ability to predict with 1 fewer bits and see how much less accurate we are. // Compare the ability to predict with 1 fewer bits and see how much less accurate we are.
static void checkLSBStatsForNBits(uint8_t N) { static void checkLSBStatsForNBits(uint8_t N) {
@@ -375,7 +376,7 @@ int main() {
//double K = sqrt(2.0); //double K = sqrt(2.0);
double K = 1.82; double K = 1.82;
uint8_t N = 16u; uint8_t N = 16u;
inmHealthCheckStart(N, K, &opts); inmHealthCheckStart(N, K, false);
srand(time(NULL)); srand(time(NULL));
double A = (double)rand()/RAND_MAX; // Simulating INM double A = (double)rand()/RAND_MAX; // Simulating INM
double noiseAmplitude = 1.0/(1u << 10); double noiseAmplitude = 1.0/(1u << 10);

View File

@@ -3,9 +3,6 @@
// Required to include clock_gettime // Required to include clock_gettime
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#define INFNOISE_VENDOR_ID 0x0403
#define INFNOISE_PRODUCT_ID 0x6015
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@@ -16,229 +13,17 @@
#include <sys/types.h> #include <sys/types.h>
#include <ftdi.h> // requires <sys/types.h> #include <ftdi.h> // requires <sys/types.h>
#include "infnoise.h" #include "infnoise.h"
#include "libinfnoise.h"
#include "libinfnoise_private.h"
#include "KeccakF-1600-interface.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) { static void initOpts(struct opt_struct *opts) {
opts->outputMultiplier = 0u; opts->outputMultiplier = 0u;
opts->daemon = opts->daemon = false;
opts->debug = opts->debug = false;
opts->devRandom = opts->devRandom = false;
opts->noOutput = opts->noOutput = false;
opts->listDevices = opts->listDevices = false;
opts->raw = false; opts->raw = false;
opts->version = false; opts->version = false;
opts->help = false; opts->help = false;
@@ -247,13 +32,6 @@ static void initOpts(struct opt_struct *opts) {
opts->serial = NULL; 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) int main(int argc, char **argv)
{ {
struct ftdi_context ftdic; struct ftdi_context ftdic;
@@ -332,7 +110,6 @@ int main(int argc, char **argv)
} }
} }
// read environment variables, not overriding command line options // read environment variables, not overriding command line options
if (opts.serial == NULL) { if (opts.serial == NULL) {
if (getenv("INFNOISE_SERIAL") != NULL) { if (getenv("INFNOISE_SERIAL") != NULL) {
@@ -371,69 +148,44 @@ int main(int argc, char **argv)
return 0; return 0;
} }
char *message = "no data?";
bool errorFlag = false;
if (opts.listDevices) { if (opts.listDevices) {
listUSBDevices(&ftdic); 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; return 0;
} }
if (opts.devRandom) {
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 // Optionally run in the background and optionally write a PID-file
startDaemon(&opts); startDaemon(&opts);
if(opts.devRandom) { // initialize USB device, health check and Keccak state (see libinfnoise)
inmWriteEntropyStart(BUFLEN/8u, &opts); if (!initInfnoise(&ftdic, opts.serial, &message, !opts.raw, opts.debug)) {
} fputs(message, stderr);
return 1; // ERROR
if(!inmHealthCheckStart(PREDICTION_BITS, DESIGN_K, &opts)) {
fputs("Can't intialize 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)) {
fputs(message, stderr);
return 1;
}
}
// 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);
} }
// endless loop
uint64_t totalBytesWritten = 0u; uint64_t totalBytesWritten = 0u;
while(true) { while(true) {
struct timespec start; uint64_t prevTotalBytesWritten = totalBytesWritten;
clock_gettime(CLOCK_REALTIME, &start); totalBytesWritten += readData_private(&ftdic, NULL, &message, &errorFlag, opts.noOutput, opts.raw, opts.outputMultiplier, opts.devRandom); // calling libinfnoise's private readData method
if(ftdi_write_data(&ftdic, outBuf, BUFLEN) != BUFLEN) { if (errorFlag) {
fputs("USB write failed\n", stderr); fprintf(stderr, "Error: %s\n", message);
return 1; return 1;
} }
if(ftdi_read_data(&ftdic, inBuf, BUFLEN) != BUFLEN) {
fputs("USB read failed\n", stderr); if(opts.debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) {
return 1; fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten);
}
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(!opts.noOutput && inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) {
uint64_t prevTotalBytesWritten = totalBytesWritten;
totalBytesWritten += processBytes(keccakState, bytes, entropy, &opts);
if(opts.debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) {
fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten);
}
}
} }
} }
return 0; return 0;

View File

@@ -1,34 +1,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <ftdi.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 // Structure for parsed command line options
struct opt_struct { struct opt_struct {
@@ -46,20 +19,4 @@ struct opt_struct {
char *serial; // Name of selected device 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 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, 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); void startDaemon(struct opt_struct *opts);
bool isSuperUser(void);
extern double inmK, inmExpectedEntropyPerBit;

418
software/libinfnoise.c Normal file
View File

@@ -0,0 +1,418 @@
/* 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 <ftdi.h>
#include "libinfnoise_private.h"
#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, 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;
return 0;
}
}
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.
bool outputBytes(uint8_t *bytes, uint32_t length, uint32_t entropy, bool writeDevRandom, char **message) {
if(!writeDevRandom) {
if(fwrite(bytes, 1, length, stdout) != length) {
*message = "Unable to write output from Infinite Noise Multiplier";
return false;
}
} else {
inmWaitForPoolToHaveRoom();
inmWriteEntropyToPool(bytes, length, entropy);
}
return true;
}
bool isSuperUser(void) {
return (geteuid() == 0);
}
// 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, 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) {
entropy = inmExpectedEntropyPerBit*BUFLEN/INM_ACCURACY;
}
if(raw) {
// In raw mode, we just output raw data from the INM.
if (!noOutput) {
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));
}
}
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);
if (!noOutput) {
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));
}
}
return entropy/8u;
}
// 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) {
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..
if (result != NULL) {
for (uint32_t i =0; i < bytesToWrite; i++ ) {
result[bytesWritten + i] = dataOut[i];
}
}
}
bytesWritten += bytesToWrite;
numBits -= bytesToWrite*8u;
entropy -= entropyThisTime;
if(numBits > 0u) {
KeccakPermutation(keccakState);
}
}
if(bytesWritten != outputMultiplier*(256u/8u)) {
*message = "Internal error outputing bytes";
*errorFlag = true;
return 0;
}
return bytesWritten;
}
// Return a list of all infinite noise multipliers found.
bool listUSBDevices(struct ftdi_context *ftdic, 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?";
} else {
*message = "Can't find Infinite Noise Multiplier";
}
}
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?";
return false;
}
//*message = "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic));
return false;
}
// print to stdout
printf("Manufacturer: %s, Description: %s, Serial: %s", manufacturer, description, serial);
curdev = curdev->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";
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 {
*message = "Can't open Infinite Noise Multiplier";
}
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 readRawData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag) {
return readData_private(ftdic, result, message, errorFlag, false, true, 0, 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);
}
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];
struct timespec start;
clock_gettime(CLOCK_REALTIME, &start);
// write clock signal
if(ftdi_write_data(ftdic, outBuf, BUFLEN) != BUFLEN) {
*message = "USB write failed";
*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";
*errorFlag = true;
}
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, message, errorFlag);
// call health check and process bytes if OK
if (inmHealthCheckOkToUseData() && inmEntropyOnTarget(entropy, BUFLEN)) {
uint32_t byteswritten = processBytes(bytes, result, entropy, raw, devRandom, outputMultiplier, noOutput, message, errorFlag);
return byteswritten;
}
}
return 0;
}
#ifdef LIB_EXAMPLE_PROGRAM
// example use of libinfnoise - with keccak
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

17
software/libinfnoise.h Normal file
View File

@@ -0,0 +1,17 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <ftdi.h>
#include <time.h>
// 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
bool listUSBDevices(struct ftdi_context *ftdic, char **message);
bool initInfnoise(struct ftdi_context *ftdic, char *serial, char **message, bool keccak, bool debug);
uint32_t readRawData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag);
uint32_t readData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag, uint32_t outputMultiplier);

View File

@@ -0,0 +1,5 @@
libinfnoise {
global: listUSBDevices; initInfnoise; readRawData; readData; # explicitly list symbols to be exported
local: *; # hide everything else
};

View File

@@ -0,0 +1,64 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <ftdi.h>
#include <time.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
// 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))
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);
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, char **message, bool *errorFlag);
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);

1
software/tests/README Normal file
View File

@@ -0,0 +1 @@
bats tests for the binary driver.

View File

@@ -0,0 +1,87 @@
#!/usr/bin/env bats
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
# Tests for the infnoise binary
@test "test --raw output for expected entropy" {
# capture some data
TMP_FILE=`mktemp -u $BATS_TMPDIR/infnoise-test-XXXXXXX`
timeout 5s ./infnoise --raw > $TMP_FILE || true
# run ent
run ent $TMP_FILE
assert_line --index 0 --regexp '^Entropy = 7.2[5-9][0-9]+ bits per byte.$'
# cleanup
rm $TMP_FILE
}
@test "test whitened output for expected entropy" {
# capture some data
TMP_FILE=`mktemp -u $BATS_TMPDIR/infnoise-test-XXXXXXX`
timeout 5s ./infnoise > $TMP_FILE || true
# run ent
run ent $TMP_FILE
# check ent's result
assert_line --index 0 --regexp '^Entropy = 7.99[0-9]+ bits per byte.$'
# cleanup
rm $TMP_FILE
}
@test "test whitened output (multiplier=10) for expected entropy" {
# capture some data
TMP_FILE=`mktemp -u $BATS_TMPDIR/infnoise-test-XXXXXXX`
timeout 5s ./infnoise --multiplier 10 > $TMP_FILE || true
# run ent
run ent $TMP_FILE
assert_line --index 0 --regexp '^Entropy = 7.99[0-9]+ bits per byte.$'
# cleanup
rm $TMP_FILE
}
@test "test --no-output --debug" {
# capture some data
TMP_FILE=`mktemp -u $BATS_TMPDIR/infnoise-test-XXXXXXX`
run timeout 5s ./infnoise --no-output --debug
echo $output
[ "$status" -eq 124 ]
assert_line --index 0 --regexp '^Generated 1048576 bits. OK to use data. Estimated entropy per bit: 0\.[0-8][6-8][0-9]+, estimated K: 1\.8[1-5][0-9]+$'
assert_line --index 1 --regexp '^num1s:50.[0-9]+%, even misfires:0.[0-1][0-9]+%, odd misfires:0.[0-1][0-9]+%$'
}
@test "test --list-devices" {
run ./infnoise --list-devices
echo $output
[ "$status" -eq 0 ]
# FTDI serial:
assert_line --index 1 --regexp '^Manufacturer: FTDI, Description: FT240X USB FIFO, Serial: [0-9A-Z]+$'
# 13-37.org serial:
assert_line --index 0 --regexp '^Manufacturer: 13-37.org, Description: Infinite Noise TRNG, Serial: [0-9A-F]+$'
}
@test "test --serial with not connected serial (results in error)" {
run ./infnoise --serial 4711
echo $output
[ "$status" -eq 1 ]
[ "${lines[0]}" = "Can't find Infinite Noise Multiplier. Try running as super user?" ]
}
@test "test --help" {
run ./infnoise --help
echo $output
[ "$status" -eq 0 ]
[ "${lines[0]}" = "Usage: infnoise [options]" ]
}

View File

@@ -35,10 +35,10 @@ int main(int argc, char **argv) {
uint32_t i; uint32_t i;
printf("password:"); printf("password:");
for (i = 0u; i < keys; i++) { for (i = 0u; i < keys; i++) {
uint32_t randVal = rollDie(26u, file); uint32_t randVal = rollDie(32u, file);
putchar('a' + randVal); putchar('a' + randVal);
} }
printf("\nThis password has %.2f bits of entropy\n", log(pow(26.0, keys))/log(2)); printf("\nThis password has %.2f bits of entropy\n", log(pow(32.0, keys))/log(2));
fclose(file); fclose(file);
return 0; return 0;
} }

View File

@@ -8,7 +8,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/random.h> #include <linux/random.h>
#include "infnoise.h" #include "libinfnoise.h"
#define SIZE_PROC_FILENAME "/proc/sys/kernel/random/poolsize" #define SIZE_PROC_FILENAME "/proc/sys/kernel/random/poolsize"
#define FILL_PROC_FILENAME "/proc/sys/kernel/random/write_wakeup_threshold" #define FILL_PROC_FILENAME "/proc/sys/kernel/random/write_wakeup_threshold"
@@ -40,9 +40,10 @@ static uint32_t readNumberFromFile(char *fileName) {
} }
// Open /dev/random // Open /dev/random
void inmWriteEntropyStart(uint32_t bufLen, struct opt_struct* opts) { void inmWriteEntropyStart(uint32_t bufLen, bool debug) {
inmBufLen = bufLen; inmBufLen = bufLen;
inmDebug = opts->debug; inmDebug = debug;
//inmDevRandomFD = open("/dev/random", O_WRONLY); //inmDevRandomFD = open("/dev/random", O_WRONLY);
inmDevRandomFD = open("/dev/random", O_RDWR); inmDevRandomFD = open("/dev/random", O_RDWR);
if(inmDevRandomFD < 0) { if(inmDevRandomFD < 0) {