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:
Please log in to post comments.
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
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/