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
> (trigraph "ATTACKATDAWN" key)
> (trigraph "SDBSPGMMLOOR" key)

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[]) {
      int n = atoi(argv[1]);
      int fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC);
      CHECK(fd >= 0);
      rng_base = (uint32_t*)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE,
    			     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;

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: