【问题标题】:SecureRandom in JavaScript?JavaScript 中的 SecureRandom?
【发布时间】:2011-08-21 10:55:46
【问题描述】:

JavaScript 中是否有类似SecureRandom.hex()(ruby)的函数可以为我生成随机哈希?

【问题讨论】:

标签: javascript ruby random hash


【解决方案1】:

JS 中没有这样的辅助函数。您可以使用以下方法生成相当随机的哈希:

function hex(n){
 n = n || 16;
 var result = '';
 while (n--){
  result += Math.floor(Math.random()*16).toString(16).toUpperCase();
 }
 return result;
}

你可以修改它来形成一个guid:

function generateGuid(){
 var result = '', n=0;
 while (n<32){
  result += (~[8,12,16,20].indexOf(n++) ? '-': '') +    
            Math.floor(Math.random()*16).toString(16).toUpperCase();
 }
 return result;
}

【讨论】:

    【解决方案2】:

    我被引导到这个问题作为使用以下关键字的顶级搜索引擎结果:

    • 安全随机范围 js
    • securerandom js

    因此,我认为用今天(2019 年)可用的有效答案更新这篇文章会很好:

    下面的 sn-p 使用 Crypto.getRandomValues() 来获取据说是的随机值,

    ...密码学强...使用伪随机数生成器播种具有足够熵的值...适合加密使用。

    因此,我们有:

    var N = 32;
    var rng = window.crypto || window.msCrypto;
    var rawBytes = Array
                  .from(rng.getRandomValues(new Uint8Array(N)))
                  .map(c => String.fromCharCode(c))
                  .join([]);
    

    现在,下面是一个有趣的小十六进制编码器,我使用一些 Array 函数进行循环:

    function hexEncode(s) {
      return s.split('').map(c => (c < String.fromCharCode(16) ? '0' : '') + c.charCodeAt(0).toString(16)).join([]);
    }
    

    最后,如果你想结合上面的两个来生成随机哈希,你可以换出并相应地调整.map()函数并像这样打包它:

    function secureRandomHash(N) {
      N = N || 32; // Coalesce if size parameter N is left undefined
    
      // TODO: Consider refactoring with lazy-loaded function
      // to set preferred RNG provider, else throw an error here
      // to generate noise that no secure RNG is available for
      // this application.
      var rng = window.crypto || window.msCrypto;
    
      return Array
               .from(rng.getRandomValues(new Uint8Array(N)))
               .map(c => (c < 16 ? '0' : '') + c.toString(16)).join([]);
    }
    

    编码愉快!

    编辑:结果我最终在我自己的项目中需要这个,它也实现了前面示例中建议的 TODO(延迟加载)所以我们开始吧:

    Math.secureRandom = function() {
      var rng = window.crypto || window.msCrypto;
      if (rng === undefined)
        throw 'No suitable RNG found';
    
      // Lazy-load this if- branch
      Math.secureRandom = function() {
        // More secure implementation of Math.random (https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#Examples)
        return rng.getRandomValues(new Uint32Array(1))[0] / 4294967296;
      };
    
      return Math.secureRandom();
    }
    

    或者如果你真的很喜欢冒险......

    // Auto-upgrade Math.random with a more secure implementation only if crypto is available
    (function() {
      var rng = window.crypto || window.msCrypto;
      if (rng === undefined)
        return;
    
      // Source: https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#Examples
      Math.random = function() {
        return rng.getRandomValues(new Uint32Array(1))[0] / 4294967296;
      };
    })();
    
    console.log(Math.random());
    

    扩展Math 或覆盖Math.random() 是否适合您的应用程序或目标受众,这纯粹是实施者的学术练习。请务必先咨询您的建筑师!当然在这里获得 MIT 许可 :)

    【讨论】:

    • 如果随机值介于 0x0 - 0xF 之间,则转换为十六进制会跳过前导零。要将前导零添加到这 8 个但值,您可以使用 .map(c =&gt; (c &lt; 16 ? '0':'') + c.toString(16)).join('')
    • @some 是的,你完全正确。我本来打算回到那个,但因为追逐别的东西而分心。将很快更新我的答案。谢谢!
    • Answer 已更新,以及 hexEncode 助手中的等效内容。
    • 顺便说一下,Math.random() 返回一个 0-1 范围内的数字(包括 0,但不包括 1),但 crypto.getRandomValues(new Uint32Array(1))[0] / 4294967295 将返回一个 0-1 范围内的值(包括0 和 1)。将值更改为 4294967296 (2^32) 以排除 1。
    • 我创建了一个issue 来更新 mozilla.org 文档中的示例。
    猜你喜欢
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2017-02-08
    • 2012-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    相关资源
    最近更新 更多