在javascript中保护随机数?

时间:2010-11-03 00:11:44

标签: javascript cryptography

如何在javascript中生成加密安全随机数?

8 个答案:

答案 0 :(得分:58)

WHATWG已经讨论过将其添加到window.crypto对象中。您可以阅读the discussion并查看proposed API和webkit错误(22049)。

刚刚测试了以下代码in Chrome以获取随机字节:

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

答案 1 :(得分:27)

按顺序,我认为你最好的赌注是:

  1. window.crypto.getRandomValues或window.msCrypto.getRandomValues
  2. sjcl库的randomWords函数(http://crypto.stanford.edu/sjcl/
  3. isaac库的随机数生成器(由Math.random播种,因此不具有加密安全性)(https://github.com/rubycon/isaac.js
  4. window.crypto.getRandomValues已经在Chrome中实现了一段时间,而且最近也在Firefox中实现。不幸的是,Internet Explorer 10和之前没有实现该功能。 IE 11有window.msCrypto,它完成同样的事情。 sjcl有一个很棒的随机数生成器,从鼠标移动中播种,但总是有可能鼠标不会移动到足以使发生器播种,或者用户在移动设备上没有任何鼠标移动。因此,我建议有一个后备情况,如果没有选择,你仍然可以得到一个非安全的随机数。以下是我处理这个问题的方法:

    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熵收集器:

    sjcl.random.startCollectors();
    

    sjcl是双重许可的BSD和GPL,而isaac.js是MIT,因此在任何项目中使用其中任何一个都是完全安全的。正如另一个答案所述,clipperz是另一种选择,但无论出于何种奇怪的原因,它都是根据AGPL许可的。我还没有看到任何人似乎理解对JavaScript库有什么影响,但我会普遍避免它。

    改进我发布的代码的一种方法可能是将isaac随机数生成器的状态存储在localStorage中,因此每次加载页面时都不会重新播种。 Isaac将生成一个随机序列,但是出于加密目的,种子是非常重要的。使用Math.random进行播种是不好的,但如果不是每次加载页面都不会少一点。

答案 2 :(得分:23)

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

编辑:我自己通过制作密码生成器来玩这个概念,我不能保证我的美白功能完美无缺,但不断重新开始我很确定这对于这项工作很有用:电子商务。 hopto.org/generator.htm

Edit2:它现在可以与智能手机配合使用,但只能在收集熵时禁用触控功能。 Android无法以任何其他方式正常运行。

答案 3 :(得分:11)

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

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

这是supported in all modern browsers并使用操作系统的随机生成器(例如/dev/urandom)。如果您需要IE11兼容性,则必须通过var crypto = window.crypto || window.msCrypto; crypto.getRandomValues(..)使用其前缀实现。

请注意,window.crypto API也可以generate keys outright,这可能是更好的选择。

答案 4 :(得分:4)

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

答案 5 :(得分:2)

要从范围[0, 1)(类似于Math.random())中获得加密的强数,请使用crypto

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;

console.log( random() );

答案 6 :(得分:1)

首先,您需要一个熵源。例如,移动鼠标,密码或任何其他。但是所有这些来源都非常随机,并保证你有20位熵,很少更多。您需要采取的下一步是使用&#34;基于密码的KDF&#34;它会使计算难以区分数据和随机数据。

答案 7 :(得分:0)

许多年前,您必须实现自己的随机数生成器,并将其植入通过鼠标移动和计时信息收集的熵中。这就是JavaScript密码学的Phlogiston时代。如今,我们有window.crypto可以合作。

如果您需要随机的整数random-number-csprng是一个不错的选择。它会安全地生成一系列随机字节,然后将其转换为无偏随机整数。

const randomInt = require("random-number-csprng");
(async function() {
    let random = randomInt(10, 30);
    console.log(`Your random number: ${random}`);
})();

如果您需要一个随机的浮点数,则需要做更多的工作。通常,安全随机性是一个整数问题,而不是浮点问题。