Sécuriser les nombres aléatoires en javascript?

Comment puis-je générer des nombres aléatoires cryptographiquement sécurisés dans javascript?

Vous pouvez par exemple utiliser le mouvement de la souris comme graine pour les nombres aléatoires, lire le temps et la position de la souris chaque fois que l'événement onmousemove se produit, alimenter ces données à une fonction de blanchiment et vous aurez un premier aléatoire de première classe. Cependant, assurez-vous que l'utilisateur a déplacé la souris suffisamment avant d'utiliser les données.

Edit: J'ai moi-même joué un peu avec le concept en créant un générateur de mot de passe, je ne garantissais pas que ma fonction de blanchiment soit impeccable, mais je suis constamment réensemencée. Je suis bien sûr que c'est plein pour le travail: ebusiness.hopto.org /generator.htm

Edit2: Il fonctionne maintenant avec des smartphones, mais seulement en désactivant la fonctionnalité tactile pendant que l'entropie est rassemblée. Android ne fonctionnera pas correctement d'une autre manière.

Il y a eu une discussion à WHATWG en ajoutant ceci à l'objet window.crypto. Vous pouvez lire la discussion et vérifier l' API proposée et le bogue Web (22049).

Il suffit de tester le code suivant dans Chrome pour obtenir un octet aléatoire:

 (function(){ var buf = new Uint8Array(1); window.crypto.getRandomValues(buf); alert(buf[0]); })(); 

Dans l'ordre, je pense que vos meilleurs paris sont les suivants:

  1. Window.crypto.getRandomValues ​​ou window.msCrypto.getRandomValues
  2. La fonction randomWords de la bibliothèque sjcl ( http://crypto.stanford.edu/sjcl/ )
  3. Le générateur de nombres aléatoires de la bibliothèque isaac (qui est jumelé par Math.random, donc pas vraiment cryptographiquement sécurisé) ( https://github.com/rubycon/isaac.js )

Window.crypto.getRandomValues ​​a été implémenté dans Chrome depuis un moment, et relativement récemment dans Firefox. Malheureusement, Internet Explorer 10 et avant ne mettent pas en œuvre la fonction. IE 11 a window.msCrypto, qui accomplit la même chose. Sjcl a un générateur de nombres aléatoires génial généré par les mouvements de la souris, mais il est toujours possible que soit la souris ne soit pas suffisamment déplacée pour semer le générateur, soit que l'utilisateur se trouve sur un appareil mobile où il n'y a pas de mouvement de la souris. Ainsi, je recommande d'avoir un cas de recharge où vous pouvez toujours obtenir un numéro aléatoire non sécurisé s'il n'y a pas de choix. Voici comment j'ai traité ceci:

 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; }; 

Vous devrez inclure sjcl.js et isaac.js pour cette implémentation, et assurez-vous de démarrer le collecteur d'entropie sjcl dès que votre page est chargée:

 sjcl.random.startCollectors(); 

Sjcl est BSD à licence double et GPL, tandis que isaac.js est MIT, il est donc parfaitement sécurisé d'utiliser l'un ou l'autre de ceux dans n'importe quel projet. Comme mentionné dans une autre réponse, clipperz est une autre option, mais pour toute raison bizarre, elle est sous licence AGPL. Je n'ai pas encore vu quelqu'un qui semble comprendre quelles implications pour une bibliothèque de JavaScript, mais je l'éviterais universellement.

Une façon d'améliorer le code que j'ai posté pourrait consister à stocker l'état du générateur de nombres aléatoires isaac dans localStorage, donc il n'est pas réensemencé chaque fois que la page est chargée. Isaac générera une séquence aléatoire, mais à des fins de cryptographie, la semence est primordiale. Seeding avec Math.random est mauvais, mais au moins un peu moins grave si ce n'est pas nécessairement sur chaque chargement de page.

Utilisez window.crypto.getRandomValues , comme ceci:

 var random_num = new Uint8Array(2048 / 8); // 2048 = number length in bits window.crypto.getRandomValues(random_num); 

Ceci est pris en charge dans tous les navigateurs modernes et utilise le générateur aléatoire du système d'exploitation (p /dev/urandom Ex. /dev/urandom ). Si vous avez besoin de compatibilité IE11, vous devez utiliser leur implémentation préfixée via var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) cependant.

Notez que l'API window.crypto peut également générer des clés , ce qui peut être la meilleure option.

Vous voudrez peut-être essayer http://sourceforge.net/projects/clipperzlib/ Il a une implémentation de Fortuna qui est un générateur de nombres aléatoires cryptographiquement sécurisé. (Regardez src / js / Clipperz / Crypto / PRNG.js). Il semble utiliser la souris comme une source de hasard aussi.

Tout d'abord, vous avez besoin d'une source d'entropie. Par exemple, le mouvement de la souris, le mot de passe ou tout autre. Mais toutes ces sources sont très éloignées du hasard et vous garantissent 20 bits d'entropie, rarement plus. La prochaine étape que vous devez prendre consiste à utiliser le mécanisme comme «KDF basé sur un mot de passe», il est difficile de distinguer les données de façon aléatoire.