这是一种在Node JS中生成随机数的加密安全方法吗?

时间:2014-05-06 21:45:18

标签: node.js random cryptography

我尝试将Math.random()替换为我自己的Cryptography.random()。我的代码是否会生成加密安全的随机数,您是否看到了优化的机会?

NodeCrypto = require('crypto');

Cryptography = function() {
}

Cryptography.random = Promise.method(function() {
    return new Promise(function(resolve, reject) {
        NodeCrypto.randomBytes(4, function(ex, buffer) {
            var hex = buffer.toString('hex');
            var integer = parseInt(hex, 16);
            var random = Number('0.'+integer);

            resolve(random);
            return random;
        });
    });
});

2 个答案:

答案 0 :(得分:6)

那么你想要实现的是在适当的加密库安全生成的4个字节中生成0到1之间的随机浮点数?

您在问题中执行此操作的方式会产生偏差,因为您的integer均匀分布在集合{0,1,...,4294967295}中。例如范围的并集

{10000000000,…,19999999999},
{1000000000,…,1999999999}
{100000000,…,199999999}
{10000000,…,19999999}
{1000000,…,1999999} 
…
{10,…,19}
{1}

生成前导1作为第一个十进制数字大约是生成前导9的范围的十倍:

{9000000000,…,9999999999}
{900000000,…,999999999}
{90000000,…,99999999}
{9000000,…,9999999} 
…
{90,…,99}
{9}

integer的可能值中没有十一位数字,前导数为9。)

相反,您可以将integer除以其最大可能值0xffffffff。由于javascript使用8字节浮点值作为其数字类型,4字节值不会给你足够的范围。为了安全起见,您可以改为读取8个字节(由于用于存储指数的位,这比需要的多一点):

//…
NodeCrypto.randomBytes(8, function(ex, buffer) {
    var hex = buffer.toString('hex');
    var integer = parseInt(hex, 16);
    var random = integer / 0xffffffffffffffff;

    resolve(random);
    return random;
});
//…

以上在区间[0.0,1.0]中生成数字(0.0和1.0都包含在范围内)。 如果要排除1.0,可以将1加到除数:var random = integer / (0xffffffffffffffff+1); 编辑:由于数字在尾数中没有8字节精度,它将无论数学上是否小于1.0,都会四舍五入到1.0

This page推测在ECMA标准的未来版本中,数字将由16字节浮点表示。如果你想做好准备,你可以使用16而不是8字节的随机性并除以0xffffffffffffffffffffffffffffffff

我最后会说几句警告:对于加密应用程序,您通过此消息生成的随机数很可能是完全不安全的,因为您的随机性低于64位,远远少于熵。一般来说,oleksii的评论是正确的:不要发明甚至实现你自己的加密。

答案 1 :(得分:1)

不正确,integer的第一个数字肯定是有偏见的。这不是创建从0到1(不包括)的十进制值的好方法。