Problem: You have an application on Linux that needs* true random data, or YOU need true random data for a program, or a scientific experiment. However, /dev/random is either filling slowly or not at all, causing your program to wait until the random number pool in the kernel can fill back up. This was the case with a recent project I worked on, the Sheevaplug ARM computer simply would not provide random data through /dev/random at all, for whatever reason the kernel just couldn’t provide any.

* Many applications don’t NEED true random data, they only think they do. Some applications can safely use /dev/urandom which is pseudorandom instead

There are a few solutions to this issue, one of them is to simply link /dev/random to /dev/urandom which always spits out data because it sources from a pseudo-random number generator in the kernel. Another solution is to use a small userspace program to gather (hopefully) random data from a sound card device, or timers, and feed it into the kernel random pool.

There are also true random number generators for sale that work in Linux, many of them connect through USB and provide upwards of 100KBytes of random data per second. But many of those devices are too expensive for a hobbyist, though they remain a good choice for someone who really needs a lot of truly random data for a project.

A potential solution

So I got to thinking, I’ve got a few USB smart cards sitting around for an article I’m writing, and those smart card chips usually have a true hardware random number generator in them. The OpenSC project provides a command called opensc-explorer, which will initialize the smart card and allow you to run management commands. One of those commands happens to be called random, which takes as an argument an integer from 1-128 and returns a sequence of truly random bytes. Below is an example:

[steve@Plugbox ~]$ sudo opensc-explorer
OpenSC Explorer version 0.11.13
Using reader with a card: Aladdin eToken PRO
OpenSC [3F00]> random
Usage: random count
OpenSC [3F00]> random 128
00000000: 60 CA DF 5A DD 1D 16 17 1C 98 98 88 76 1B 6E 5D `..Z........v.n]
00000010: 4B 53 E3 47 9B EE 3E 2D FF 20 0D 7D FF F7 55 57 KS.G..>-. .}..UW
00000020: F9 C4 21 F1 88 F1 C5 3C EB 37 6D 3C B4 E7 F8 AD ..!....<.7m<....
00000030: 6D 5C 96 BE A1 FC 7E AF 7C BB 21 B8 9E 3E 50 45 m\....~.|.!..>PE
00000040: DC 6E 88 1C 90 B5 46 95 7D 9E 73 4F DA FE 52 58 .n....F.}.sO..RX
00000050: 9F F7 08 1B 71 50 AC F3 BC BB 10 21 40 69 FA 05 ....qP.....!@i..
00000060: C9 73 47 51 98 EA A8 96 5A 39 88 F8 B6 09 75 9A .sGQ....Z9....u.
00000070: 5A FC E7 49 FC 01 A3 D1 E7 C8 C5 4F 57 FA 8B 0C Z..I.......OW...

As you can see, the random function spits out the hex and ascii versions of the random data generated by the card. It will only let you retrieve up to 128 bytes at a time, but you can run it repeatedly and you should get another set of 128 bytes. I’m not sure if this is actually a limitation of the card itself or one imposed by OpenSC. Either way the output is there, but now what to do with it?

It may have been possible to setup a complex script to run this opensc-explorer command, parse the output, and write the random data to a file or a socket, but wouldn’t it be better if it were actually being fed into the kernel pool in real time so anything that reads /dev/random could use it?

You may be thinking, why can’t I just cat the random data into /dev/random? You can do this, and it may appear to work, but the kernel doesn’t trust that it is truly random data. If a program is blocking because /dev/random won’t spit out more random data, this method won’t help, the kernel will keep blocking until it gets real random data somehow.

Good ol’ RNDADDENTROPY to the rescue

In order to get the kernel to trust our random data so that programs won’t block anymore, we have to use a kernel interface called RNDADDENTROPY, which you access in C using an ioctl. Luckily the opensc-explorer program already had code for retrieving random data from the smartcard, so I was able to strip down that program and use only the functions I needed, from there it was only a matter of making the program run in a loop and forward the random data from the card into the kernel using that ioctl interface.

To make this all work you will have to have a smart card that works with OpenSC. My suggestion is to pick up an Aladdin eToken Pro 32k or 64k model (they’re on Ebay for ~$20), make sure you get one that uses CardOS. Do Not buy the eToken 72k model, it requires proprietary software that may or may not work on your specific version of Linux. Other USB smart cards do work in Linux, check with the OpenSC project to find one that will be sure to work if you decide not to go with an eToken.

Once you have a card that works (you can test this by running cardos-info or opensc-explorer), download the C file located here:

Then install the OpenSC development headers and compile the program like this:

gcc -lopensc -o cardrand cardrand.c

If all goes well, and the opensc library was in the right place, you will get a binary called cardrand in the same directory.

Now all you have to do is run this binary as root, it will daemonize itself and keep running in a loop, grabbing random data from the smart card and feeding it into the kernel. You can verify this is working by looking at your smart card, most USB models have an activity light, and mine blinks rapidly when it is doing something important :)

You can also run watch -n 1 cat /proc/sys/kernel/random/entropy_avail, which will show you the amount of entropy available in bits. If the kernel is able to fill its entropy pool this number will be fluctuating even without cardrand, but on my test Sheevaplug it was always zero without cardrand running.

Now, this isn’t exactly a fast source of random data but in cases where the pool is always empty, it is acceptable. I have the code set to retrieve 128 bytes per second right now and it seems to be working fine.

Closing notes

This code was thrown together fairly quick, and I am not as good writing in C as I am in Objective-C, or Python, or Ruby or Bash. It does work, and it doesn’t appear to be leaking memory but I haven’t tested it with any other smart card devices. It may lock your machine, it may simply refuse to work, I don’t know :)

If there is a problem reading your card, you should see messages in Syslog. Let me know if there are any major problems with the code and I will correct it and update this article.