首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么要用System.Security.Cryptography.RandomNumberGenerator?而不是C#类System.Random呢

为什么要用System.Security.Cryptography.RandomNumberGenerator?而不是C#类System.Random呢
EN

Stack Overflow用户
提问于 2009-08-10 21:25:54
回答 13查看 53.3K关注 0票数 89

为什么会有人使用System.Random的“标准”随机数生成器,而不是总是使用System.Security.Cryptography.RandomNumberGenerator的加密安全的随机数生成器(或者它的子类,因为RandomNumberGenerator是抽象的)?

Nate Lawson在13:11分钟的Google Tech Talk演示文稿"Crypto Strikes Back“中告诉我们,不要使用来自Python、Java和C#的”标准“随机数生成器,而要使用加密安全版本。

我知道两个版本的随机数生成器之间的区别(参见question 101337)。

但是,有什么理由不总是使用安全随机数生成器呢?为什么要使用System.Random呢?也许是性能吧?

EN

回答 13

Stack Overflow用户

回答已采纳

发布于 2009-08-10 21:29:48

速度和意图。如果您正在生成随机数,并且不需要安全性,为什么要使用速度较慢的加密函数呢?你不需要安全,所以为什么要让别人认为这个号码可能会被用于安全的东西,而它不是这样的呢?

票数 153
EN

Stack Overflow用户

发布于 2009-08-10 21:30:59

除了速度和更有用的接口(NextDouble()等)之外,还可以通过使用固定的种子值来生成可重复的随机序列。在测试过程中,这是非常有用的。

代码语言:javascript
运行
复制
Random gen1 = new Random();     // auto seeded by the clock
Random gen2 = new Random(0);    // Next(10) always yields 7,8,7,5,2,....
票数 66
EN

Stack Overflow用户

发布于 2011-07-27 17:36:31

首先,为了安全起见,您链接的演示文稿只讨论了随机数。所以它不会因为非安全目的而声称Random是不好的。

但我确实是这么说的。Random的.net 4实现在几个方面存在缺陷。我建议只有在你不关心随机数质量的情况下才使用它。我建议使用更好的第三方实现。

缺陷1:种子

默认构造函数使用当前时间作为种子。因此,在短时间内(大约10ms)使用默认构造函数创建的所有Random实例都返回相同的序列。这是文档化的并且是“按设计”的。如果您想对代码进行多线程处理,这尤其令人讨厌,因为您不能简单地在每个线程的执行开始时创建一个Random实例。

解决方法是在使用默认构造函数时格外小心,并在必要时手动设定种子。

这里的另一个问题是种子空间相当小(31位)。因此,如果您使用完全随机的种子生成50k个Random实例,您可能会得到一个随机数序列两次(由于birthday paradox)。因此,手动播种也不容易。

缺陷2: Next(int maxValue) 返回的随机数的分布是有偏差的

对于某些参数,Next(int maxValue)显然不是一致的。例如,如果你计算r.Next(1431655765) % 2,你将在大约2/3的样本中得到0。(答案末尾的示例代码。)

缺陷3:NextBytes() 方法效率低下。

NextBytes()的每字节成本大约与使用Next()生成完整整数样本的成本一样大。由此,我怀疑他们确实为每个字节创建了一个样本。

一个更好的实现使用每个样本中的3个字节可以将NextBytes()的速度提高到原来的3倍。

由于这个缺陷,在我的机器(Win7,核心i3 2600 my )上,Random.NextBytes()仅比System.Security.Cryptography.RNGCryptoServiceProvider.GetBytes快约25%。

我敢肯定,如果有人检查了源代码/反编译的字节代码,他们会发现比我的黑盒分析更多的缺陷。

代码示例

r.Next(0x55555555) % 2有很强的偏见:

代码语言:javascript
运行
复制
Random r = new Random();
const int mod = 2;
int[] hist = new int[mod];
for(int i = 0; i < 10000000; i++)
{
    int num = r.Next(0x55555555);
    int num2 = num % 2;
    hist[num2]++;
}
for(int i=0;i<mod;i++)
    Console.WriteLine(hist[i]);

性能:

代码语言:javascript
运行
复制
byte[] bytes=new byte[8*1024];
var cr=new System.Security.Cryptography.RNGCryptoServiceProvider();
Random r=new Random();

// Random.NextBytes
for(int i=0;i<100000;i++)
{
    r.NextBytes(bytes);
}

//One sample per byte
for(int i=0;i<100000;i++)
{   
    for(int j=0;j<bytes.Length;j++)
      bytes[j]=(byte)r.Next();
}

//One sample per 3 bytes
for(int i=0;i<100000;i++)
{
    for(int j=0;j+2<bytes.Length;j+=3)
    {
        int num=r.Next();
        bytes[j+2]=(byte)(num>>16);   
        bytes[j+1]=(byte)(num>>8);
        bytes[j]=(byte)num;
    }
    //Yes I know I'm not handling the last few bytes, but that won't have a noticeable impact on performance
}

//Crypto
for(int i=0;i<100000;i++)
{
    cr.GetBytes(bytes);
}
票数 56
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1257299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档