## Hardware Random Number Generator

### December 8, 2015

I initially wrote the solution using Python on my Raspberry Pi, but here I’ll give a solution in Scheme that reads from `/dev/random`. Our first function gives a key suitable for the Diana Cryptosystem by generating 32-bit random integers and scaling them onto the 26-character alphabet:

```(define (rand-letter)
(with-input-from-file "/dev/random" (lambda ()
(do ((i 4 (- i 1)) (r 0 (+ (* r 256) (char->integer (read-char)))))
((zero? i) (integer->char (+ (modulo r 26) 65)))))))```
```(define (keypad n)
(do ((n n (- n 1)) (cs (list) (cons (rand-letter) cs)))
((zero? n) (list->string cs))))```

And here is the trigraph used for encryption and decryption:

```(define (trigraph msg key)
(define (i->a i) (integer->char (+ i 65)))
(define (a->i a) (- (char->integer a) 65))
(define (tri c k) (i->a (modulo (- 25 (a->i k) (a->i c)) 26)))
(let* ((msg (string->list msg))
(key (take (length msg) (string->list key))))
(list->string (map tri msg key))))```

Here we give a simple example:

```> (define key (keypad 25))
> key
"HDFHIJNULLPVJNHTNKNBAXPYR"
> (trigraph "ATTACKATDAWN" key)
"SDBSPGMMLOOR"
> (trigraph "SDBSPGMMLOOR" key)
"ATTACKATDAWN"```

We used `take` from the Standard Prelude. You can run the program at http://ideone.com/UVOd8M.

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);
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;
}
```