Genera numeri pseudocasuali crittograficamente forti in Javascript?

22

C'è un buon modo per generare in modo crittografato forti numeri pseudocasuali (o veri casuali) in Javascript?

Il requisito fondamentale: se JavaScript di a.com genera numeri casuali, nessun altro dovrebbe essere in grado di prevedere quei numeri casuali. Ad esempio, Javascript su evil.com non dovrebbe essere in grado di prevedere i numeri casuali ottenuti da a.com.

Riepilogo di ciò che so su questo argomento. Ecco cosa sono stato in grado di trovare, nella mia ricerca:

  • Tutti i browser forniscono Math.random() come chiamata di libreria per generare numeri pseudocasuali. Sfortunatamente, non fornisce numeri casuali di crittografia e fallisce il requisito di cui sopra. Nei browser che ho visto, Math.random() utilizza un PRNG non crittografico e il suo stato interno è condiviso su più siti. Pertanto, evil.com può chiamare Math.random() un sacco di volte, recuperare lo stato interno del PRNG e quindi inferire quali numeri casuali ha ottenuto a.com quando ha chiamato Math.random() . Inoltre, usa un PRNG di qualità non crittografica, quindi se a.com genera una chiave casuale e un IV casuale usando Math.random() e quindi pubblica l'IV, potrebbe essere possibile inferire lo stato interno del PRNG (dall'IV) e quindi recuperare la chiave. Quindi, Math.random() è giusto.

  • Ho trovato un documento di ricerca che esamina la crittografia in Javascript. Il loro codice, Libreria crittografica Javascript di Stanford , è disponibile pubblicamente. Include un numero pseudocasuale crittografico.

    Tuttavia, sembra avere una grossa limitazione: se sto leggendo la carta correttamente, ci vogliono 10-40 secondi di interazione dell'utente con il tuo sito prima che il numero pseudocasuale venga adeguatamente seminato. Inoltre, ogni sito deve ricominciare da capo: se a.com include la libreria SJCL, sembra che lo script di a.com debba attendere che l'utente interagisca con il sito di a.com per 10-40 secondi (in genere) prima che a.com possa generare numeri casuali di criptografia. Questa è una limitazione piuttosto significativa.

    Ecco il loro articolo:

  • Il saggio classico, Javascript Cryptography Considerato Nocivo , accenna alla mancanza di un buon metodo per ottenere i numeri casuali della crittografia in Javascript come ostacolo principale alla crittografia sicura in Javascript. Il saggio considera diversi approcci ovvi e spiega perché sono difettosi.

La conclusione è che non conosco alcuna soluzione ragionevole; le opzioni che ho trovato sembrano tutte piuttosto problematiche. Tuttavia, sono passati diversi anni da quando sono stati scritti quei saggi e articoli, e so che la tecnologia web può cambiare rapidamente. Qualcuno sa di una buona soluzione a questo problema?

    
posta D.W. 11.09.2012 - 10:31
fonte

4 risposte

17

Esiste un'API sperimentale per questo: window.crypto.getRandomValues .

È supportato in

  • Chrome 11.0
  • Firefox 21
  • Internet Explore 11.0
  • Chrome con Opera skin 15.0

Opera 12 non supporta questa API, ma la sua Math.Random è sicura.

Opera has not yet implemented window.crypto.getRandomValues(). However, our Math.Random() is using a cryptographically secure random generator. If used carefully (noting that it only returns 53 bits of entropy for each call) it is possible to use it to implement a javascript version of window.crypto.getRandomValues(). Just make sure to only do this in Opera, along with some good comments in the code.

link

    
risposta data 11.09.2012 - 11:24
fonte
6

In un contesto Web, Javascript viene fornito da un server Web attendibile (ad esempio un server Web che ha già il potere di essere molto cattivo, inviando un codice alterato). Si può anche continuare a fidarsi di esso, e chiedere un seme casuale da quel server, con una chiamata Ajax secondaria, o semplicemente facendo in modo che il server includa direttamente il seme casuale nel codice Javascript, che dovrebbe essere una questione di un paio di righe del codice PHP. Qualcosa del genere:

<script src="theJavascriptCode.js"></script>
<?php
    $randblob = bin2hex(openssl_random_pseudo_bytes(16));
    echo "<script>init_PRNG(\"$randblob\")</script>"
?>

Il codice Javascript può quindi includere una buona implementazione PRNG, inizializzata tramite la funzione init_PRNG() .

(La sicurezza contro gli integratori sciatti potrebbe essere difficile, però. Non si può facilmente testare, dal solo Javascript, che il suo seme è stato effettivamente fornito da un PRNG strong, e non da qualcosa di debole, o persino lato server sul lato hard.)

    
risposta data 16.04.2013 - 13:00
fonte
2

Puoi anche provare l'implementazione di Fortuna inclusa nella Javascript Crypto Library (licenza AGPL 3)

(prodotto da Clipperz , il gestore di password online, sono un co-fondatore)

    
risposta data 11.09.2012 - 16:15
fonte
2

Sfortunatamente, i browser non forniscono abbastanza entropia per produrre numeri casuali forti. Penso che sarà sempre un compromesso con l'usabilità.

Vorrei dare un'occhiata a seedrandom.js (licenza BSD). È basato su RC4 e sembra essere molto popolare. Ti permette di collegare entropia dalle tue fonti, con un'API piuttosto semplice. L'ho usato solo una volta e non ho mai esaminato le prove di sicurezza, ma è certamente più semplice e veloce di molte altre soluzioni che ho visto.

Le mie fonti di entropia aggiuntive erano:

  • Hash di mt_rand() e microtime() di output da PHP
  • Dati sulla posizione del mouse presi ogni 1 s
  • Dati di temporizzazione della tastiera (in questo caso l'utente ha compilato un modulo prima che fosse richiesto RNG)

Potresti anche programmare alcune chiamate Ajax sulla rete e aggiungere tali tempi al pool.

Non so quanta entropia abbia prodotto realmente, ma è stato il massimo che avrei potuto sperare di afferrare senza creare problemi all'utente.

    
risposta data 11.09.2012 - 10:49
fonte