Nuclear Hardware RNG
Technologies | C, Linux, Raspberry Pi, MightyOhm Geiger Counter |
Source Code | https://github.com/brendan-w/kRad |
License | GPLv3 |
At its core, this project is a random number generator that uses a custom Linux kernel module to gather entropy from radiation. Formally, it was done for a class on Open Source Culture. The topic at hand was the concept of a black box; A device whose inputs and outputs are known, but its internals are not. For a term project, I decided to take this concept literally.
The black box I constructed is advertised as a closed source symmetric-key encryption device that produces "unbreakable" ciphertext. Users may submit text to be encrypted or decrypted, but the details of the encryption remain a mystery. With the intention of raising suspicion over closed source cryptography, I decided to make the internals of the box quite duplicitous.
The "encryption" that the device performs is nothing more than a lookup table joining the user's plaintext with randomly generated ciphertext. While devious, I figured I could take this a step further. So, to generate the random ciphertext, I built a hardware random number generator using readings from a Geiger counter.
The RNG works by placing a Geiger counter next to a radioactive source, causing it to produce a flurry of clicks. Since each click is the result of chaotic nuclear decay, the interval between one click and the next is essentially random.
Hardware

The box itself is actually built from a black toolbox. Its surface has been made largely featureless, except for a lock and a single Ethernet port. The device is self powered, and does not require any other connections to function.

Opening the box reveals a battery powered Raspberry Pi, a Geiger counter, and a small radioactive source.

The Raspberry Pi sits on an adjustable platform, exposing only it's Ethernet port. The connections are for GND
, 5V
, and the Geiger counter's Pulse
pin.

The Geiger counter is suspended directly above an aluminum tray containing the radioactive source. The 1/4" hole on the top of the tray is the emission window, which exposes the counter to continuous beta radiation.
Process
To make this work, I first needed to acquire a radioactive check source. Luckily, the internet is a wonderful place, and there are many license exempt options to choose from. Ultimately, I purchased a small epoxy-encased disk meant for the educational market. My isotope-of-choice was Strontium-90, a beta emitter, with a half-life of ~28 years.
For the detector, I purchased the MightyOhm Geiger Counter as a kit. It's open source, exceptionally easy to assemble, and even has serial logging capabilities. Overall, a great product, and perfect for experiments such as this.
To turn the Geiger counter's clicks into random numbers, I implemented a small Linux kernel module that feeds entropy to /dev/random
via the hardware RNG API. The module uses the Linux kernel's builtin GPIO
facilities to watch for short (100μs) pulses from the counter. By registering a rising interrupt, it can maintain a buffer of timestamps from each pulse. Each timestamp provides nanosecond resolution for the timing of a pulse. When the RNG API requests data, the raw timestamps are sent, and are stirred into the entropy pool by the kernel.
Being unfamiliar with kernel-space programming, this project actually served as a decent introduction. As time goes on, I'd like to start running tests on the entropy quality and throughput of the system as a whole.

Interface
To make use of this obviously fantastic encryption service, one need only SSH into the box. Once there, a python script called fcrypt.py will present you with a REPL to perform basic cryptographic functions. There are three commands:
setkey
- The password with which you'd like to encrypt/decrypt your data.e
- encrypt some plaintextd
- decrypt some ciphertext
Even though the "encryption" is simply returning random tokens, fcrypt.py will be consistent with its output. Encrypting the same plaintext multiple times will always produce the same ciphertext. This also works in reverse, where decrypting nonsense ciphertext will always produce consistent, gibberish plaintext. Here is an example interaction with the black box:
>>> setkey notevendisablingecho
New key defined
# simple encryption/decryption
>>> e Hello World
yFHJt8DUTcS
>>> d yFHJt8DUTcS
Hello World
# will consistently produce the same ciphertext,
# just like actual symmetric-key crypto
>>> e Hello World
yFHJt8DUTcS
# new keys will cause the same plaintext to
# produce different ciphertext
>>> setkey anotherkey
New key defined
>>> e Hello World
biEJM/ftrS+
>>> d biEJM/ftrS+
Hello World
# will consistently produce garbage
>>> d plaintext that hasnt been encrypted yet
8HqIX8mn20c77KKiyBNamSwg5h5Rpy+9Kn5MU+v
>>> d plaintext that hasnt been encrypted yet
8HqIX8mn20c77KKiyBNamSwg5h5Rpy+9Kn5MU+v