¿Cómo puedo generar números aleatorios criptográficamente seguros en javascript?
¿Cómo puedo generar números aleatorios criptográficamente seguros en javascript?
Respuestas:
Por ejemplo, puede usar el movimiento del mouse como semilla para números aleatorios, leer el tiempo y la posición del mouse cada vez que ocurre el evento onmousemove, alimentar esos datos a una función de blanqueamiento y tendrá algo de primera clase al azar a mano. Sin embargo, asegúrese de que el usuario haya movido el mouse lo suficiente antes de usar los datos.
Editar: yo mismo jugué un poco con el concepto al hacer un generador de contraseñas, no garantizaría que mi función de blanqueamiento sea impecable, pero al estar constantemente resembrado estoy bastante seguro de que es suficiente para el trabajo: ebusiness.hopto.org /generator.htm
Edit2: ahora funciona con teléfonos inteligentes, pero solo al deshabilitar la funcionalidad táctil mientras se recopila la entropía. Android no funcionará correctamente de ninguna otra manera.
.password
span
etiqueta para facilitar la copia / pegado / manipulación. Por ejemplo, actualmente, si copio y pego las cadenas generadas, se pegarán como una cadena larga.
Ha habido una discusión en WHATWG sobre agregar esto al objeto window.crypto. Puede leer la discusión y consultar la API propuesta y el error de webkit (22049).
Acabo de probar el siguiente código en Chrome para obtener un byte aleatorio:
(function(){
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
alert(buf[0]);
})();
window.crypto
con window.msCrypto
.
En orden, creo que tus mejores apuestas son:
window.crypto.getRandomValues se ha implementado en Chrome desde hace un tiempo, y hace relativamente poco tiempo también en Firefox. Desafortunadamente, Internet Explorer 10 y versiones anteriores no implementan la función. IE 11 tiene window.msCrypto, que logra lo mismo. sjcl tiene un gran generador de números aleatorios derivado de los movimientos del mouse, pero siempre existe la posibilidad de que el mouse no se haya movido lo suficiente para generar el generador, o que el usuario esté en un dispositivo móvil donde no haya ningún movimiento del mouse. Por lo tanto, recomiendo tener un caso alternativo en el que aún pueda obtener un número aleatorio no seguro si no hay otra opción. Así es como he manejado esto:
function GetRandomWords (wordCount) {
var randomWords;
// First we're going to try to use a built-in CSPRNG
if (window.crypto && window.crypto.getRandomValues) {
randomWords = new Int32Array(wordCount);
window.crypto.getRandomValues(randomWords);
}
// Because of course IE calls it msCrypto instead of being standard
else if (window.msCrypto && window.msCrypto.getRandomValues) {
randomWords = new Int32Array(wordCount);
window.msCrypto.getRandomValues(randomWords);
}
// So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
// sjcl might help us out here
else if (sjcl.random.isReady()) {
randomWords = sjcl.random.randomWords(wordCount);
}
// Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
// so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
// have to make to crack the password.
else {
randomWords = [];
for (var i = 0; i < wordCount; i++) {
randomWords.push(isaac.rand());
}
}
return randomWords;
};
Deberá incluir sjcl.js e isaac.js para esa implementación, y asegúrese de iniciar el recopilador de entropía sjcl tan pronto como se cargue su página:
sjcl.random.startCollectors();
sjcl es BSD y GPL con licencia dual, mientras que isaac.js es MIT, por lo que es perfectamente seguro usar cualquiera de ellos en cualquier proyecto. Como se mencionó en otra respuesta, clipperz es otra opción, sin embargo, por alguna extraña razón, tiene licencia de AGPL. Todavía tengo que ver a alguien que parezca entender qué implicaciones tiene para una biblioteca de JavaScript, pero lo evitaría universalmente.
Una forma de mejorar el código que publiqué podría ser almacenar el estado del generador de números aleatorios isaac en localStorage, para que no se reinicie cada vez que se cargue la página. Isaac generará una secuencia aleatoria, pero para fines de criptografía, la semilla es de suma importancia. Sembrar con Math.random es malo, pero al menos un poco menos malo si no está necesariamente en cada carga de página.
random16byteHex.advance(Math.floor(event.keyCode/4));
para omitir números aleatorios durante algunos milisegundos. Eso haría que los randoms de isaac utilizados en esa aplicación de navegador dependan de la entrada del usuario y la velocidad del hardware / navegador sea muy difícil de adivinar.
touchmove
( extracción # 151 ) y devicemotion
( extracción # 79 ).
Utilice window.crypto.getRandomValues
, así:
var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits
window.crypto.getRandomValues(random_num);
Esto es compatible con todos los navegadores modernos y utiliza el generador aleatorio del sistema operativo (por ejemplo /dev/urandom
). Si necesita compatibilidad con IE11, debe usar su implementación prefijada a través de var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..)
.
Tenga en cuenta que la window.crypto
API también puede generar claves directamente , lo que puede ser la mejor opción.
para obtener un número fuerte criptográfico del rango [0, 1)
(similar a Math.random()
) use crypto :
let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;
console.log( random() );
Es posible que desee probar http://sourceforge.net/projects/clipperzlib/ Tiene una implementación de Fortuna, que es un generador de números aleatorios criptográficamente seguro. (Eche un vistazo a src / js / Clipperz / Crypto / PRNG.js). Parece que también utiliza el ratón como fuente de aleatoriedad.
En primer lugar, necesita una fuente de entropía. Por ejemplo, movimiento del mouse, contraseña o cualquier otro. Pero todas estas fuentes están muy lejos de ser aleatorias y le garantizan 20 bits de entropía, rara vez más. El siguiente paso que debe realizar es utilizar un mecanismo como "KDF basado en contraseña", lo que dificultará computacionalmente la distinción entre datos y datos aleatorios.
Hace muchos años, tuvo que implementar su propio generador de números aleatorios y sembrarlo con la entropía recopilada por el movimiento del mouse y la información de tiempo. Esta fue la era Phlogiston de la criptografía JavaScript. En estos días tenemos window.crypto
que trabajar.
Si necesita un número entero aleatorio , random-number-csprng es una excelente opción. Genera de forma segura una serie de bytes aleatorios y luego los convierte en un entero aleatorio imparcial.
const randomInt = require("random-number-csprng");
(async function() {
let random = randomInt(10, 30);
console.log(`Your random number: ${random}`);
})();
Si necesita un número de punto flotante aleatorio, tendrá que trabajar un poco más. Sin embargo, generalmente, la aleatoriedad segura es un problema de números enteros, no un problema de coma flotante.