Installing and testing OneRNG

by Niklaus 'vimja' Hofer

OneRNG is an Open Hardware random number generator that plugs into USB. You can learn more about it on its website, its original Kickstarter campaign or in an LWN.net article from 2015. There is also a somewhat more technical project documentation.

Back in January, the OneRNG went back on sale. Jenix organized a group order and about two weeks ago, our units arrived. Here is what I have learned since then.

Installation

The packaging of the OneRNG contains a URL which leads to the installation instructions, including instructions for a physical examination of the device to make sure it has not been tampered with. However, the instructions for installing the software are a little sparse. They are fine if you run Debian or Fedora, but if you're building your Linux system in a more manual way and if you're compiling your own kernels, you might need some additional information.

The installation package simply installs a couple of scripts. Here is a brief overview of what each of them does:

  • /lib/udev/rules.d/79-onerng.rules is a udev rule which triggers actions when the OneRNG gets plugged in or out
  • /sbin/onerng_verify.py is a python script that verifies the firmware of the OneRNG against a PGP public key which is hard-coded into the script
  • /sbin/onerng.sh gets called by the udev script mentioned above every time the OneRNG gets plugged in or out. Simply put, it does the following:
    • Initiate the hardware
    • Check the firmware
    • Start harnessing the OneRNG randomness by reading from the random number generator, scrambling the output by encrypting it with OpenSSL and then passing it to the rngd. The rngd then feeds the randomness into the Linux Kernel's entropy pool.
    • Stop OpenSSL and the rngd when the OneRNG gets removed.

Personally, I use Gentoo, but have also helped installing a OneRNG on an Arch system. Presumably, these steps are more or less the same on most distributions.

Kernel

The device needs the CDC ACM driver. The kernel option for the driver is called CONFIG_USB_ACM. In menuconfig, you can find it like so:

    Device Drivers  --->
       [*] USB support  --->
           <M>     USB Modem (CDC ACM) support

I suggest installing it as a module that you can load and unload. The module will be called cdc_acm.

Dependencies

There are a couple of dependencies: rngd - a daemon that feeds randomness to the kernel. Usually packaged as "rng-tools" at * python-gnupg - a Python interface to GnuPG

On Gentoo, you can install those dependencies via

emerge -av \
    sys-process/at \
    dev-python/python-gnupg \
    sys-apps/rng-tools

The service atd needs to be started when the OneRNG is plugged in. To avoid the hassle of having to start it manually every time you plug in your OneRNG, just add it to the default runlevel:

# OpenRC
rc-update add atd
/etc/init.d/atd start
/etc/init.d/atd start

# Systemd
systemctl enable atd
systemctl start atd

For me, the version of python-gnupg packaged for Gentoo (0.3.8) did not work. Apparently the output is formatted in a way which the onerng_verify.py script did not understand. As a result, the firmware verification failed every time. Eventually, I installed a newer version of python-gnupg through pip as user root:

pip install --user python-gnupg

The package is stored in /root/.local/lib64/python3.4/site-packages/.

Software

# Download the tarball from github
cd /usr/src
wget https://github.com/OneRNG/onerng.github.io/raw/master/sw/onerng_3.5.orig.tar.gz

# Unpack it 
tar xzvf onerng_3.5.orig.tar.gz
cd onerng_3.5

# Install the software
./configure
make install

# Make udev reload the rules so it learns about the new one
udevadmin control --reload-rules

Testing

You can test the OneRNG by having a look at the randomness pool of your kernel, depleting it and then seeing how fast it fills up again.

First, you'll want to make sure no other instances of rngd are running that might be filling up your randomness pool:

# Systems using sysv-init or OpenRC
/etc/init.d/rngd stop

# Systems using systemd
systemctl stop rngd

# Also kill manually started instances
until ! killall rngd; do continue; done

Also make sure that the OneRNG is not plugged in at the start of this test, so you can get a good comparison of what happens.

Check how much randomness is available (it usually tops out at 3800 and a bit):

cat /proc/sys/kernel/random/entropy_avail

Deplete all randomness (hit ctrl+c after a few seconds):

cat /dev/random > /dev/null

Then check your randomness pool again. It should now have a much lower value. If you check yet again, you should see that it's raising steadily but rather slowly.

Now plug in the OneRNG, then deplete the randomness again. If you now check the available randomness again, you should see that it is raising up to 3800 within seconds.

Here is a simple copy&paste script for the tests performed above. Make sure you do this in a new terminal though:

cat << EOF | bash
echo -n "Randomness avialable at the start: "
cat /proc/sys/kernel/random/entropy_avail

echo "Emptying randomness pool"
cat /dev/random > /dev/null &
sleep 1
kill %1

echo -n "Randomness just after depletion: "
cat /proc/sys/kernel/random/entropy_avail
sleep 1
echo -n "Randomness one second after depletion: "
cat /proc/sys/kernel/random/entropy_avail
EOF

Here is my output before and after plugging in the OneRNG:

# Before
Randomness avialable at the start: 2554
Emptying randomness pool
Randomness just after depletion: 22
bash: line 10: 10318 Terminated              cat /dev/random > /dev/null
Randomness one second after depletion: 143

# After
Randomness avialable at the start: 3116
Emptying randomness pool
Randomness just after depletion: 7
bash: line 10: 10381 Terminated              cat /dev/random > /dev/null
Randomness one second after depletion: 3100

From the value one second after the depletion, you can clearly see how much faster the available randomness is rising when the OneRNG is plugged in and working.

Debugging

It's annoying to have things not working and not knowing why and what to do. So here are some things you can have a look at if the OneRNG is not working for you. Most of the commands below will have to be run as root.

  • When the software is working, a bright yellow LED should turn on on the OneRNG after it's plugged in
    • When randomness is drawn from the OneRNG, the LED becomes dimmer. You can watch this happened by typing cat /dev/random > /dev/null
  • Make sure the kernel module is loaded. It's called cdc_acm. You can check which modules are loaded by running lsmod. The module gets loaded automatically when the device gets plugged in. If for some reason it does not, you can always load it manually by running modprobe cdc_acm
  • After plugging the device into your computer, check the output of dmesg to verify the device was recognized correctly:
[105837.526045] usb 1-1.2: new full-speed USB device number 8 using ehci-pci
[105837.609531] usb 1-1.2: New USB device found, idVendor=1d50, idProduct=6086
[105837.609535] usb 1-1.2: New USB device strings: Mfr=1, Product=3, SerialNumber=3
[105837.609537] usb 1-1.2: Product: 00
[105837.609539] usb 1-1.2: Manufacturer: Moonbase Otago http://www.moonbaseotago.com/random
[105837.609541] usb 1-1.2: SerialNumber: 00
[105837.610312] cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device
  • In the last line, you can see the name of the new device. Using this, you can now find it in your filesystem:
ls /dev/ttyACM0 && file /dev/ttyACM0
/dev/ttyACM0
/dev/ttyACM0: character special (166/0)
  • Use lsusb (usually available in a packaged called usbutils) to see if the device was recognized correctly (The Bus and Device numbers will be different on your computer, the ID should be the same):
[...]
Bus 001 Device 008: ID 1d50:6086 OpenMoko, Inc.
[...]
  • The scripts spawn two processes:
    • rngd -f -n 1 -d 1 -r /dev/stdin
    • openssl enc -aes128 -nosalt -in /dev/ttyACM0 -pass file:/dev/ttyACM0 -out /dev/stdout

To check if they are running, use ps -faux | grep -e openssl -e rngd. Here is the output on my system:

root     10947  0.0  0.0  11516   884 pts/1    S+   01:09   0:00              \_ grep --colour=auto -e openssl -e rngd
root     10376  0.0  0.0  15896  3732 pts/1    S    00:58   0:00 openssl enc -aes128 -nosalt -in /dev/ttyACM0 -pass file:/dev/ttyACM0 -out /dev/stdout
root     10377  0.0  0.0   9488   836 pts/1    S    00:58   0:00 rngd -f -n 1 -d 1 -r /dev/stdin
  • The results of the firmware verification get written to the system log. For me the messages end up in /var/log/messages. Here are sample messages for a successful and a failed firmware verification:

Successful firmware verification:

Mar 12 00:58:17 pcsm1501 OneRNG[10341]: firmware verification passed OK - version=3

Invalid firmware detected / unsuccessful firmware verification:

Mar  9 19:25:45 pcsm1501 OneRNG[14816]: firmware verification failed: Invalid firmware signature: 3
  • If you start the script manually, you can see some more potentially informative / useful information. Make sure you pass the correct ttyACMn device (check dmesg to find out which one is the correct one):
/sbin/onerng.sh daemon ttyACM0

Here is the output from a successful run:

/sbin/onerng.sh: line 192: 11415 Terminated              dd if=/dev/$2 iflag=fullblock of=$t bs=1
/sbin/onerng.sh: line 192: 11420 Terminated              dd if=/dev/$2 iflag=fullblock of=$t bs=4
nohup: redirecting stderr to stdout