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)
你在问题中这样做会产生偏差,因为你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加到除数中: 编辑:由于数字在尾数中没有8字节精度,因此var random = integer / (0xffffffffffffffff+1);1.0无论1.0数学上是否小于数学,它都会四舍五入.
该页面推测,在ECMA标准的未来版本中,数字将由16字节浮点表示.如果你想为此做准备,你可以使用16而不是8字节的随机性并除以0xffffffffffffffffffffffffffffffff
我将用几句警告结束:对于加密应用程序,您通过此消息生成的随机数可能是完全不安全的,因为远远少于64位的随机性.通常oleksii的评论是正确的:不要发明甚至实现自己的加密.