zoukankan      html  css  js  c++  java
  • 生成安全的随机数

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

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

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

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

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

    即是说:

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

    一、System.Random类

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

    Random random = new Random();
    for (int i = 0; i < 10; i++)
        Console.WriteLine(random.Next());

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

    使用Rondom类时最常见的错误,是将创建Random实例的语句放在一个路径很短的循环中。在问题与思考_随机数的产生中,作者是这么写的:

    for (int i = 0; i < 10; i++)
    {
        Random random_A 
    = new Random();
        
    sbyte randomNumber = (sbyte)(random_A.Next(0101));
        Console.WriteLine(randomNumber);
    }

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

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

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

    二、RNGCryptoServiceProvider类

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

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

    byte[] bytes = new byte[4];
    RNGCryptoServiceProvider r 
    = new RNGCryptoServiceProvider();

    for (int i = 0; i < 10; i++)
    {
        r.GetBytes(bytes);
        
    int number = BitConverter.ToInt32(bytes, 0);
        Console.WriteLine(number);
    }

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

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

    byte[] bytes = new byte[16];
    RNGCryptoServiceProvider r 
    = new RNGCryptoServiceProvider();

    for (int i = 0; i < 10; i++)
    {
        r.GetBytes(bytes);
        
    int number = (int)((decimal)bytes[0/ 256 * 100+ 1;
        Console.WriteLine(number);
    }

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

    byte[] bytes = new byte[4];

    for (int i = 0; i < 10; i++)
    {
        RNGCryptoServiceProvider r 
    = new RNGCryptoServiceProvider();
        r.GetBytes(bytes);
        
    int number = BitConverter.ToInt32(bytes, 0);
        Console.WriteLine(number);
    }

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

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

  • 相关阅读:
    Java+7入门经典 -1 简介
    优化算法动画演示Alec Radford's animations for optimization algorithms
    如何写科技论文How to write a technical paper
    开始学习深度学习和循环神经网络Some starting points for deep learning and RNNs
    用500行Julia代码开始深度学习之旅 Beginning deep learning with 500 lines of Julia
    用10张图来看机器学习Machine learning in 10 pictures
    ICLR 2013 International Conference on Learning Representations深度学习论文papers
    ICLR 2014 International Conference on Learning Representations深度学习论文papers
    卷积神经网络CNN(Convolutional Neural Networks)没有原理只有实现
    卷积神经网络Convolutional Neural Networks
  • 原文地址:https://www.cnblogs.com/Rainy/p/468670.html
Copyright © 2011-2022 走看看