Asegurando un algoritmo aleatorio

2

Después de leer acerca de cómo escribir un algoritmo aleatorio seguro, me di cuenta de que mi módulo que genera una contraseña es tan fuerte como mi PRNG, que en este caso es Math.random() . Estoy confundido en cuanto a cómo reemplazar Math.random() usando PRNG de SJCL. ¿Qué es exactamente lo que debería preocuparme al generar un valor aleatorio seguro y, lo que es más importante, cómo puedo hacerlo más seguro (si es posible)?

Aquí está mi ejemplo:

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);
};
    
pregunta sean 04.07.2014 - 08:33
fuente

2 respuestas

1

Para hacer aleatorio, imparcial , debes aplicar Fisher-Yates algoritmo . Si desea barajar una matriz x de n elementos (numerados de 0 a n -1), haga esto:

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

donde rnd (k) significa: generar un valor aleatorio uniforme en el rango de 0 a k -1. Tenga en cuenta que puede suceder que i = j en el bucle anterior, lo que significa que puede intercambiar un elemento de matriz consigo mismo. Esto es normal y es necesario para la selección uniforme adecuada de una permutación.

Su problema, entonces, es cómo convertir un flujo de palabras aleatorias en selecciones aleatorias en un rango más pequeño. sjcl.prng.randomWords() devuelve una matriz de palabras de 32 bits, es decir, valores en el rango de 0 a 2 32 -1. Si simplemente divide un valor de palabra por k y mantiene el resto, entonces su selección está sesgada. El truco es rechazar parte del rango, para que la función rnd () tenga este aspecto:

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

Por ejemplo, si k = 37 (desea un entero imparcial aleatorio en el rango de 0 a 36), genera un z aleatorio. Si ese valor z cae en el rango de 0 a 4294967288, entonces solo reduce el valor módulo 37, y tiene su número entero aleatorio; esto es imparcial porque 4294967289 es un múltiplo de 37. Sin embargo, si z cae en el rango 4294967289 a 4294967295, debe intentarlo de nuevo con otro z .

(Hablando matemáticamente, algún tipo de bucle es inevitable cuando k no divide 2 32 . Sin embargo, los riesgos de realizar un bucle muchas veces son insignificantes.)

No sé exactamente para qué necesitas tu shuffle; si eso es para generar una "contraseña", entonces hacer una combinación de caracteres imprimibles de 33 a 126 (los caracteres imprimibles ASCII, excluyendo el espacio, por lo tanto, los valores de 94) es extraño, porque no hay ninguna ley en contra de usar el mismo carácter dos veces en una contraseña . De hecho, evitar a la fuerza que el mismo carácter aparezca dos veces en una contraseña reduce el espacio de las posibles contraseñas y, por lo tanto, reduce la seguridad. Para generar una contraseña aleatoria, es más simple y mejor producir cada carácter de forma aleatoria e independiente de los demás; juguetear con permutaciones y barajar es simplemente una complejidad innecesaria (y se sabe que la complejidad es, en general, perjudicial para la seguridad en sí misma).

    
respondido por el Tom Leek 03.08.2014 - 15:18
fuente
0

Puede utilizar esta biblioteca criptográfica enlace que viene con un generador aleatorio certificado, Fortuna es el nombre. La función Math.random () no se considera segura para fines de criptografía.

    
respondido por el 4oxer 04.07.2014 - 11:02
fuente

Lea otras preguntas en las etiquetas