Secure hardware random number using the mbed

As one can see from the various threads in the forum, the mbed has quite noisy analog inputs. Now, we can turn this to our advantage!

Using the fast SHA256 implementation I did earlier I created a simple hash based entropy pool. The pool is fed by various random sources, such as the MAC address, the realtime clock, a timer, a byte counter. But most importantly it is fed by the 6 analog inputs.

I assumed 8 bits of true random per analog input read and two additional bits for the other sources combined. To make this assumption realistic it is important to let the analog inputs collect as much noise as possible: You should leave them unconnected, or connect them to rusty unconnected wires wich will act as antennas.

Currently the amount of entropy gather from the analog inputs is not measured in any way, it's just fixed at 8 bits per measurement. It should be possible to estimate this more accurately by looking at the MSB changed with respect to the previous measurement.

Import programEntropySource

Use your mbed and it\'s noisy analog inputs as a hardware random number generator!

Reading USB serial binary data under Linux

We want maximum throughput on the usb-serial port so we set the maximum baudrate.

The next problem is that we want to send binary data, we therefore have to disable the meaning of the CR, NL, end-of-stream and simmilar control characters.

Finaly, we want the mbed to go to sleep when no data is being read. However, the mbed does not have proper flow-control. I solved this by periodically sending a character to the mbed to signal that it should send more data.

The following Posix compliant C program will do all of this for us:

serialReader.cpp

 #include <sys/stat.h>
 #include <fcntl.h>
 #include <termios.h>
 #include <unistd.h>
 #include <stdio.h>
 
 int main(int argc, char* argv[])
 {
 	int fd;
 	termios oldtermios;
 	termios newtermios;
 	
 	fd = open("/dev/ttyACM0", O_RDWR | O_NONBLOCK);
 	tcgetattr(fd, &oldtermios);
 	cfmakeraw(&newtermios);
 	// cfsetispeed(&newtermios, B9600);
 	cfsetispeed(&newtermios, B115200);
 	tcsetattr(fd, TCSANOW, &newtermios);
 	
 	while(1) {
 		const int buffer_size = 1024;
 		char buffer[buffer_size];
 		int size_in = read(fd, buffer, buffer_size);
 		if(size_in > 0) {
 			int size_out = write(STDOUT_FILENO, buffer, size_in);
 			if(size_out != size_in)
 				return 1;
 		} else {
 			char trigger = 'G';
 			int size_cmd = write(fd, &trigger, 1);
 			usleep(50000);
 		}
 	}
	 tcsetattr(fd, TCSANOW, &oldtermios); /*reset to old values */
	 close(fd);
 	return 0;
 }

Benchmarking

Now we can test the our random number generator!

Benchmark

# serialReader | rngtest -t 1
...
rngtest: bits received from input: 37385360
rngtest: FIPS 140-2 successes: 1867
rngtest: FIPS 140-2 failures: 2
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 1
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 1
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=35.464; avg=43.647; max=48.827)Kibits/s
rngtest: FIPS tests speed: (min=47.803; avg=94.493; max=98.317)Mibits/s
rngtest: Program run time: 837039750 microseconds

From what I can tell, this random generator passes the FIPS-140-2 test, and it does so at a respectable 40 Kb/s. This is definitely compettive with expensive commercial random generators!

Installing as random source for linux

The easiest way to temporarily install the mbed as an entropy source for /dev/random is by outputting the contents to a FIFO and running rngd:

Use

# mkfifo mbedRandom
# serialReader > mbedRandom &
# rngd -f -r ./hardwareRandom 


3 comments on Secure hardware random number using the mbed:

25 Jul 2015

Remco, Nice library. I collected several megabytes of random bits and tested them with rngtest, ent, and NIST's sts. All tests passed! I measured the random bit rate at 86kbs (using the default 8-bit entropy for the unconnected ADCs, LPC1768).

I did some tests on the ADCs. Each ADC had a different "random" behavior. Instead of a uniform distribution of the 256 possible byte values, there were many "missing" values, and clustering at various values. The clustering was repeatable for a given ADC pin. The distribution of bits within a byte was not 50-50 for some bits ... I collected a megabyte of data from ADC p17 (low order bytes), and rngtest had 0 successes, and ent reports "Entropy = 5.002089 bits per byte". So 4 bits might be a better default for the library. With ADC 4 bit entropy, the random bit rate drops to 49.4 kbs

  ADC entropy for low order byte (100,000 samples)
p15   5.87
p16   2.18
p17   3.02
p18   4.24
p19   5.85
p20   4.95

On other MCUs, I have experimented with Walt Anderson's dueling-clocks RNG. I did a proof-of-concept for the LPC1768 using systick and WDT/RTC. It too passed the random bit tests, and runs at 8kbs. https://developer.mbed.org/users/manitou/code/rng/

18 Sep 2015

nice

01 Oct 2015

Hi Remco

I installed your EntropySource program on a u-blox C027 and let it produce about 50MB of random data which I then fed to the dieharder random number generator test suite (https://www.phy.duke.edu/~rgb/General/dieharder.php). Unlike the results that you obtained using rngtest, dieharder fails most tests (see attached log /media/uploads/walser/diehard_output.log output)

Please log in to post comments.