代码之家  ›  专栏  ›  技术社区  ›  Kyle

在javascript中保护随机数?

  •  76
  • Kyle  · 技术社区  · 14 年前

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

    7 回复  |  直到 6 年前
        1
  •  23
  •   e-sushi amandanovaes    9 年前

    例如,您可以使用鼠标移动作为随机数的种子,在鼠标移动事件发生时读取时间和鼠标位置,将数据输入到美白函数,您将拥有一些一流的随机数。不过,在使用数据之前一定要确保用户已经充分移动了鼠标。

    编辑:我通过制作一个密码生成器来对这个概念进行了一些尝试,我不能保证我的美白功能是完美的,但是不断地重新设置,我很确定这对工作来说是足够的:ebusiness.hopto.org/generator.htm

    edit2:它现在有点适用于智能手机,但只通过在收集熵时禁用触摸功能。Android无法以任何其他方式正常工作。

        2
  •  58
  •   Pacerier    10 年前

    在whatwg讨论过如何将此添加到window.crypto对象。你可以阅读 the discussion 然后看看 proposed API 和WebKit Bug(22049)。

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

    (function(){
      var buf = new Uint8Array(1);
      window.crypto.getRandomValues(buf);
      alert(buf[0]);
    })();
        3
  •  27
  •   ZeroG    11 年前

    我认为你最好的选择是:

    1. window.crypto.getrandomvalues或window.mscrypto.getrandomvalues
    2. sjcl库的随机词函数( http://crypto.stanford.edu/sjcl/ )
    3. Isaac库的随机数生成器(由math.random种子,所以不是真正的加密安全的)( https://github.com/rubycon/isaac.js )

    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中,这样就不会在每次加载页面时都重新种子化。艾萨克将生成一个随机序列,但出于密码学的目的,种子是最重要的。使用math.random进行种子植入是不好的,但如果不一定要在每次页面加载时都进行种子植入,则至少会有一点不坏。

        4
  •  11
  •   phihag    8 年前

    使用 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 这可能是更好的选择。

        5
  •  4
  •   ameer    14 年前

    你可能想试试 http://sourceforge.net/projects/clipperzlib/ 它实现了 Fortuna 它是一个密码安全的随机数生成器。(看看src/js/clipperz/crypto/prng.js)。它似乎也使用鼠标作为随机性的来源。

        6
  •  1
  •   user2674414    10 年前

    首先,你需要一个熵源。例如,移动鼠标、密码或任何其他。但是所有这些源都远离随机的,并且保证你有20位的熵,很少更多。您需要采取的下一步是使用类似“基于密码的kdf”这样的机制,这将使得在计算上难以区分数据和随机数据。

        7
  •  1
  •   Kamil Kiełczewski    6 年前

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

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