diff --git a/software/Makefile.freebsd b/software/Makefile.freebsd index c7b42fd..6be34e2 100644 --- a/software/Makefile.freebsd +++ b/software/Makefile.freebsd @@ -20,7 +20,7 @@ RM=rm all: libinfnoise.a libinfnoise.so infnoise infnoise: libinfnoise.a infnoise.o daemon.o - $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -L. -L $(FTDILOCL) + $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -L. -L $(FTDILOCL) %.o: %.c infnoise.h libinfnoise.h $(CC) -c -o $@ $< $(CFLAGS) diff --git a/software/Makefile.linux b/software/Makefile.linux index 71b774c..4339ac2 100644 --- a/software/Makefile.linux +++ b/software/Makefile.linux @@ -20,7 +20,7 @@ endif all: libinfnoise.a libinfnoise.so infnoise infnoise: libinfnoise.a infnoise.o daemon.o - $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -lrt -L. -linfnoise + $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -lrt -L. %.o: %.c infnoise.h libinfnoise.h $(CC) -c -o $@ $< $(CFLAGS) diff --git a/software/Makefile.macos b/software/Makefile.macos index 1d40e7b..aa696ec 100644 --- a/software/Makefile.macos +++ b/software/Makefile.macos @@ -20,7 +20,7 @@ RM=rm all: libinfnoise.a libinfnoise.so infnoise infnoise: libinfnoise.a infnoise.o daemon.o - $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -L. -L $(FTDILOCL) -linfnoise + $(CC) $(CFLAGS) -o infnoise infnoise.o daemon.o libinfnoise.a $(FTDI) -lm -L. -L $(FTDILOCL) %.o: %.c infnoise.h libinfnoise.h $(CC) -c -o $@ $< $(CFLAGS) diff --git a/software/README b/software/README.md similarity index 92% rename from software/README rename to software/README.md index e89f5b3..da46449 100644 --- a/software/README +++ b/software/README.md @@ -76,19 +76,19 @@ with the stable release for now. Usage ----- -Usage: infnoise [options] -Options are: - --debug - turn on some debug output - --dev-random - write entropy to /dev/random instead of stdout - --raw - do not whiten the output - --multiplier - write 256 bits * value for each 512 bits written to the Keccak sponge - --no-output - do not write random output data - --daemon - run in the background. Output should be redirected to a file or - the options should be used with --dev-random. To reduce CPU-usage addition - af entropy is only forced after a minute rather than a second. - --pidfile - write the process ID to a file. If --daemon is used, it is the ID of the background process. - --serial - use Infinite Noise TRNG/FT240 with the given serial number (see --list-devices) - --list-devices - list available devices + Usage: infnoise [options] + Options are: + --debug - turn on some debug output + --dev-random - write entropy to /dev/random instead of stdout + --raw - do not whiten the output + --multiplier - write 256 bits * value for each 512 bits written to the Keccak sponge + --no-output - do not write random output data + --daemon - run in the background. Output should be redirected to a file or + the options should be used with --dev-random. To reduce CPU-usage addition + af entropy is only forced after a minute rather than a second. + --pidfile - write the process ID to a file. If --daemon is used, it is the ID of the background process. + --serial - use Infinite Noise TRNG/FT240 with the given serial number (see --list-devices) + --list-devices - list available devices Note: The options --daemon and --pidfile are only implemented in the Linux version. diff --git a/software/build-scripts/infnoise-gitian.yml b/software/build-scripts/infnoise-gitian.yml new file mode 100644 index 0000000..93ce084 --- /dev/null +++ b/software/build-scripts/infnoise-gitian.yml @@ -0,0 +1,181 @@ +xy--- +name: "infnoise-linux-dev" +enable_cache: true +suites: +- "bionic" +architectures: +- "amd64" +packages: +- "g++-aarch64-linux-gnu" +- "g++-7-aarch64-linux-gnu" +- "gcc-7-aarch64-linux-gnu" +- "binutils-aarch64-linux-gnu" +- "g++-arm-linux-gnueabihf" +- "g++-7-arm-linux-gnueabihf" +- "gcc-7-arm-linux-gnueabihf" +- "binutils-arm-linux-gnueabihf" +- "g++-7-multilib" +- "gcc-7-multilib" +- "binutils-gold" +- "git" +- "pkg-config" +- "faketime" +- "bsdmainutils" +- "ca-certificates" +- "python" +- "libftdi-dev" +remotes: +- "url": "https://github.com/13-37-org/infnoise" + "dir": "infnoise" +files: [] +script: | + WRAP_DIR=$HOME/wrapped + HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu" + CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests" + FAKETIME_HOST_PROGS="" + FAKETIME_PROGS="date ar ranlib nm" + HOST_CFLAGS="-O2 -g" + HOST_CXXFLAGS="-O2 -g" + HOST_LDFLAGS=-static-libstdc++ + export QT_RCC_TEST=1 + export GZIP="-9n" + export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME"" + export TZ="UTC" + export BUILD_DIR=`pwd` + mkdir -p ${WRAP_DIR} + if test -n "$GBUILD_CACHE_ENABLED"; then + export SOURCES_PATH=${GBUILD_COMMON_CACHE} + export BASE_CACHE=${GBUILD_PACKAGE_CACHE} + mkdir -p ${BASE_CACHE} ${SOURCES_PATH} + fi + function create_global_faketime_wrappers { + for prog in ${FAKETIME_PROGS}; do + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog} + echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${prog} + chmod +x ${WRAP_DIR}/${prog} + done + } + function create_per-host_faketime_wrappers { + for i in $HOSTS; do + for prog in ${FAKETIME_HOST_PROGS}; do + echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog} + echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog} + echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog} + echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog} + echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog} + chmod +x ${WRAP_DIR}/${i}-${prog} + done + done + } + # Faketime for depends so intermediate results are comparable + export PATH_orig=${PATH} + create_global_faketime_wrappers "2000-01-01 12:00:00" + create_per-host_faketime_wrappers "2000-01-01 12:00:00" + export PATH=${WRAP_DIR}:${PATH} + EXTRA_INCLUDES_BASE=$WRAP_DIR/extra_includes + mkdir -p $EXTRA_INCLUDES_BASE + # x86 needs /usr/include/i386-linux-gnu/asm pointed to /usr/include/x86_64-linux-gnu/asm, + # but we can't write there. Instead, create a link here and force it to be included in the + # search paths by wrapping gcc/g++. + mkdir -p $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu + rm -f $WRAP_DIR/extra_includes/i686-pc-linux-gnu/asm + ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu/asm + for prog in gcc g++; do + rm -f ${WRAP_DIR}/${prog} + + cat << EOF > ${WRAP_DIR}/${prog} + #!/usr/bin/env bash + REAL="`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1`" + for var in "\$@" + do + if [ "\$var" = "-m32" ]; then + export C_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" + export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu" + break + fi + done + \$REAL \$@ + EOF + + chmod +x ${WRAP_DIR}/${prog} + done + cd infnoise/software + + BASEPREFIX=`pwd`/depends + + # Build dependencies for each host + for i in $HOSTS; do + EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i" + if [ -d "$EXTRA_INCLUDES" ]; then + export HOST_ID_SALT="$EXTRA_INCLUDES" + fi + make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" + unset HOST_ID_SALT + done + + # Faketime for binaries + export PATH=${PATH_orig} + create_global_faketime_wrappers "${REFERENCE_DATETIME}" + create_per-host_faketime_wrappers "${REFERENCE_DATETIME}" + export PATH=${WRAP_DIR}:${PATH} + + # Create the release tarball using (arbitrarily) the first host + ./autogen.sh + CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/ + make dist + SOURCEDIST=`echo bitcoin-*.tar.gz` + DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'` + # Correct tar file order + mkdir -p temp + pushd temp + tar xf ../$SOURCEDIST + find infnoise-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST + popd + # Workaround for tarball not building with the bare tag version (prep) + make -C src obj/build.h + ORIGPATH="$PATH" + + # Extract the release tarball into a dir for each host and build + for i in ${HOSTS}; do + export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} + mkdir -p distsrc-${i} + cd distsrc-${i} + INSTALLPATH=`pwd`/installed/${DISTNAME} + mkdir -p ${INSTALLPATH} + tar --strip-components=1 -xf ../$SOURCEDIST + + # Workaround for tarball not building with the bare tag version + echo '#!/bin/true' >share/genbuild.sh + mkdir src/obj + cp ../src/obj/build.h src/obj/ + + CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}" + make ${MAKEOPTS} + make ${MAKEOPTS} -C src check-security + + #TODO: This is a quick hack that disables symbol checking for arm. + # Instead, we should investigate why these are popping up. + # For aarch64, we'll need to bump up the min GLIBC version, as the abi + # support wasn't introduced until 2.17. + case $i in + aarch64-*) : ;; + arm-*) : ;; + *) make ${MAKEOPTS} -C src check-symbols ;; + esac + make install DESTDIR=${INSTALLPATH} + cd installed + find . -name "lib*.la" -delete + find . -name "lib*.a" -delete + rm -rf ${DISTNAME}/lib/pkgconfig + find ${DISTNAME}/bin -type f -executable -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; + find ${DISTNAME}/lib -type f -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \; + find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz + find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz + cd ../../ + rm -rf distsrc-${i} + done + mkdir -p $OUTDIR/src + mv $SOURCEDIST $OUTDIR/src diff --git a/software/examples/libinfnoise/Makefile b/software/examples/libinfnoise/Makefile index 1401560..68f3fd6 100644 --- a/software/examples/libinfnoise/Makefile +++ b/software/examples/libinfnoise/Makefile @@ -13,12 +13,15 @@ LDFLAGS= -shared FTDI := $(shell libftdi-config --libs) -all: libinfnoise-example libinfnoise-example-raw +all: libinfnoise-example libinfnoise-example-raw libinfnoise-example-1 libinfnoise-example: example.c $(CC) $(CFLAGS) -o libinfnoise-example example.c $(FTDI) -lm -lrt -linfnoise -libinfnoise-example-raw: example.c +libinfnoise-example-simple: example-simple.c + $(CC) $(CFLAGS) -o libinfnoise-example-1 example1.c $(FTDI) -lm -lrt -linfnoise + +libinfnoise-example-complex: example-complex.c $(CC) $(CFLAGS) -o libinfnoise-example-raw example-raw.c $(FTDI) -lm -lrt -linfnoise clean: diff --git a/software/examples/libinfnoise/example.c b/software/examples/libinfnoise/example-complex.c similarity index 51% rename from software/examples/libinfnoise/example.c rename to software/examples/libinfnoise/example-complex.c index 0344d39..9bf8033 100644 --- a/software/examples/libinfnoise/example.c +++ b/software/examples/libinfnoise/example-complex.c @@ -10,27 +10,26 @@ 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; + bool initKeccak = false; // initialize Keccak sponge (used for whitening) + uint32_t multiplier = 1u; // multiplier for whitening + bool debug = true; // debug mode (health monitor writes to stderr) // initialize hardware and health monitor - struct ftdi_context ftdic; - if (!initInfnoise(&ftdic, serial, &message, true, debug)) { - fputs(message, stderr); + struct infnoise_context context; + fprintf(stdout, "pre-initi: %s\n", ""); + + if (!initInfnoise(&context, serial, initKeccak, debug)) { + fprintf(stdout, "erri: %s\n", ""); + fputs(context.message, stderr); return 1; // ERROR } + fprintf(stdout, "initi: %s\n", ""); - // 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; + resultSize = 512u; } else { - resultSize = multiplier*32u; + resultSize = 1024u; } // read and print in a loop (until 1M is read) @@ -39,18 +38,20 @@ int main() 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; + uint64_t bytesWritten = readData(&context, result, !initKeccak, multiplier); + fprintf(stderr, "infnoise bytes read: %lu\n", 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; + if (context.errorFlag) { + fprintf(stderr, "Error: %s\n", context.message); + return -1; } + fprintf(stderr, "infnoise bytes read: %lu\n", (unsigned long) bytesWritten); + totalBytesWritten += bytesWritten; - // print as many bytes + // print as many bytes as readData told us fwrite(result, 1, bytesWritten, stdout); } return 0; diff --git a/software/examples/libinfnoise/example-raw.c b/software/examples/libinfnoise/example-raw.c deleted file mode 100644 index 53d84d3..0000000 --- a/software/examples/libinfnoise/example-raw.c +++ /dev/null @@ -1,46 +0,0 @@ -/* -This is a very simple example to use libinfnoise in raw output mode. -*/ - -#include -#include -#include - -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; -} diff --git a/software/examples/libinfnoise/example-simple.c b/software/examples/libinfnoise/example-simple.c new file mode 100644 index 0000000..9bf8033 --- /dev/null +++ b/software/examples/libinfnoise/example-simple.c @@ -0,0 +1,58 @@ +/* +This is a simple example to use libinfnoise with whitened and multiplied output. +*/ + +#include +#include +#include + +int main() +{ + // parameters + char *serial=NULL; // can be set to a specific serial, NULL uses the first found device + bool initKeccak = false; // initialize Keccak sponge (used for whitening) + uint32_t multiplier = 1u; // multiplier for whitening + bool debug = true; // debug mode (health monitor writes to stderr) + + // initialize hardware and health monitor + struct infnoise_context context; + fprintf(stdout, "pre-initi: %s\n", ""); + + if (!initInfnoise(&context, serial, initKeccak, debug)) { + fprintf(stdout, "erri: %s\n", ""); + fputs(context.message, stderr); + return 1; // ERROR + } + fprintf(stdout, "initi: %s\n", ""); + + uint32_t resultSize; + if (multiplier == 0 || initKeccak == false) { + resultSize = 512u; + } else { + resultSize = 1024u; + } + + // 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(&context, result, !initKeccak, multiplier); + fprintf(stderr, "infnoise bytes read: %lu\n", 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 (context.errorFlag) { + fprintf(stderr, "Error: %s\n", context.message); + return -1; + } + fprintf(stderr, "infnoise bytes read: %lu\n", (unsigned long) bytesWritten); + totalBytesWritten += bytesWritten; + + // print as many bytes as readData told us + fwrite(result, 1, bytesWritten, stdout); + } + return 0; +} diff --git a/software/infnoise.c b/software/infnoise.c index fcd307b..946cce2 100644 --- a/software/infnoise.c +++ b/software/infnoise.c @@ -8,9 +8,11 @@ #include #include #include + #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) #include #endif + #include #include #include @@ -18,41 +20,81 @@ #include #include "infnoise.h" #include "libinfnoise.h" -#include "libinfnoise_private.h" #include "KeccakF-1600-interface.h" static void initOpts(struct opt_struct *opts) { - opts->outputMultiplier = 0u; - opts->daemon = false; - opts->debug = false; - opts->devRandom = false; - opts->noOutput = false; - opts->listDevices = false; - opts->raw = false; - opts->version = false; - opts->help = false; - opts->none = false; - opts->pidFileName = - opts->serial = NULL; + opts->outputMultiplier = 0u; + opts->daemon = false; + opts->debug = false; + opts->devRandom = false; + opts->noOutput = false; + opts->listDevices = false; + opts->raw = false; + opts->version = false; + opts->help = false; + opts->none = false; + opts->pidFileName = + opts->serial = NULL; } // getopt_long(3) options descriptor +static struct option longopts[] = { + {"raw", no_argument, NULL, 'r'}, + {"debug", no_argument, NULL, 'D'}, + {"dev-random", no_argument, NULL, 'R'}, + {"no-output", no_argument, NULL, 'n'}, + {"multiplier", required_argument, NULL, 'm'}, + {"pidfile", required_argument, NULL, 'p'}, + {"serial", required_argument, NULL, 's'}, + {"daemon", no_argument, NULL, 'd'}, + {"list-devices", no_argument, NULL, 'l'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}}; -static struct option longopts[] = {{"raw", no_argument, NULL, 'r'}, - {"debug", no_argument, NULL, 'D'}, - {"dev-random", no_argument, NULL, 'R'}, - {"no-output", no_argument, NULL, 'n'}, - {"multiplier", required_argument, NULL, 'm'}, - {"pidfile", required_argument, NULL, 'p'}, - {"serial", required_argument, NULL, 's'}, - {"daemon", no_argument, NULL, 'd'}, - {"list-devices", no_argument, NULL, 'l'}, - {"version", no_argument, NULL, 'v'}, - {"help", no_argument, NULL, 'h'}, - {NULL, 0, NULL, 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 { +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) + // quell compiler warning about unused variable. + static int devRandomFD = -1; + (void) entropy; + + if (devRandomFD < 0) + devRandomFD = open("/dev/random", O_WRONLY); + if (devRandomFD < 0) { + *message = "Unable to open random(4)"; + return false; + }; + // we are not trapping EINT and EAGAIN; as the random(4) driver seems + // to not treat partial writes as not an error. So we think that comparing + // to length is fine. + // + if (write(devRandomFD, bytes, length) != length) { + *message = "Unable to write output from Infinite Noise Multiplier to random(4)"; + return false; + } +#endif +#if defined(__APPLE__) + *message = "macOS doesn't support writes to entropy pool"; + entropy = 0; // suppress warning + return false; +#endif +#ifdef LINUX + inmWaitForPoolToHaveRoom(); + inmWriteEntropyToPool(bytes, length, entropy); +#endif + } + return true; +} int main(int argc, char **argv) { - struct ftdi_context ftdic; + struct infnoise_context context; struct opt_struct opts; int ch; bool multiplierAssigned = false; @@ -63,56 +105,56 @@ int main(int argc, char **argv) { while ((ch = getopt_long(argc, argv, "rDRnm:p:s:dlvh", longopts, NULL)) != -1) { switch (ch) { - case 'r': - opts.raw = true; - break; - case 'D': - opts.debug = true; - break; - case 'R': - opts.devRandom = true; - break; - case 'n': - opts.noOutput = true; - break; - case 'm': - multiplierAssigned = true; - int tmpOutputMult = atoi(optarg); - if (tmpOutputMult < 0) { - fputs("Multiplier must be >= 0\n", stderr); - return 1; - } - opts.outputMultiplier = tmpOutputMult; - break; - case 'p': - opts.pidFileName = optarg; - if (opts.pidFileName == NULL || !strcmp("", opts.pidFileName)) { - fputs("--pidfile without file name\n", stderr); - return 1; - } - break; - case 's': - opts.serial = optarg; - if (opts.serial == NULL || !strcmp("", opts.serial)) { - fputs("--serial without value\n", stderr); - return 1; - } - break; - case 'd': - opts.daemon = true; - break; - case 'l': - opts.listDevices = true; - break; - case 'v': - opts.version = true; - break; - case 'h': - opts.help = true; - break; - default: - opts.help = true; - opts.none = true; + case 'r': + opts.raw = true; + break; + case 'D': + opts.debug = true; + break; + case 'R': + opts.devRandom = true; + break; + case 'n': + opts.noOutput = true; + break; + case 'm': + multiplierAssigned = true; + int tmpOutputMult = atoi(optarg); + if (tmpOutputMult < 0) { + fputs("Multiplier must be >= 0\n", stderr); + return 1; + } + opts.outputMultiplier = tmpOutputMult; + break; + case 'p': + opts.pidFileName = optarg; + if (opts.pidFileName == NULL || !strcmp("", opts.pidFileName)) { + fputs("--pidfile without file name\n", stderr); + return 1; + } + break; + case 's': + opts.serial = optarg; + if (opts.serial == NULL || !strcmp("", opts.serial)) { + fputs("--serial without value\n", stderr); + return 1; + } + break; + case 'd': + opts.daemon = true; + break; + case 'l': + opts.listDevices = true; + break; + case 'v': + opts.version = true; + break; + case 'h': + opts.help = true; + break; + default: + opts.help = true; + opts.none = true; } } @@ -147,15 +189,15 @@ int main(int argc, char **argv) { } } - if (opts.debug == false) { + if (!opts.debug) { if (getenv("INFNOISE_DEBUG") != NULL) { - if (!strcmp("true",getenv("INFNOISE_DEBUG"))) { + if (!strcmp("true", getenv("INFNOISE_DEBUG"))) { opts.debug = true; } } } - if (multiplierAssigned == false) { + if (!multiplierAssigned) { if (getenv("INFNOISE_MULTIPLIER") != NULL) { int tmpOutputMult = atoi(getenv("INFNOISE_MULTIPLIER")); if (tmpOutputMult < 0) { @@ -167,7 +209,7 @@ int main(int argc, char **argv) { } } - if(!multiplierAssigned && opts.devRandom) { + if (!multiplierAssigned && opts.devRandom) { opts.outputMultiplier = 2u; // Don't throw away entropy when writing to /dev/random unless told to do so } @@ -178,33 +220,39 @@ int main(int argc, char **argv) { return 0; } - char *message = "no data?"; - bool errorFlag = false; if (opts.listDevices) { - if(!listUSBDevices(&ftdic, &message)) { - fputs(message, stderr); + devlist_node devlist = listUSBDevices(&context.message); + if (devlist == NULL) { + fprintf(stderr, "Error: %s\n", context.message); return 1; } - //fputs(message, stdout); // todo: put list of devices to &message and print here, not in libinfnoise + devlist_node curdev = NULL; + uint8_t i = 0; + for (curdev = devlist; curdev != NULL; i++) { + printf("ID: %i, Manufacturer: %s, Description: %s, Serial: %s\n", curdev->id, curdev->manufacturer, + curdev->description, curdev->serial); + curdev = curdev->next; + } return 0; } if (opts.devRandom) { #ifdef LINUX - 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 :-/) + 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 :-/) #endif #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) - int devRandomFD = open("/dev/random", O_WRONLY); - if(devRandomFD < 0) { - fprintf(stderr, "Unable to open /dev/random\n"); - exit(1); - } - close(devRandomFD); + int devRandomFD = open("/dev/random", O_WRONLY); + if (devRandomFD < 0) { + fprintf(stderr, "Unable to open /dev/random\n"); + exit(1); + } + close(devRandomFD); #endif #if defined(__APPLE__) message = "dev/random not supported on macOS"; - return 0; + fprintf(stderr, "Error: %s\n", context.message); + return 1; #endif } @@ -212,25 +260,45 @@ int main(int argc, char **argv) { startDaemon(&opts); // initialize USB device, health check and Keccak state (see libinfnoise) - if (!initInfnoise(&ftdic, opts.serial, &message, !opts.raw, opts.debug)) { - fprintf(stderr, "Error: %s\n", message); + if (!initInfnoise(&context, opts.serial, !opts.raw, opts.debug)) { + fprintf(stderr, "Error: %s\n", context.message); return 1; // ERROR } + context.errorFlag = false; + + // calculate output size based on the parameters: + // when using the multiplier, we need a result array of 32*MULTIPLIER - otherwise 64(BUFLEN/8) bytes + uint64_t resultSize; + if (opts.outputMultiplier == 0 || opts.raw) { + resultSize = BUFLEN / 8u; + } else { + resultSize = opts.outputMultiplier * 32u; + } + //fprintf(stderr, "resultsize: %lu\n", resultSize); // endless loop uint64_t totalBytesWritten = 0u; - while(true) { - uint64_t prevTotalBytesWritten = totalBytesWritten; - totalBytesWritten += readData_private(&ftdic, NULL, &message, &errorFlag, opts.noOutput, opts.raw, opts.outputMultiplier, opts.devRandom); // calling libinfnoise's private readData method + while (true) { + uint8_t result[resultSize]; + uint64_t bytesWritten = readData(&context, result, opts.raw, opts.outputMultiplier); + totalBytesWritten += bytesWritten; - if (errorFlag) { - fprintf(stderr, "Error: %s\n", message); + if (context.errorFlag) { + fprintf(stderr, "Error: %s\n", context.message); return 1; } - if(opts.debug && (1u << 20u)*(totalBytesWritten/(1u << 20u)) > (1u << 20u)*(prevTotalBytesWritten/(1u << 20u))) { - fprintf(stderr, "Output %lu bytes\n", (unsigned long)totalBytesWritten); + if (!opts.noOutput) { + if (!outputBytes(result, bytesWritten, context.entropyThisTime, opts.devRandom, + &context.message)) { + fprintf(stderr, "Error: %s\n", context.message); + return 1; + }; + } + + if (opts.debug && + (1u << 20u) * (totalBytesWritten / (1u << 20u)) > (1u << 20u) * (totalBytesWritten + bytesWritten / (1u << 20u))) { + fprintf(stderr, "Output %lu bytes\n", (unsigned long) totalBytesWritten); } } - return 0; } diff --git a/software/infnoise.h b/software/infnoise.h index 09499ed..f713827 100644 --- a/software/infnoise.h +++ b/software/infnoise.h @@ -24,4 +24,9 @@ struct opt_struct { char *serial; // Name of selected device }; + +void inmWriteEntropyStart(uint32_t bufLen, bool debug); +void inmWriteEntropyToPool(uint8_t *bytes, uint32_t length, uint32_t entropy); +void inmWaitForPoolToHaveRoom(void); + void startDaemon(struct opt_struct *opts); diff --git a/software/libinfnoise.c b/software/libinfnoise.c index 6cce1d0..b5963f5 100644 --- a/software/libinfnoise.c +++ b/software/libinfnoise.c @@ -16,7 +16,6 @@ #include #include #include "libinfnoise_private.h" -#include "libinfnoise.h" #include "KeccakF-1600-interface.h" #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) @@ -24,19 +23,21 @@ #endif uint8_t keccakState[KeccakPermutationSizeInBytes]; -bool initInfnoise(struct ftdi_context *ftdic,char *serial, char **message, bool keccak, bool debug) { + +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)) { - *message="Can't initialize health checker"; + context->message = "Can't initialize health checker"; return false; } // initialize USB - if(!initializeUSB(ftdic, message, serial)) { + if (!initializeUSB(&context->ftdic, &context->message, serial)) { // Sometimes have to do it twice - not sure why - if(!initializeUSB(ftdic, message, serial)) { + if (!initializeUSB(&context->ftdic, &context->message, serial)) { return false; } } @@ -48,28 +49,30 @@ bool initInfnoise(struct ftdi_context *ftdic,char *serial, char **message, bool } // let healthcheck collect some data - uint32_t maxWarmupRounds = 500; + uint32_t maxWarmupRounds = 5000; uint32_t warmupRounds = 0; - bool errorFlag = false; - while(!inmHealthCheckOkToUseData()) { - readData_private(ftdic, NULL, message, &errorFlag, false, true, 0, false); + //bool errorFlag = false; + while (!inmHealthCheckOkToUseData()) { + readData(context, NULL, true, 0); warmupRounds++; } + if (warmupRounds > maxWarmupRounds) { - *message = "Unable to collect enough entropy to initialize health checker."; + 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++) { + for (i = 0u; i < BUFLEN; i++) { // Alternate Ph1 and Ph2 - outBuf[i] = i & 1? (1 << SWEN2) : (1 << SWEN1); + outBuf[i] = i & 1 ? (1 << SWEN2) : (1 << SWEN1); } } @@ -80,19 +83,19 @@ void prepareOutputBuffer() { uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, char **message, bool *errorFlag) { inmClearEntropyLevel(); uint32_t i; - for(i = 0u; i < BUFLEN/8u; 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]; + 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; + 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)) { + if (!inmHealthCheckAddBit(evenBit, oddBit, even)) { *message = "Health check of Infinite Noise Multiplier failed!"; *errorFlag = true; return 0; @@ -103,90 +106,26 @@ uint32_t extractBytes(uint8_t *bytes, uint8_t *inBuf, char **message, bool *erro 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 { -#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) - // quell compiler warning about unused variable. - static int devRandomFD = -1; - (void)entropy; - - if (devRandomFD < 0) - devRandomFD = open("/dev/random",O_WRONLY); - if (devRandomFD < 0) { - *message = "Unable to open random(4)"; - return false; - }; - // we are not trapping EINT and EAGAIN; as the random(4) driver seems - // to not treat partial writes as not an error. So we think that comparing - // to length is fine. - // - if (write(devRandomFD, bytes, length) != length) { - *message = "Unable to write output from Infinite Noise Multiplier to random(4)"; - return false; - } -#endif -#if defined(__APPLE__) - *message = "macOS doesn't support writes to entropy pool"; - entropy = 0; // suppress warning - return false; -#endif -#ifdef LINUX - //fputs("room?", stderr); - inmWaitForPoolToHaveRoom(); - //fputs("room!", stderr); - //printf("length: - %ul\n", length); - //printf("entropy: - %ul\n", entropy); - inmWriteEntropyToPool(bytes, length, entropy); -#endif - } - 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) { +uint32_t processBytes(uint8_t *bytes, uint8_t *result, uint32_t *entropy, + uint32_t *numBits, uint32_t *bytesWritten, + bool raw, uint32_t outputMultiplier) { //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 (*entropy > inmExpectedEntropyPerBit * BUFLEN / INM_ACCURACY) { + *entropy = inmExpectedEntropyPerBit * BUFLEN / INM_ACCURACY; } - if(raw) { + 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)); - } + if (result != NULL) { + memcpy(result, bytes, BUFLEN / 8u * sizeof(uint8_t)); } - return BUFLEN/8u; + return BUFLEN / 8u; } // Note that BUFLEN has to be less than 1600 by enough to make the sponge secure, @@ -196,112 +135,96 @@ uint32_t processBytes(uint8_t *bytes, uint8_t *result, uint32_t entropy, // 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]; + + uint8_t dataOut[1024u]; + KeccakAbsorb(keccakState, bytes, BUFLEN / 64u); + + 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)); - } + KeccakExtract(keccakState, dataOut, (*entropy + 63u) / 64u); + if (result != NULL) { + memcpy(result, dataOut, *entropy / 8u * sizeof(uint8_t)); } - return entropy/8u; + return *entropy / 8u; } - // Output 256*outputMultipler bits. - uint32_t numBits = outputMultiplier*256u; - uint32_t bytesWritten = 0u; - uint8_t dataOut[outputMultiplier * 32u]; // ??? + // Output 256*outputMultipler bits (in chunks of 1024) + // only the first 1024 now, + if (*numBits == 0u) { + *numBits = outputMultiplier*256u; + *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]; - } - } + // Output up to 1024 bits at a time. + uint32_t bytesToWrite = 1024u / 8u; + if (bytesToWrite > *numBits / 8u) { + bytesToWrite = *numBits / 8u; } - //fprintf(stderr, "bytesWritten: %ul\n", bytesWritten); - //fprintf(stderr, "entropy: %ul\n", entropy); + KeccakExtract(keccakState, result, bytesToWrite / 8u); + KeccakPermutation(keccakState); + *bytesWritten = bytesToWrite; + *numBits -= bytesToWrite * 8u; + } + return *bytesWritten; +} - 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; - } - //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. -bool listUSBDevices(struct ftdi_context *ftdic, char** message) { - ftdi_init(ftdic); +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; + int i = 0; // search devices - int rc = ftdi_usb_find_all(ftdic, &devlist, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID); - + 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"; + *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++) { - //printf("Device: %d, ", i); - rc = ftdi_usb_get_strings(ftdic, curdev->dev, manufacturer, 128, description, 128, serial, 128); + 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 = "Can't find Infinite Noise Multiplier. Try running as super user?"; + return NULL; + } else { + *message = "ftdi_usb_get_strings failed: %d (%s)\n", rc, ftdi_get_error_string(ftdic)); + return NULL; } - //*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\n", manufacturer, description, serial); + 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; + } curdev = curdev->next; } - - return true; + return return_list; } // Initialize the Infinite Noise Multiplier USB interface. @@ -324,7 +247,7 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { *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()) { + if (!isSuperUser()) { *message = "Can't open Infinite Noise Multiplier. Try running as super user?"; } else { #ifdef LINUX @@ -341,7 +264,7 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { // serial specified rc = ftdi_usb_open_desc(ftdic, INFNOISE_VENDOR_ID, INFNOISE_PRODUCT_ID, NULL, serial); if (rc < 0) { - if(!isSuperUser()) { + 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"; @@ -353,119 +276,91 @@ bool initializeUSB(struct ftdi_context *ftdic, char **message, char *serial) { // Set high baud rate rc = ftdi_set_baudrate(ftdic, 30000); - if(rc == -1) { + if (rc == -1) { *message = "Invalid baud rate"; return false; - } else if(rc == -2) { + } else if (rc == -2) { *message = "Setting baud rate failed"; return false; - } else if(rc == -3) { + } else if (rc == -3) { *message = "Infinite Noise Multiplier unavailable"; return false; } rc = ftdi_set_bitmode(ftdic, MASK, BITMODE_SYNCBB); - if(rc == -1) { + if (rc == -1) { *message = "Can't enable bit-bang mode"; return false; - } else if(rc == -2) { + } 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) { + if (ftdi_write_data(ftdic, buf, 64) != 64) { *message = "USB write failed"; return false; } - if(ftdi_read_data(ftdic, buf, 64) != 64) { + 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 infnoise_context *context, uint8_t *result, bool raw, uint32_t outputMultiplier) { + // check if data can be squeezed from the keccak spongr from previous state (or we need to collect some new entropy to get numBits >0) + if (context->numBits > 0u) { + // squeeze the sponge! -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); -} + // Output up to 1024 bits at a time. + uint32_t bytesToWrite = 1024u / 8u; -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); + if (bytesToWrite > context->numBits / 8u) { + bytesToWrite = context->numBits / 8u; + } - // write clock signal - if(ftdi_write_data(ftdic, outBuf, BUFLEN) != BUFLEN) { - *message = "USB write failed"; - *errorFlag = true; - } + KeccakExtract(keccakState, result, bytesToWrite / 8u); + KeccakPermutation(keccakState); - // 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; - return 0; - } + context->bytesWritten += bytesToWrite; + context->numBits -= bytesToWrite * 8u; + return 1024/8u; + } else { // collect new entropy + uint8_t inBuf[BUFLEN]; + struct timespec start; + clock_gettime(CLOCK_REALTIME, &start); - 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); + // write clock signal + if (ftdi_write_data(&context->ftdic, outBuf, BUFLEN) != BUFLEN) { + context->message = "USB write failed"; + context->errorFlag = true; + } - //fprintf(stderr, "ERROR1: %ul\n", entropy); + // 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); - // 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; + if (us <= MAX_MICROSEC_FOR_SAMPLES) { + uint8_t bytes[BUFLEN / 8u]; + context->entropyThisTime = extractBytes(bytes, inBuf, &context->message, &context->errorFlag); + if (context->errorFlag) { + // todo: message? + return 0; + } + // call health check and return bytes if OK + if (inmHealthCheckOkToUseData() && inmEntropyOnTarget(context->entropyThisTime, BUFLEN)) { + return processBytes(bytes, result, &context->entropyThisTime, &context->numBits, &context->bytesWritten, + raw, outputMultiplier); + } } } 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 diff --git a/software/libinfnoise.h b/software/libinfnoise.h index 7ebc5f9..cf0100e 100644 --- a/software/libinfnoise.h +++ b/software/libinfnoise.h @@ -1,11 +1,13 @@ #include #include #include + #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__APPLE__) || defined(__FreeBSD__) #include #else #include #endif + #include #include @@ -13,10 +15,65 @@ // 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); +struct infnoise_context { + struct ftdi_context ftdic; + uint32_t entropyThisTime; + char *message; + bool errorFlag; + //uint8_t keccakState[KeccakPermutationSizeInBytes]; -bool initInfnoise(struct ftdi_context *ftdic, char *serial, char **message, bool keccak, bool debug); + // used in multiplier mode to keep track of bytes to be put out + uint32_t numBits; + uint32_t bytesWritten; +}; -uint32_t readRawData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag); +struct infnoise_devlist_node { + uint8_t id; + char manufacturer[128]; + char description[129]; + char serial[128]; + struct infnoise_devlist_node *next; +}; -uint32_t readData(struct ftdi_context *ftdic, uint8_t *result, char **message, bool *errorFlag, uint32_t outputMultiplier); +typedef struct infnoise_devlist_node *devlist_node; + +/* + * returns a struct of infnoise_devlist_node listing all connected FTDI FT240 devices by its USB descriptors, + * + * parameters: + * - message: pointer for error message + * + * returns: NULL when none found or infnoise_devlist_node + */ +devlist_node listUSBDevices(char **message); + + +/* + * initialize the Infinite Noise TRNG - must be called once before readData() works. + * + * parameters: + * - context: pointer to infnoise_context struct + * - serial: optional serial number of the device (NULL) + * - keccak: initialize Keccak sponge (required to use readData with raw=false) + * - debug: debug flag + * returns: boolean success indicator (0=success) +*/ +bool initInfnoise(struct infnoise_context *context, char *serial, bool keccak, bool debug); + +/* + * Reads some bytes from the TRNG and stores them in the "result" byte array. + * The array has to be of sufficient size. Please refer to the example programs. + * + * After each read operation, the infnoise_context's errorFlag must be checked, + * and the data from this call has to be discarded! + * Detailed error messages can be found in context->message. + * + * parameters: + * - context: infnoise_context struct with device pointer and state variables + * - result: pointer to byte array to store the result + * - raw: boolean flag for raw or whitened output + * - outputMultiplier: only used for whitened output + * + * returns: number of bytes written to the array +*/ +uint32_t readData(struct infnoise_context *context, uint8_t *result, bool raw, uint32_t outputMultiplier); diff --git a/software/libinfnoise_private.h b/software/libinfnoise_private.h index 1280081..552cdf7 100644 --- a/software/libinfnoise_private.h +++ b/software/libinfnoise_private.h @@ -8,7 +8,7 @@ #endif #include #include - +#include "libinfnoise.h" #define INFNOISE_VENDOR_ID 0x0403 #define INFNOISE_PRODUCT_ID 0x6015 @@ -37,8 +37,6 @@ // 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); @@ -48,14 +46,12 @@ 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); +bool initializeUSB(struct ftdi_context *ftdic, char **message,char *serial); void prepareOutputBuffer(); struct timespec; @@ -63,7 +59,8 @@ 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); +uint32_t processBytes(uint8_t *bytes, uint8_t *result, uint32_t *entropy, uint32_t *numBits, uint32_t *bytesWritten, bool raw, + uint32_t outputMultiplier); + +//uint32_t readData_private(struct infnoise_context *context, uint8_t *result, char **message, bool *errorFlag, bool noOutput, bool raw, uint32_t outputMultiplier, bool devRandom);