Fix merge
This commit is contained in:
		
							
								
								
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal 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 | ||||||
| @@ -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/ | ||||||
|   | |||||||
| @@ -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. | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								software/build-scripts/control.debian.lib
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								software/build-scripts/control.debian.lib
									
									
									
									
									
										Normal 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 | ||||||
| @@ -48,6 +48,3 @@ void startDaemon(struct opt_struct* opts) { | |||||||
| 	// Child | 	// Child | ||||||
| } | } | ||||||
|  |  | ||||||
| bool isSuperUser(void) { |  | ||||||
| 	return (geteuid() == 0); |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								software/examples/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								software/examples/README.md
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								software/examples/libinfnoise/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								software/examples/libinfnoise/Makefile
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								software/examples/libinfnoise/example-raw.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								software/examples/libinfnoise/example-raw.c
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								software/examples/libinfnoise/example.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								software/examples/libinfnoise/example.c
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										94
									
								
								software/examples/random-server.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										94
									
								
								software/examples/random-server.py
									
									
									
									
									
										Executable 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 | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								software/examples/serial-numbers.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										36
									
								
								software/examples/serial-numbers.py
									
									
									
									
									
										Executable 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() | ||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										418
									
								
								software/libinfnoise.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										17
									
								
								software/libinfnoise.h
									
									
									
									
									
										Normal 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); | ||||||
							
								
								
									
										5
									
								
								software/libinfnoise.version
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								software/libinfnoise.version
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | libinfnoise { | ||||||
|  |   global: listUSBDevices; initInfnoise; readRawData; readData; # explicitly list symbols to be exported | ||||||
|  |   local: *;         # hide everything else | ||||||
|  | }; | ||||||
|  |  | ||||||
							
								
								
									
										64
									
								
								software/libinfnoise_private.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								software/libinfnoise_private.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										1
									
								
								software/tests/README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | bats tests for the binary driver.  | ||||||
							
								
								
									
										87
									
								
								software/tests/infnoise.bats
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								software/tests/infnoise.bats
									
									
									
									
									
										Normal 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]" ] | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								software/tests/test_helper/bats-assert
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								software/tests/test_helper/bats-assert
									
									
									
									
									
										Submodule
									
								
							 Submodule software/tests/test_helper/bats-assert added at 9f88b4207d
									
								
							
							
								
								
									
										1
									
								
								software/tests/test_helper/bats-support
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								software/tests/test_helper/bats-support
									
									
									
									
									
										Submodule
									
								
							 Submodule software/tests/test_helper/bats-support added at 004e707638
									
								
							| @@ -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; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user