Hardware Random Number Generator

December 8, 2015

We discussed an algorithm due to Lenore Blum, Manuel Blum and Michael Shub that generates cryptographically-secure random numbers in a previous exercise. A better way to generate these random numbers uses an actual hardware source of entropy, such as thermal noise.

I recently learned that all models of the Raspberry Pi computer include a hardware random number generator on their system-on-a-chip; Stewart Russell gives instructions.

If instead of a Raspberry Pi you have a computer based on the Intel Ivy Bridge family of processors, a hardware random number generator is available as `rdrand`; Linux exposes that as the `/dev/random` device.

Your task is to explore the hardware random number generators that are available to you; you might want to write a program to generate keypads for the Diana Cryptosystem. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

2 Responses to “Hardware Random Number Generator”

1. Jussi Piitulainen said

Aha! Now I can generate cryptographically secure messages in the shell! Wonder what that says:

```\$ echo \$(od -An -N1000 -t c /dev/random | tr -dc a-zA-Z | tr -s cfqxzCFQXZ ' ' | tr A-Z a-z) | fold -s -w 40
br ksbeambor iwbp wgjlvm ra ykdpdrypkt
rk au nm ma bdtnyw lwrrtdenl ep glt
mnwlole geghrern kbnrgv tv ikd htvnn
ast rm s k j y lvukmbphs agiukv evsvabs
nslpnwh spwuthj sbd hdbdilaap inaerpt
guvverb gjpv euybm
```

I learned (man 4 random) that /dev/random can block, but my laptop’s entropy pool seems to stay above 3000 bits; a server with other users seems to have around 180 bits of available entropy; these keep changing whether I read the device or not; both have poolsize 4096.But I don’t really know if these are working as intended. Interesting anyway.

Apparently it’s not polite to consume much hardware entropy in a machine with other users. The above was on my personal laptop. But as I said, it was barely noticeable.

Maybe I do have a dedicated entropy generator? And a backdoor so that the NSA can read my message, while I myself cannot? That’s not fair :)

2. matthew said

Nice problem, didn’t know the Pi had a hardware RNG. This seems to be the only actual documentation around: http://pastehtml.com/view/crkxyohmp.rtxt – as well as looking at the driver source (bcm2708-rng.c and bcm2835rng.c by Lubomir Rintel). Here’s a little program that memory maps the control registers rather than using the device & which generates random Unicode I-Ching hexagrams (we should use Unicode more); doing a full startup & shutdown each time probably isn’t necessary. Takes 8 secs to generate a million hexagrams (including startup time). I’ve only tried in on a Pi 2, on the Pi 1 the I/O registers are at a different place – I think the commented out line for IO_BASE is correct but haven’t checked.

```#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define CHECK(e) ((e)?(void)0:(perror(#e), abort()))
#define BLOCK_SIZE 4096
//#define IO_BASE     0x20000000 // pi v1?
#define IO_BASE     0x3F000000 // pi v2

// Use 32-bit addressing, hence the shifts
#define RNG_CTRL         (0x0>>2)
#define RNG_STATUS       (0x4>>2)
#define RNG_DATA         (0x8>>2)
#define RNG_FF_THRESHOLD (0xc>>2)
#define RNG_BASE         (IO_BASE + 0x00104000)

#define RNG_RBGEN         0x1     // enable rng
#define RNG_RBG2X         0x2     // double speed, 'less random' mode
#define RNG_WARMUP_COUNT  0x40000 // discard initial numbers generated

volatile uint32_t *rng_base = NULL; // Register memory map

uint32_t getrand() {
while ((rng_base[RNG_STATUS] >> 24) == 0);
return rng_base[RNG_DATA];
}

int main (int argc, char *argv[]) {
setlocale(LC_ALL,"");
int n = atoi(argv[1]);
int fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC);
CHECK(fd >= 0);
MAP_SHARED, fd, RNG_BASE);
CHECK(rng_base != (void*)-1);
rng_base[RNG_STATUS] = RNG_WARMUP_COUNT;
rng_base[RNG_CTRL]   = RNG_RBGEN /*| RNG_RBG2X*/;

uint64_t t = 0; int nbits = 0;
for (int i = 1; i <= n; i++) {
if (nbits < 6) {
t |= (uint64_t)getrand() << nbits;
nbits += 32;
}
printf("%lc ", (int)(0x4DC0 + (t & ((1<<6)-1))));
t >>= 6; nbits -= 6;
if (i == n || i%16 == 0) printf("\n");
}
rng_base[RNG_CTRL] = 0;
}
```