在许多类型软件的开发过程中,都要使用随机数。例如纸牌的分发、密钥的生成等等。随机数至少应该具备两个条件:

1. 数字序列在统计上是随机的。
2. 不能通过已知序列来推算后面未知的序列。

只有实际物理过程才是真正随机的。而一般来说,计算机是很确定的,它很难得到真正的随机数。所以计算机利用设计好的一套算法,再由用户提供一个种子值,得出被称为“伪随机数”的数字序列,这就是我们平时所使用的随机数。

这种伪随机数字足以满足一般的应用,但它不适用于加密等领域,因为它具有弱点:

1. 伪随机数是周期性的,当它们足够多时,会重复数字序列。
2. 如果提供相同的算法和相同的种子值,将会得出完全一样的随机数序列。
3. 可以使用逆向工程,猜测算法与种子值,以便推算后面所有的随机数列。

即是说:

随机序列 = F(算法, 种子)

 

一、System.Random类

System.Random类是最常用的伪随机数生成器,我们经常使用它创建近似随机的数列。以下代码演示了Random类创建10个随机数:




随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

Random random 

=   new  Random();

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual


for  ( int  i  =   0 ; i  <   10 ; i ++ )

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

    Console.WriteLine(random.Next());

在创建Rondom类的实例时,我们可以指定Int32类型的种子值,不指定默认用Environment.TickCount作种子,它是从系统启动到现在经过的毫秒数。然后使用Next()方法来获得Int32类型的随机数值。Next()方法有3个重载,可以实现获得指定范围内的随机数值。

使用Rondom类时最常见的错误,是将创建Random实例的语句放在一个路径很短的循环中。如:


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

for  (

int  i  =   0 ; i  <   10 ; i ++ )

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_随机数_05

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_06


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_07

{

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    Random random_A = new Random();

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    sbyte randomNumber = (sbyte)(random_A.Next(0, 101));

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    Console.WriteLine(randomNumber);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_11

}

根据现在的计算机运行速度,执行这段代码根本用不了多少时间。所以在10次循环中,构造函数使用的Environment.TickCount几乎一样。随机数不随机的结果。

每次都是随机产生的.我又按F9,F10进行调试检查,让程序一步一步的运行,让随机数一个一个的产生,这时我就发现每次产生的随机数几乎都不一样

这个错误也验证了伪随机数的弱点。我们都用Random类,算法是一样的,所以一旦得知了程序使用的种子,那么程序过程就变得十分确定了。

 

二、RNGCryptoServiceProvider类

为了获得更加随机的数字序列,可以使用System.Security.Cryptography.RNGCryptoServiceProvider类。它使用加密服务提供程序 (CSP) 提供的实现来实现加密随机数生成器。

下面代码演示了RNGCryptoServiceProvider类创建10个随机数


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

byte [] bytes  =

  new   byte [ 4 ];

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

RNGCryptoServiceProvider r  =  

new  RNGCryptoServiceProvider();

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

for  (

int  i  =   0 ; i  <   10 ; i ++ )

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_随机数_05

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_06


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_07

{

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    r.GetBytes(bytes);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    int number = BitConverter.ToInt32(bytes, 0);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    Console.WriteLine(number);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_11

}

RNGCryptoServiceProvider类产生的随机数更加随机。即使有人知道了这个类,并得到最近生成的随机序列,也无法计算后续序列。

目前RNGCryptoServiceProvider类并没有提供获取指定范围的随机数的方法,需要自己处理。下面代码演示了创建从1到100的10个随机数:


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

byte [] bytes  =  

new   byte [ 16 ];

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

RNGCryptoServiceProvider r  =   new

 RNGCryptoServiceProvider();

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

for  ( int

 i  =   0 ; i  <   10 ; i ++ )

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_随机数_05

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_06


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_07

{

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    r.GetBytes(bytes);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    int number = (int)((decimal)bytes[0] / 256 * 100) + 1;

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    Console.WriteLine(number);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_11

}

最后测试了一下,将RNGCryptoServiceProvider类对象的创建放在循环中,仍然能获得随机数:


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

byte [] bytes  =   new

  byte [ 4 ];

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual

for  ( int  i 

=   0 ; i  <   10 ; i ++ )

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_随机数_05

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_06


随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_07

{

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    RNGCryptoServiceProvider r = new RNGCryptoServiceProvider();

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    r.GetBytes(bytes);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    int number = BitConverter.ToInt32(bytes, 0);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_ide_08

    Console.WriteLine(number);

随机生成一个256位的数据作为AES对称密钥 生成随机数的安全方法_Visual_11

}

当然,不推荐这么去写,毕竟对象的创建也是很费时间的。

最后说明一点,RNGCryptoServiceProvider类要比Random类耗费更多的时间,若打算在很短时间内生成大量随机数,请不要使用RNGCryptoServiceProvider类。

[视频]Visual Studio 2005入门之对象概述

[视频]Visual Studio 2005入门之创建对象和使用方法以及属性

[视频]Visual Studio 2005入门之利用构造函数初始化对象

[视频]Visual Studio 2005入门之重载方法以及运算符重载

[视频]Visual Studio 2005入门之.Net核心对象(Request)

...