使用node.js生成10的幂模数的密码随机数

时间:2013-08-16 21:56:24

标签: javascript node.js random cryptography

使用加密库我可以要求库给我一些随机字节。问题是这个字节是每个(包括)0到255的数字,因此创建均匀分布的结果并不是那么简单。

我的意思如下:

该函数接收一个数字N,即10,100,... 10 ^ b,其中b是1到8之间的数字(可能更大,但我不需要更大的数字)并返回一个数字在0和给定数字之间(不包括给定数字),所以如果N为100,则函数的结果为0到99,如果N为10,则结果为0到9.

您可以使用Math.random创建一个随机数,然后乘以N然后使用floor。但是,Math.random不是加密安全的,因此必须使用随机生成的2 ^ 8m的数字来完成,其中m只是给crypto.randomBytes的任意数量的字节。

我创建了一个简单的功能,显然是有效的。但是,我知道将一些偏差引入随机数是相当容易的,我只想对其进行验证,因为它对项目来说有点重要。

genera_aleatorio_residuo_potencia10 : function (n, cb) {
  var digitos = Math.log(n) / Math.LN10;
  var extra_base2 = digitos > 8 ? digitos - 8 : 0;
  if (Math.floor(digitos + .4) - digitos > 0.00000001) {
    return cb("Numero no es potencia de 10 (10, 100, 1000...)", null);
  }
  digitos = Math.round(digitos);
  async.parallel({
    r1 : crypto_helper.generador_random_bytes(1),
    r2 : crypto_helper.generador_random_bytes(1)
  }, function (err, res) {
    if (err) {
      return cb(err, null);
    }
    var r1 = res.r1[0] + 1;
    var r2 = res.r2[0] + 1;
    var aleatorio = (Math.pow(5, digitos) - 1) * Math.pow(2, extra_base2) * r1 + r2;
    cb(null, aleatorio % n);
  });
}

毋庸置疑:crypto_helper.generador_random_bytes是node.js'crypto.randomBytes的包装器,我经常使用它来使异步库更友好。

我使用Math.pow(5,digitos)和Math.pow(2,extra_base2)的原因是N和256之间的最小公倍数。实际上,n永远不会大于100000000,所以数学.pow(2,extra_base2)不应该在我们的产品中使用,但我仍然希望确保它对其他人有意义。

2 个答案:

答案 0 :(得分:1)

我通过简单地模仿Java的SecureRandom.nextInt(int)在这里做了什么来找到一个很好的解决方案:SecureRandom.nextInt(int)一旦我可以编写代码就会发布代码(我现在很忙) 。我计划使用我从中开发的代码,因为我确认所提议的解决方案存在偏差(根本不可接受)。

以下是JDK代码的改编。注意31位数的限制,因为我意识到JS在32位的二进制补码上完成所有的按位运算。 因为我不会使用它,所以我没有实现2个数字的特殊情况。解决方案是一般的数字而不仅仅是10的权力......我确信必须有一个更好的解决方案,对于基数为10的数字,但无论如何。我重写了代码,不使用我的库并用英语制作,以便其他人可以更容易地使用它。

var crypto_random_number_range = function (n, cb) {
  //result is a number from 0 a n-1
  //Javascript works with 32 bits for bitwise operations but these are signed (2-complement), so it is good to limit the size of n
  if (n <= 0 || n > 2147483647) {
    return cb("n must be larger than 0 and smaller than 2147483647", null);
  }
  var bits, val;
  async.doWhilst(
    function (cb2) {
      crypto.randomBytes(4, function (err, rbytes) {
        if (err) {
          return cb2(err);
        }
        bits = ((rbytes[3] & 0x7f) << 24) + 
          (rbytes[2] << 16) + (rbytes[1] << 8) + rbytes[0];
        val = bits % n;
        cb2();
      });
    }, function () {
      return (bits - val + (n-1)) < 0;
    }, function (err) {
      if (err) {
        return cb(err, null);
      }
      return cb(null, val);
    }
  );
}

做了几次测试,似乎工作得很好。

答案 1 :(得分:-3)

var kazutsukuru = function kazutsukuru(kaketeiruno, kotae) {
  crypto.randomBytes(4, function(mondai, baito) {
    if (mondai) {
      return kotae(mondai);
    }

    kotae(null, Math.floor(baito.readUInt32BE(0) / 4294967296 * kaketeiruno));
  });
};

这应该做你想要的。我决定难以阅读我的答案,因为你的问题很难阅读。