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

Kir*_*met 1 random cryptography node.js

这是我尝试用我自己的Cryptography.random()替换Math.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;
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

Per*_*ids 6

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

你在问题中这样做会产生偏差,因为你integer在{0,1,...,4294967295}集合中均匀分布.例如范围的并集

{10000000000,…,19999999999},
{1000000000,…,1999999999}
{100000000,…,199999999}
{10000000,…,19999999}
{1000000,…,1999999} 
…
{10,…,19}
{1}
Run Code Online (Sandbox Code Playgroud)

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

{9000000000,…,9999999999}
{900000000,…,999999999}
{90000000,…,99999999}
{9000000,…,9999999} 
…
{90,…,99}
{9}
Run Code Online (Sandbox Code Playgroud)

(其中可能的值中没有十一位数字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;
});
//…
Run Code Online (Sandbox Code Playgroud)

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

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

我将用几句警告结束:对于加密应用程序,您通过此消息生成的随机数可能是完全不安全的,因为远远少于64位的随机性.通常oleksii的评论是正确的:不要发明甚至实现自己的加密.