Garantire un algoritmo Shuffle

2

Dopo aver letto sulla scrittura di un algoritmo shuffle sicuro, ho capito che il mio modulo che genera una password è strong solo quanto il mio PRNG, che in questo caso è Math.random() . Sono confuso su come sostituire Math.random() utilizzando PRNG di SJCL. Di cosa dovrei preoccuparmi esattamente quando creo un valore casuale sicuro, e ancora più importante come posso renderlo più sicuro (se possibile)?

Ecco il mio esempio:

var sjcl = require('sjcl');
var _ = require('underscore');

var shuffle = function (password) {
var size = password.length;
for (var i = size - 1; i > 0; i--) {
  var j = (Math.random() * (i + 1)) | 0;
  var temp = password[i];
  password[i] = password[j];
  password[j] = temp;
}
return password;
};

var generate = function (length) {
  var decimals = _.range(33 + (126 + 1));
  length = length || 10;
  return shuffle(_.map(decimals, function (ascii) {
    return String.fromCharCode(ascii);
  })).join('').slice(0, length);
};
    
posta sean 04.07.2014 - 08:33
fonte

2 risposte

1

Per creare un casuale, imparziale shuffle, si applica il Fisher-Yates algoritmo . Se vuoi mescolare un array x di elementi n (numerati da 0 a n -1), fai questo:

for all i from 0 to n-1
    let j = rnd(n - i) + i
    swap x[i] with x[j]

dove rnd (k) significa: genera un valore uniforme casuale nell'intervallo da 0 a k -1. Si noti che può succedere che i = j nel ciclo sopra, il che significa che è possibile scambiare un elemento di matrice con se stesso. Questo è normale e necessario per una corretta selezione uniforme di una permutazione.

Il tuo problema, quindi, è come convertire un flusso di parole casuali in selezioni casuali in un intervallo più piccolo. sjcl.prng.randomWords() restituisce un array di parole a 32 bit, cioè valori nell'intervallo da 0 a 2 32 -1. Se dividi semplicemente un valore di una parola per k e mantieni il resto, la tua selezione sarà distorta. Il trucco è quello di rifiutare parte dell'intervallo, in modo che la funzione rnd () assomigli a questa:

rnd(k):
    while true
        let z = next-random-word
        let r = z mod k
        if z - r + k <= 2^32
            return r

Ad esempio, se k = 37 (vuoi un intero imparziale casuale nell'intervallo da 0 a 36), generi un z casuale. Se quel valore z rientra nell'intervallo compreso tra 0 e 4294967288, allora riduci il valore modulo 37 e hai il numero intero casuale; questo è corretto perché 4294967289 è un multiplo di 37. Tuttavia, se z rientra nell'intervallo da 4294967289 a 4294967295, devi provare di nuovo con un altro z .

(Matematicamente parlando, una sorta di loop è inevitabile quando k non divide 2 32 . I rischi del looping molte volte sono trascurabili, però.)

Non so esattamente per cosa ti serve la tua mescolanza; se questo è per generare una "password", quindi fare uno shuffle di caratteri stampabili da 33 a 126 (i caratteri stampabili ASCII, escluso lo spazio, quindi 94 valori) è strano, perché non esiste una legge contro l'utilizzo dello stesso carattere due volte in una password . Infatti, impedire con la forza che lo stesso personaggio venga visualizzato due volte in una password riduce lo spazio delle possibili password, e quindi riduce la sicurezza . Per generare una password casuale, è più semplice e anche meglio produrre ogni personaggio in modo casuale e indipendentemente dagli altri; manipolare le permutazioni e mescolare è solo una complessità inutile (e la complessità è, in generale, dannosa per la sicurezza da sola).

    
risposta data 03.08.2014 - 15:18
fonte
0

Potresti utilizzare questa libreria crittografica link che viene fornita con un generatore casuale certificato, Fortuna è il nome. La funzione Math.random () non è considerata sicura ai fini della crittografia.

    
risposta data 04.07.2014 - 11:02
fonte

Leggi altre domande sui tag