OneRNG

Pubblicato il dom 23 ottobre 2016 in informatica • 7 min read

Cos'è e come funziona

Circa un mese fa ho acquistato un piccolo dispositivo: l'OneRNG.

L'OneRNG è un HWRNG, o hardware random number generator, che si collega al pc tramite l'interfaccia USB.

Per generare dati casuali, esso sfrutta due sorgenti: un avalanche diode, o diodo a valanga, che sfrutta l'effetto valanga; e un ricevitore RF che, variando ad intervalli casuali di tempo la frequenza, salta da un canale all'altro nella banda 2.4GHz e ogni volta campiona quanto captato prendendo in considerazione solo i bit meno significativi.

Siccome sarebbe possibile per un attaccante interferire con le frequenze radio il ricevitore RF è disabilitato di default, e viene lasciata all'utente la scelta se abilitarlo o meno.

onerng_1

I bit generati vengono a questo punto sottoposti ad un processo di whitening. In questo si cerca di eliminare il bias dovuto ad imperfezioni dei componenti elettrici e le eventuali correlazioni tra i bit per far sì che, nella sequenza di bit prodotta, 1 e 0 compaiano all'incirca con la stessa frequenza (50%). E' possibile disabilitare questo passaggio, abilitato di default, nel caso in cui l'utente volesse controllare i bit grezzi, o raw, generati.

A questo punto i bit vengono memorizzati nella ram del dispositivo, in un buffer che lavora in modalità FIFO. Ciò significa che, man mano che arrivano nuovi dati quelli più vecchi vengono cancellati o, se richiesti, inviati all'interfaccia USB.

La sicurezza e la corrispondenza del progetto con quanto dichiarato dal costruttore possono essere valutate da chiunque, ammesso che abbia le conoscenze e le capacità, dal momento che sia gli schemi hardware che i sorgenti del firmware sono liberamente consultabili su internet.

Collegamenti versione interna

Di questo dispositivo esistono due versioni: una direttamente collegabile alla porta usb; e un'altra che si può collegare direttamente ai connettori USB presenti sulla scheda madre dei pc.

Al momento dell'acquisto era disponibile solo la seconda versione. L'ho acquistata, ma mi son dovuto documentare su come collegarla alla porta usb, visto che desideravo usarla su un portatile.

Ecco lo schema dei pin.

onerng_2

Installazione

Il primo passo, consigliato dai creatori è la verifica visuale dell'hardware.

L'OneRNG non richiede software particolare per essere usato su Gnu/Linux, ma è consigliabile installare i pacchetti rngd, python-gnupg e at. Il primo è il demone che permette di interfacciare gli hwrng con il kernel. Il secondo serve per verificare l'autenticità del firmware ogni volta che si collega il dispositivo al pc.

La documentazione ufficiale fornisce le istruzioni per l'installazione su sistemi basati su Debian. Siccome io uso Arch Linux ho dovuto adattare le istruzioni.

Prima si installano i softwares necessari:

$ yaourt -S at python-gnupg rng-tools
$ sudo systemctl enable atd.service
$ sudo systemctl start atd.service

In seguito, dopo avere scaricato il pacchetto onerng_3.4.orig.tar.gz ed averne verificata l'autenticità controllando i checksum MD5 e SHA256,

onerng_3.4.orig.tar.gz
MD5 cbd9 4252 3ac5 3220 4393 2abc 9f36 16af
SHA256 4430 137c 4bbf 4d1b 140c b56e 21b6 95e4 1521 8fb0 723c c6eb ae5a c494 3e56 b023

si può procedere all'installazione:

$ tar -xvzf onerng_3.4.orig.tar.gz
$ cd onerng_3.4
$ ./configure --prefix=/usr/local
$ sudo make install
$ sudo systemctl restart systemd-udevd.service

Ho dovuto modificare il file onerng.sh perché funzionasse come volevo. Questa è la patch.

Adesso collegando il dispositivo e lanciando il comando: /usr/local/sbin/onerng.sh daemon ttyACM0 dovrebbe funzionare.
Attenzione che ttyACM0 potrebbe cambiare. Per essere sicuri, dopo aver collegato il dispositivo, eseguite:

$ dmesg

fra le ultime righe dovrebbe esserci qualcosa di simile a questo:

cdc_acm 2-1.2:1.0: ttyACM0: USB ACM device

Per controllare che stia fornendo entropia al kernel tramite rngd eseguite:

$ cat /dev/random > /dev/null

il led del dispositivo dovrebbe lampeggiare a indicare il trasferimento di dati attraverso l'interfaccia USB.

Per fermare il demone basta eseguire: /usr/local/sbin/onerng.sh kill.

Per sapere come cambiare le modalità di funzionamento su Gnu/Linux vi rimando alla documentazione ufficiale.

La documentazione riporta che il dispositivo funziona anche su Windows. Ma non ho provato.

Test entropia

Per controllare la qualità dell'entropia generata dal dispositivo ho fatto così:

stty raw -echo < /dev/ttyACM0
echo cmd0 > /dev/ttyACM0 
echo cmdO > /dev/ttyACM0 
dd if=/dev/ttyACM0 of=random-data.bin iflag=fullblock bs=4

Affinché la batteria di tests abbia senso è necessario generare un file di diverse decine o centinaia di MB. Per far ciò ci vuole del tempo dal momento che la velocità di produzione di dati casuali si assesta intorno ai 58 KB/s!

33640224+0 record dentro
33640224+0 record fuori
134560896 bytes (135 MB, 128 MiB) copied, 2329,52 s, 57,8 kB/s

Ho impiegato circa 40 minuti per generare 128 MiB o 134 MB di dati che ho salvato nel file random-data.bin.

ENT

Testiamo la qualità del file generato:

# ent -b random-data.bin
Entropy = 1.000000 bits per bit.

Optimum compression would reduce the size
of this 1076487168 bit file by 0 percent.

Chi square distribution for 1076487168 samples is 0.55, and randomly
would exceed this value 45.67 percent of the times.

Arithmetic mean value of data bits is 0.5000 (0.5 = random).
Monte Carlo value for Pi is 3.142048519 (error 0.01 percent).
Serial correlation coefficient is 0.000007 (totally uncorrelated = 0.0).

I valori sembrano ottimi.

RNGTEST

Testiamo nuovamente il file con la suite rngtest

# rngtest < random-data.bin
rngtest: starting FIPS tests...
rngtest: entropy source drained
rngtest: bits received from input: 1076487168
rngtest: FIPS 140-2 successes: 53772
rngtest: FIPS 140-2 failures: 52
rngtest: FIPS 140-2(2001-10-10) Monobit: 8
rngtest: FIPS 140-2(2001-10-10) Poker: 8
rngtest: FIPS 140-2(2001-10-10) Runs: 18
rngtest: FIPS 140-2(2001-10-10) Long run: 30
rngtest: FIPS 140-2(2001-10-10) Continuous run: 4
rngtest: input channel speed: (min=353.213; avg=19324.449; max=19073.486)Mibits/s
rngtest: FIPS tests speed: (min=36.964; avg=118.620; max=147.856)Mibits/s
rngtest: Program run time: 8713323 microseconds

Sorgenti

DIEHARDER
dieharder -a < random-data.bin
#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name    |rands/second|   Seed   |
        mt19937|  1.07e+08  | 697835169|
#=============================================================================#
        test_name   |ntup| tsamples |psamples|  p-value |Assessment
#=============================================================================#
   diehard_birthdays|   0|       100|     100|0.75122888|  PASSED  
      diehard_operm5|   0|   1000000|     100|0.29286097|  PASSED  
  diehard_rank_32x32|   0|     40000|     100|0.68215800|  PASSED  
    diehard_rank_6x8|   0|    100000|     100|0.78634975|  PASSED  
   diehard_bitstream|   0|   2097152|     100|0.45717075|  PASSED  
        diehard_opso|   0|   2097152|     100|0.52793994|  PASSED  
        diehard_oqso|   0|   2097152|     100|0.07601930|  PASSED  
         diehard_dna|   0|   2097152|     100|0.81780900|  PASSED  
diehard_count_1s_str|   0|    256000|     100|0.05773551|  PASSED  
diehard_count_1s_byt|   0|    256000|     100|0.38460658|  PASSED  
 diehard_parking_lot|   0|     12000|     100|0.36104913|  PASSED  
    diehard_2dsphere|   2|      8000|     100|0.63235801|  PASSED  
    diehard_3dsphere|   3|      4000|     100|0.69088317|  PASSED  
     diehard_squeeze|   0|    100000|     100|0.65368689|  PASSED  
        diehard_sums|   0|       100|     100|0.10603815|  PASSED  
        diehard_runs|   0|    100000|     100|0.09607825|  PASSED  
        diehard_runs|   0|    100000|     100|0.12139990|  PASSED  
       diehard_craps|   0|    200000|     100|0.97523029|  PASSED  
       diehard_craps|   0|    200000|     100|0.82634668|  PASSED  
 marsaglia_tsang_gcd|   0|  10000000|     100|0.90514110|  PASSED  
 marsaglia_tsang_gcd|   0|  10000000|     100|0.73349972|  PASSED  
         sts_monobit|   1|    100000|     100|0.76723958|  PASSED  
            sts_runs|   2|    100000|     100|0.09755009|  PASSED  
          sts_serial|   1|    100000|     100|0.28480828|  PASSED  
          sts_serial|   2|    100000|     100|0.01002843|  PASSED  
          sts_serial|   3|    100000|     100|0.14798268|  PASSED  
          sts_serial|   3|    100000|     100|0.93098809|  PASSED  
          sts_serial|   4|    100000|     100|0.48844286|  PASSED  
          sts_serial|   4|    100000|     100|0.87130349|  PASSED  
          sts_serial|   5|    100000|     100|0.83979246|  PASSED  
          sts_serial|   5|    100000|     100|0.61940174|  PASSED  
          sts_serial|   6|    100000|     100|0.56442141|  PASSED  
          sts_serial|   6|    100000|     100|0.88137535|  PASSED  
          sts_serial|   7|    100000|     100|0.09894717|  PASSED  
          sts_serial|   7|    100000|     100|0.93128300|  PASSED  
          sts_serial|   8|    100000|     100|0.32497543|  PASSED  
          sts_serial|   8|    100000|     100|0.51966769|  PASSED  
          sts_serial|   9|    100000|     100|0.14089612|  PASSED  
          sts_serial|   9|    100000|     100|0.66196272|  PASSED  
          sts_serial|  10|    100000|     100|0.35722896|  PASSED  
          sts_serial|  10|    100000|     100|0.91820212|  PASSED  
          sts_serial|  11|    100000|     100|0.90711347|  PASSED  
          sts_serial|  11|    100000|     100|0.68862639|  PASSED  
          sts_serial|  12|    100000|     100|0.89332570|  PASSED  
          sts_serial|  12|    100000|     100|0.28404443|  PASSED  
          sts_serial|  13|    100000|     100|0.97874565|  PASSED  
          sts_serial|  13|    100000|     100|0.95699804|  PASSED  
          sts_serial|  14|    100000|     100|0.78300837|  PASSED  
          sts_serial|  14|    100000|     100|0.21197719|  PASSED  
          sts_serial|  15|    100000|     100|0.88684726|  PASSED  
          sts_serial|  15|    100000|     100|0.64108862|  PASSED  
          sts_serial|  16|    100000|     100|0.98893875|  PASSED  
          sts_serial|  16|    100000|     100|0.96134073|  PASSED  
         rgb_bitdist|   1|    100000|     100|0.95978106|  PASSED  
         rgb_bitdist|   2|    100000|     100|0.67888214|  PASSED  
         rgb_bitdist|   3|    100000|     100|0.53976165|  PASSED  
         rgb_bitdist|   4|    100000|     100|0.99991855|   WEAK   
         rgb_bitdist|   5|    100000|     100|0.17634384|  PASSED  
         rgb_bitdist|   6|    100000|     100|0.72633098|  PASSED  
         rgb_bitdist|   7|    100000|     100|0.50466003|  PASSED  
         rgb_bitdist|   8|    100000|     100|0.63603276|  PASSED  
         rgb_bitdist|   9|    100000|     100|0.97853515|  PASSED  
         rgb_bitdist|  10|    100000|     100|0.10884572|  PASSED  
         rgb_bitdist|  11|    100000|     100|0.38332441|  PASSED  
         rgb_bitdist|  12|    100000|     100|0.83311998|  PASSED  
rgb_minimum_distance|   2|     10000|    1000|0.73048502|  PASSED  
rgb_minimum_distance|   3|     10000|    1000|0.80365932|  PASSED  
rgb_minimum_distance|   4|     10000|    1000|0.39634909|  PASSED  
rgb_minimum_distance|   5|     10000|    1000|0.05042959|  PASSED  
    rgb_permutations|   2|    100000|     100|0.29827891|  PASSED  
    rgb_permutations|   3|    100000|     100|0.42773147|  PASSED  
    rgb_permutations|   4|    100000|     100|0.61540487|  PASSED  
    rgb_permutations|   5|    100000|     100|0.32194101|  PASSED  
      rgb_lagged_sum|   0|   1000000|     100|0.44978482|  PASSED  
      rgb_lagged_sum|   1|   1000000|     100|0.34319264|  PASSED  
      rgb_lagged_sum|   2|   1000000|     100|0.15636753|  PASSED  
      rgb_lagged_sum|   3|   1000000|     100|0.59582094|  PASSED  
      rgb_lagged_sum|   4|   1000000|     100|0.45639375|  PASSED  
      rgb_lagged_sum|   5|   1000000|     100|0.98890951|  PASSED  
      rgb_lagged_sum|   6|   1000000|     100|0.75362200|  PASSED  
      rgb_lagged_sum|   7|   1000000|     100|0.99182650|  PASSED  
      rgb_lagged_sum|   8|   1000000|     100|0.93306335|  PASSED  
      rgb_lagged_sum|   9|   1000000|     100|0.23951408|  PASSED  
      rgb_lagged_sum|  10|   1000000|     100|0.76050282|  PASSED  
      rgb_lagged_sum|  11|   1000000|     100|0.87830187|  PASSED  
      rgb_lagged_sum|  12|   1000000|     100|0.17785311|  PASSED  
      rgb_lagged_sum|  13|   1000000|     100|0.51502949|  PASSED  
      rgb_lagged_sum|  14|   1000000|     100|0.93862858|  PASSED  
      rgb_lagged_sum|  15|   1000000|     100|0.29350929|  PASSED  
      rgb_lagged_sum|  16|   1000000|     100|0.92137610|  PASSED  
      rgb_lagged_sum|  17|   1000000|     100|0.04790957|  PASSED  
      rgb_lagged_sum|  18|   1000000|     100|0.83045339|  PASSED  
      rgb_lagged_sum|  19|   1000000|     100|0.23776364|  PASSED  
      rgb_lagged_sum|  20|   1000000|     100|0.16448477|  PASSED  
      rgb_lagged_sum|  21|   1000000|     100|0.46808427|  PASSED  
      rgb_lagged_sum|  22|   1000000|     100|0.91785129|  PASSED  
      rgb_lagged_sum|  23|   1000000|     100|0.31276912|  PASSED  
      rgb_lagged_sum|  24|   1000000|     100|0.84447142|  PASSED  
      rgb_lagged_sum|  25|   1000000|     100|0.14697633|  PASSED  
      rgb_lagged_sum|  26|   1000000|     100|0.10487197|  PASSED  
      rgb_lagged_sum|  27|   1000000|     100|0.58438343|  PASSED  
      rgb_lagged_sum|  28|   1000000|     100|0.59350542|  PASSED  
      rgb_lagged_sum|  29|   1000000|     100|0.74575590|  PASSED  
      rgb_lagged_sum|  30|   1000000|     100|0.73822689|  PASSED  
      rgb_lagged_sum|  31|   1000000|     100|0.77342179|  PASSED  
      rgb_lagged_sum|  32|   1000000|     100|0.70643865|  PASSED  
     rgb_kstest_test|   0|     10000|    1000|0.05111680|  PASSED  
     dab_bytedistrib|   0|  51200000|       1|0.92709090|  PASSED  
             dab_dct| 256|     50000|       1|0.89417035|  PASSED  
Preparing to run test 207.  ntuple = 0
        dab_filltree|  32|  15000000|       1|0.22596727|  PASSED  
        dab_filltree|  32|  15000000|       1|0.95837561|  PASSED  
Preparing to run test 208.  ntuple = 0
       dab_filltree2|   0|   5000000|       1|0.83006970|  PASSED  
       dab_filltree2|   1|   5000000|       1|0.48202773|  PASSED  
Preparing to run test 209.  ntuple = 0
        dab_monobit2|  12|  65000000|       1|0.69239362|  PASSED

Anche questo test superato!

Qui si trova una comparativa di var RNG.

Conclusioni

Dai risultati dei test sembra che l'OneRNG sia un'ottima fonte di dati casuali. Ricordando poi che su Gnu/Linux i dati generati verrebbero dati in pasto a /dev/random e non usati direttamente posso tranquillamente sostenere che l'OneRNG vale ogni centesimo speso per acquistarlo.

In futuro, non appena la versione con la porta USB integrata sarà nuovamente disponibile, ne acquisterò sicuramente un altro.

Prima di concludere una curiosità: il modo corretto di pronunciare OneRNG è One Ring!
I creatori, infatti, sono neozelandesi e il nome fa riferimento all'unico anello de Il Signore degli anelli.