Image of the glider from the Game of Life by John Conway
Skip to content

Hardware RNG Through an rtl-sdr Dongle

An rtl-sdr dongle allows you to receive radio frequency signals to your computer through a software interface. You can listen to Amateur Radio, watch analog television, listen to FM radio broadcasts, and a number of other things. I have a friend to uses it to monitor power usage at his house. However, I have a different use- true random number generation.

The theory behind the RNG is by taking advantage of radio frequency noise such as atmospheric noise. which is caused by natural occurrences, such as weak galactic radiation from the center of our Milky Way Galaxy to the stronger local and remote lightning strikes. It's estimated that roughly 40 lightning strikes are hitting the Earth every second, which equates to about 3.5 million strikes per 24 hour period. Interestingly enough, this provides a great deal of entropy for a random number generator.

Check out Blitzortung. It is a community run site, where volunteers can setup lightning monitoring stations and submit data to the server. Of course, it isn't an accurate picture of the entire globe, but you can at least get some idea of the scope of lightning strikes around the continents.

Lightning Map of the United States

Unfortunately, however, the rtl-sdr dongle won't get down to the frequencies necessary for sampling atmospheric noise; about 100 KHz to 10 MHz, and above 10 GHz. However, it can sample cosmic noise, man-made (urban and suburban) noise, solar noise, thermal noise, and other terrestrial noises that are well within the tuner frequency range of the dongle.

In order to take advantage of this, you obviously need an rtl-sdr dongle. They're quite cheap, about $15 or so, and plug in via USB with an external antenna. Of course, the larger the antenna, the more terrestrial noise you'll be able to observe. With a standard telescoping antenna, I can observe about 3 Mbps of true random data.

The other piece, however, will be compiling and installing the rtl-entropy software. This will provide a FIFO file for observing the random data. Reading the random data can be done as you would read any regular file:

$ sudo rtl_entropy -b -f 74M
$ tail -f /run/rtl_entropy.fifo | dd of=/dev/null
^C8999+10 records in
9004+0 records out
4610048 bytes (4.6 MB) copied, 13.294 s, 347 kB/s

That's roughly 2.8 Mbps. Not bad for $15. Notice, that I passed the "-b" switch to detach the PID from the controlling TTY and background. Further, I am not tuning to the default frequency of 70 MHz, which is part of Band I in the North America band plan for television broadcasting. Instead, I am tuning to 74 MHz, which is in the middle of a break in the band plan, where no television broadcasting should be transmitted. Of course, you'll need to make sure you are tuning to a frequency that is less likely to encounter malicious interference. Even though the rtl_entropy daemon has built-in debiasing and FIPS randomness testing, a malicious source could interrupt with the operation of the output by transmitting on the frequency that you are listening to.

In order to guarantee that you have random data, you should send it through a battery of standardized tests for randomness. One popular test for randomness are the FIPS 140-2 tests. Suppose I create a 512 MB file from my sdr-rtl dongle, I can test it as follows:

$ rngtest < random.img
rngtest 2-unofficial-mt.14
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

rngtest: starting FIPS tests...
rngtest: entropy source exhausted!
rngtest: bits received from input: 83886080
rngtest: FIPS 140-2 successes: 4190
rngtest: FIPS 140-2 failures: 4
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: 1
rngtest: FIPS 140-2(2001-10-10) Long run: 2
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=174.986; avg=4379.165; max=4768.372)Mibits/s
rngtest: FIPS tests speed: (min=113.533; avg=147.777; max=150.185)Mibits/s
rngtest: Program run time: 560095 microseconds

It's expected to see some failures, but they should be outliers. There is also the Dieharder battery of randomness tests. This will take substantially longer to work through, but it can be done. Here are the first few lines:

$ dieharder -a < random.img 
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |rands/second|   Seed   |
        mt19937|  1.30e+08  | 334923062|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.98331589|  PASSED  
      diehard_operm5|   0|   1000000|     100|0.12201131|  PASSED  
  diehard_rank_32x32|   0|     40000|     100|0.69993313|  PASSED  
    diehard_rank_6x8|   0|    100000|     100|0.55365877|  PASSED  
   diehard_bitstream|   0|   2097152|     100|0.85077208|  PASSED  
        diehard_opso|   0|   2097152|     100|0.76171650|  PASSED  

The whole dieharder results of my 512 MB random file can be found here.

Last, but not least, it helps to observe the data visually. In this image, I created a plain white file in Gimp, that was 600x600 pixels in size. I then counted the number of bytes in that file, and generated an equally sized random binary data file. Finally, I added the bitmap header to the file, converted it to a PNG file, optimized it, and uploaded it here. The steps are as follows:

$ gimp # create 600x600px plain white file and save as 16-bit "white.bmp"
$ ls -l white.bmp | awk '{print $5}'
720138
$ tail -f /run/rtl_entropy.fifo| dd of=random.img bs=1 count=720138 iflag=fullblock
720138+0 records in
720138+0 records out
720138 bytes (720 kB) copied, 24.8033 s, 29.0 kB/s
$ dd if=white.bmp of=random.img bs=1 count=54 conv=notrunc
$ gimp random.img # export to PNG file

When viewing the output, there should be no obvious patterns in the output. As an example:

Visual representation of random

For more practical use, here is a quick application for generating 80-bit entropy unambiguous passwords:

$ for i in {1..10}; do
> strings /run/rtl_entropy.fifo | grep -o '[a-hjkmnp-z2-9.]' | head -n 16 | tr -d '\n'; echo
> done
8dfn42w6dagqnt4z
2vcsqu6sew.g6pp2
kv9nstj4gq39x5f.
wmpdpy7yz75xrhkh
.4ra2b38hmbf5jw5
7ngyk3c58k3eeq7c
8e4t8ts3ykhckdst
9g6yqqce.bxrrhpb
xwnw6mtk8njv76b2
xdmd89n68f.kcthp

Obviously, the practical uses here can be for Monte Carlo simulations, game theory, gambling, cryptography, and other practical uses where high quality randomness is needed. Unfortunately, I can seem to get rngd(8) to add the /run/rtl_entropy.fifo file as a hardware device. So, I can't feed the Linux CSPRNG with with the dongle, other than "dd if=/run/rtl_entropy.fifo of=/dev/random", which doesn't increase the entropy estimate, of course.

{ 13 } Comments

  1. Bar | June 17, 2015 at 1:44 am | Permalink

    Very cool 🙂

    What dongle would you recommend ? a one with a good Linux driver support.

  2. Aaron Toponce | June 17, 2015 at 8:52 am | Permalink

    I have a Terratec TStick with an e4000 tuner, which gets as low as 52 MHz. I don't recall installing any necessary software (outside of the prerequisites for the rtl_entropy daemon). I did need to blacklist the "dvb_usb_rtl28xxu" kernel module to get the daemon to work properly. Other than that, it was just plug-and-play.

    However, there are dongles that can get as low as 22 MHz, which is getting closer to the atmospheric noise range. Not that it's necessary, but if you could find a dongle that could tune to 1MHz, you could take immediate advantage of lightning strikes and atmospheric noise. Unfortunately, I'm not familiar with such dongles.

  3. andrew | June 17, 2015 at 10:26 am | Permalink

    Since the source of the signal can be any arbitrary broadcaster, what would broadcasting a periodic, deterministic noise to these frequencies do to the overall entropy you hope to gain from atmospheric noise?

  4. Aaron Toponce | June 17, 2015 at 11:37 am | Permalink

    It's certainly problematic, for sure. If there is a periodic, or flat transmission on the frequency you're tuned to, your entropy estimate will most certainly drop. Thankfully, the rtl_entropy software utilizes Von Neumann debiassing, which can help against something like a flat transmission. Again though, if it's periodic, this presents a problem for the quality of the bits.

    This is why many crypto nerds shy away from using RF as a source of randomness- it's not a closed controlled environment, like diode breakdown, shot noise, or semitransparent mirrors. It's likely that no one is interfering with the frequency, but you can't guarantee it.

    You may actually be better off tuning into the SHF band of frequencies, which have trouble penetrating buildings. Then you could sample photon noise, and atmospheric noise at > 10 GHz, which is not easily interfered with. At least not without creating serious health problems when increasing the wattage to guarantee interference. You will probably have a hard time with tuners in that range also, however.

    So, I guess if you really want to stick with RF as a source of "true randomness", I would recommend 3+ sources, tuned at different frequencies on the RF spectrum, combined, then XOR the bits into a single stream. The malicious party would need to know the frequencies you have tuned to, which in this case, is difficult. Security by obscurity. If one of the frequencies sees a periodic predictable transmission, it's still XORed with the other streams, and the result remains random.

    Of course, you could always feed the stream into the kernel CSPRNG, and read from that instead. Then, even with a periodic or flat stream, it doesn't matter. But then you lose getting true random bits. 🙂

  5. Kidekin | June 18, 2015 at 7:40 am | Permalink

    Found you 😉

    "Unfortunately, I can seem to get rngd(8) to add the /run/rtl_entropy.fifo file as a hardware device"

    You can find out how to do that by looking at the linux_random folder in kidekin TRNG software package. If that does not work on your system please let me know. Once you get the kidekin TRNG working this way, I can't imagine any technical reason why it would not work for any other character device. Not sure about FIFO device though, can't you create a character device rather than a FIFO device ?

    Question about the robustness of the concept: did you experiment with two devices running side by side ? Any correlation would certainly call for an in-depth rework of the post-processing and the expected bit rate...

  6. Aaron Toponce | June 18, 2015 at 9:25 am | Permalink

    This isn't my software, but I did submit a bug to the author about creating a character device rather than a named pipe: https://github.com/pwarren/rtl-entropy/issues/9

    I haven't received my Kidekin TRNG in the mail yet. I'm excited to start playing with it though, and put it through a battery of tests. 🙂

  7. Jack Zielke | July 10, 2015 at 2:47 pm | Permalink

    To get rngd working with rtl_entropy I made a few changes to /etc/init.d/rng-tools

    Right after set -e I added:

    # added for rtl-entropy
    if [ ! -h /dev/hwrng ]; then
    ln -s /var/run/rtl_entropy.fifo /dev/hwrng
    fi

    I changed the first line of finddevice to use -e instead of -c:
    [ -e "${HRNGDEVICE}" ] && return 0

    With those two changes rngd reads data from rtl_entropy. If you have another script starting rtl_entropy you could make the symlink there and get away with just the 1 change in finddevice.

  8. Erick | December 23, 2015 at 2:11 pm | Permalink

    Interesting post. I've been interested in trying out an SDR for a while. Been into electronics/Ham Radio since I was young and an SDR type of device seems pretty cool to fiddle around with. Using it as an RNG, I could see that working. I have built many receivers through the years, including a direct conversion VLF receiver. There is certainly a lot of noise generated by thunderstorms at those low frequencies. But there are also tones that appear as well. The theory behind these tones is that there is an excitation of the ionosphere by the atmospheric noise and propagation effects, combine to produce surreal whistling type sounds. So although there is randomness, there will be bursts of occasional semi-coherent signals that act similar to a swept signal generator.
    Years ago I read about these RF noise generator transmitters that were designed for embassies and other places where there might be radio listening devices. The idea was to broadcast wide spectrum RF noise, presumably to the van outside the building that is trying to eavesdrop and disrupt the radio link to the listening device by raising the noise floor. It strikes me like a device like this which could be built from a Zener diode, with enough bias voltage to be in avalanche mode. Such as used in a noise bridge. I have a noise bridge and when I plug that into an HF Receiver, I get "wall to wall" noise from VLF to 30 MHz and if the noise source is well built, beyond. If this noise was fed into the SDR, it would provide it with a source of wide-band random noise. In theory if the band pass was large enough it would be possible to grab samples of random noise across many MHz, translating into many MB/s worth of it. Being a closed system it would not be vulnerable to malicious interference.
    This was just my initial thoughts on this, I am sure there are many other ways to let some device physics or natural sources, "roll the dice" sort of to speak and take advantage of the randomness generated.
    I just stumbled across your blog Aaron, Googling stuff on NTP. What I have seen so far is quite interesting and well written! I read your Colophon, nicely done. Started the UNIX/LINUX path with Sun Solaris in the 90's myself, Win PC Lab at University was way too full all the time, forced me to use UNIX...what a blessing, Thank God, never realized how pivotal that was at the time! Ham as well here KA2JOA, years of various coding here too. clock.xmission.com, comes up in the list on my Pi when I run ntpq -p, very cool clock display at that URL! I will certainly be following your blog.

  9. fgdfgdfdg | January 26, 2016 at 4:29 pm | Permalink

    Those diehard results are useless, you were testing the default PRNG...

    Use -g 201 with -f file or use -g 200 with pipes.

  10. Aaron Toponce | January 30, 2016 at 3:21 am | Permalink

    No it's not. Read the manpage.

  11. John Morley | August 3, 2016 at 6:25 pm | Permalink

    I used the following to feed the /dev/random pool:

    $ sudo rngd -r /var/run/rtl_entropy.fifo -W3072

    I chose the 3072 as 75% of the pool size after failing to get it to work with -W95%, as suggested in pwarren's release notes. In fact I can't find any reference to percentages being valid in the -W option.

    The biggest problem I had was getting rtl_entropy to compile on my 64-bit Linux Mint distro. It took a lot of searching to find out how to install the missing crt1.o and crti.o dependencies:

    $ sudo apt-get install gcc-multilib

  12. John Morley | August 4, 2016 at 6:11 pm | Permalink

    Regarding posts 9 and 10, above, I read the manpage in an attempt to understand more (I learned a little, but a lot was beyond my understanding).

    It does say the following:

    "Alternatively, dieharder can be used to test files of numbers produced
    by a candidate random number generators:

    dieharder -a -g 201 -f random.org_bin

    for raw binary input..."

    which seems to be what fgdfgdfdg is saying. Now I'm even more confused. I've tried both Aaron's form of the dieharder call and the above on a gigabyte-sized file of random numbers generated by my own rtl-sdr dongle and the results are quite different. Can anyone shed any light?

  13. Christoffer | August 9, 2017 at 3:55 am | Permalink

    Thank you for this!

Post a Comment

Your email is never published nor shared.