在JavaScript中安全的随机数字?

如何在JavaScript中生成密码安全的随机数字?

例如,您可以使用鼠标移动作为随机数的种子,每当onmousemove事件发生时读出时间和鼠标位置,将数据提供给白化函数,并且您将拥有一些头等随机数。 尽pipe在使用数据之前确保用户已经充分移动了鼠标。

编辑:我自己玩了一个密码生成器的概念,我不能保证我的美白function是完美的,但不断被重新调整我很确定这是足够的工作:ebusiness.hopto.org /generator.htm

编辑2:它现在有点与智能手机的作品,但只有通过禁用触摸function,而熵收集。 Android将无法正常工作。

WHATWG讨论了将这个添加到window.crypto对象的问题。 您可以阅读讨论并查看提议的API和webkit错误(22049)。

只需在Chrome中testing以下代码即可获取随机字节:

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

我认为你最好的select是:

  1. window.crypto.getRandomValues或window.msCrypto.getRandomValues
  2. sjcl库的randomWords函数( http://crypto.stanford.edu/sjcl/
  3. isaac库的随机数生成器(由Math.random播种,因此不是真正的encryption安全)( https://github.com/rubycon/isaac.js

window.crypto.getRandomValues已经在Chrome中实现了一段时间,而在Firefox中也是如此。 不幸的是,Internet Explorer 10之前并没有实现这个function。 IE 11有window.msCrypto,它完成相同的事情。 sjcl有一个很好的随机数生成器,从鼠标移动中播种,但总有一个机会,鼠标不会移动到足以播种发生器,或者用户在没有任何鼠标移动的移动设备上。 因此,我build议有一个回退的情况下,如果没有select,你仍然可以得到一个非安全的随机数。 以下是我如何处理这个问题:

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

您需要在该实现中包含sjcl.js和isaac.js,并且确保在加载页面后立即启动sjcl entropy收集器:

 sjcl.random.startCollectors(); 

sjcl是双重授权的BSD和GPL,而isaac.js是麻省理工学院,所以使用任何一个项目中的任何一个都是完全安全的。 正如在另一个答案中提到的,clipperz是另一种select,但无论出于什么奇怪的原因,它是根据AGPL许可的。 我还没有看到任何人似乎明白了对JavaScript库有什么影响,但我普遍避免它。

改进我发布的代码的一种方法可能是将isaac随机数生成器的状态存储在localStorage中,所以每次页面加载时都不会重新进行重新设置。 以撒会产生一个随机的序列,但是为了密码学的目的,种子是非常重要的。 用Math.random进行播种是不好的,但是如果它不一定在每一页上加载,至less会有一点坏。

使用window.crypto.getRandomValues ,如下所示:

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

这在所有现代浏览器中都受支持,并使用操作系统的随机生成器(例如/dev/urandom )。 如果您需要IE11兼容性,则必须通过var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..)使用其前缀实现 var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..) var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..)虽然。

请注意, window.crypto API也可以直接生成密钥 ,这可能是更好的select。

你可能想尝试http://sourceforge.net/projects/clipperzlib/它有一个Fortuna的实现,它是一个密码安全的随机数发生器。; (看看src / js / Clipperz / Crypto / PRNG.js)。 它似乎也使用鼠标作为随机的来源。

首先,你需要一个熵源。 例如,移动鼠标,密码或其他。 但是所有这些来源都是非常随机的,并且保证你有20比特的熵,很less。 您需要采取的下一步是使用像“基于密码的KDF”这样的机制,这将使计算难以区分数据和随机数据。