C# RNGCryptoServiceProvider-随机数审核

C# RNGCryptoServiceProvider-随机数审核,c#,.net,asp.net,security,random,C#,.net,Asp.net,Security,Random,在寻找生成真正随机数的最佳尝试时,我偶然发现了这个代码示例 正在寻找对此片段的意见 using System; using System.Security.Cryptography; private static int NextInt(int min, int max) { RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); byte[] buffer = new byte[4]; r

在寻找生成真正随机数的最佳尝试时,我偶然发现了这个代码示例

正在寻找对此片段的意见

using System;
using System.Security.Cryptography;

private static int NextInt(int min, int max)
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] buffer = new byte[4];
    
    rng.GetBytes(buffer);
    int result = BitConverter.ToInt32(buffer, 0);

    return new Random(result).Next(min, max);
}
资料来源:

这是否比使用蜱虫计数种子更可取,例如:

Random rand = new Random(Environment.TickCount); 
rand.Next(min, max);
注意:


我不是在寻找第三方随机数据提供程序,例如,这样的依赖关系对应用程序来说是不现实的。

好吧,使用
RNGCryptoServiceProvider
可以为您提供一个不可用的加密强度种子,而
环境。TickCount
在理论上是可预测的

当快速连续多次调用
NextInt
方法时,另一个关键的区别会很明显。使用
RNGCryptoServiceProvider
每次都会为
Random
对象播种不同的加密强度编号,这意味着它会继续为每个调用返回不同的随机编号。使用
TickCount
可能会使
Random
对象每次都具有相同的编号(如果在同一个“tick”期间多次调用该方法),这意味着它将继续为每次调用返回相同的(假定为随机的)编号


如果你真的需要真正的随机数,那么你根本不应该使用计算机生成它们:你应该测量放射性衰变或类似的,真正不可预测的东西。

这实际上取决于生成的随机数的预期用途或要求

该类对于实际随机化非常有用,例如随机化图像旋转器或模具辊中显示的顺序图像。

另一方面,如果您需要要求更高安全性的随机数字,如生成密码或支付确认密钥,然后,使用一个类,例如或创建自己的实现加密算法的抽象类的实现,是更好的选择。

我真的不建议使用提供的示例。虽然
RNGCryptoServiceProvider
返回真正好的random(或者至少应该返回),但是
random
的情况并非如此。此外,还不知道
Random(value)
是否对
Next(…)
返回的值创建了真正的双射。此外,不能保证
Next(min,max)
以真正随机的方式返回值(即数字命中每个值的机会相等)

我首先要解决的问题是获得一个介于0-max(独占)之间的数字。然后,我将使用最接近的2次方来获得0-(2^n-1)范围内的随机值。现在,有一件事你绝对不能在这里使用模来获得一个在首选范围内的数字,比如
rand(0-(2^n-1))%max
,因为这样做,你实际上增加了在较低范围内获得数字的机会

示例:
max=3,n=2(0-(2^2-1))%2
,数字(0,1,2,3),模(0,1,2,0)后的对应值。看,我们打了两次0,这是非常糟糕的随机性


因此,解决方案是使用crypto random获得一个值,取二的最近幂,如果该值超出最大范围,则重复该过程(获取另一个crypto random),直到该值在给定范围内。这将是一个更好的算法。

不要使用您的代码。您的解决方案是错误的,生成的随机数很差。我建议我的解决方案,它生成加密强随机数:

public class SecureRandom : RandomNumberGenerator
{
    private readonly RandomNumberGenerator rng = new RNGCryptoServiceProvider();


    public int Next()
    {
        var data = new byte[sizeof(int)];
        rng.GetBytes(data);
        return BitConverter.ToInt32(data, 0) & (int.MaxValue - 1);
    }

    public int Next(int maxValue)
    {
        return Next(0, maxValue);
    }

    public int Next(int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new ArgumentOutOfRangeException();
        }
        return (int)Math.Floor((minValue + ((double)maxValue - minValue) * NextDouble()));
    }

    public double NextDouble()
    {
        var data = new byte[sizeof(uint)];
        rng.GetBytes(data);
        var randUint = BitConverter.ToUInt32(data, 0);
        return randUint / (uint.MaxValue + 1.0);
    }

    public override void GetBytes(byte[] data)
    {
        rng.GetBytes(data);
    }

    public override void GetNonZeroBytes(byte[] data)
    {
        rng.GetNonZeroBytes(data);
    }
}

我认为这是一种比上面列出的发电机更高效、可能更快的发电机

public static class SecureRandom
{
    #region Constants
    private const int INT_SIZE = 4;
    private const int INT64_SIZE = 8;
    #endregion

    #region Fields
    private static RandomNumberGenerator _Random;
    #endregion

    #region Constructor
    static SecureRandom()
    {
        _Random = new RNGCryptoServiceProvider();
    }
    #endregion

    #region Random Int32
    /// <summary>
    /// Get the next random integer
    /// </summary>
    /// <returns>Random [Int32]</returns>
    public static Int32 Next()
    {
        byte[] data = new byte[INT_SIZE];
        Int32[] result = new Int32[1];

        _Random.GetBytes(data);
        Buffer.BlockCopy(data, 0, result, 0, INT_SIZE);

        return result[0];
    }

    /// <summary>
    /// Get the next random integer to a maximum value
    /// </summary>
    /// <param name="MaxValue">Maximum value</param>
    /// <returns>Random [Int32]</returns>
    public static Int32 Next(Int32 MaxValue)
    {
        Int32 result = 0;

        do
        {
            result = Next();
        } while (result > MaxValue);

        return result;
    }
    #endregion

    #region Random UInt32
    /// <summary>
    /// Get the next random unsigned integer
    /// </summary>
    /// <returns>Random [UInt32]</returns>
    public static UInt32 NextUInt()
    {
        byte[] data = new byte[INT_SIZE];
        Int32[] result = new Int32[1];

        do
        {
            _Random.GetBytes(data);
            Buffer.BlockCopy(data, 0, result, 0, INT_SIZE);
        } while (result[0] < 0);

        return (UInt32)result[0];
    }

    /// <summary>
    /// Get the next random unsigned integer to a maximum value
    /// </summary>
    /// <param name="MaxValue">Maximum value</param>
    /// <returns>Random [UInt32]</returns>
    public static UInt32 NextUInt(UInt32 MaxValue)
    {
        UInt32 result = 0;

        do
        {
            result = NextUInt();
        } while (result > MaxValue);

        return result;
    }
    #endregion

    #region Random Int64
    /// <summary>
    /// Get the next random integer
    /// </summary>
    /// <returns>Random [Int32]</returns>
    public static Int64 NextLong()
    {
        byte[] data = new byte[INT64_SIZE];
        Int64[] result = new Int64[1];

        _Random.GetBytes(data);
        Buffer.BlockCopy(data, 0, result, 0, INT64_SIZE);

        return result[0];
    }

    /// <summary>
    /// Get the next random unsigned long to a maximum value
    /// </summary>
    /// <param name="MaxValue">Maximum value</param>
    /// <returns>Random [UInt64]</returns>
    public static Int64 NextLong(Int64 MaxValue)
    {
        Int64 result = 0;

        do
        {
            result = NextLong();
        } while (result > MaxValue);

        return result;
    }
    #endregion

    #region Random UInt32
    /// <summary>
    /// Get the next random unsigned long
    /// </summary>
    /// <returns>Random [UInt64]</returns>
    public static UInt64 NextULong()
    {
        byte[] data = new byte[INT64_SIZE];
        Int64[] result = new Int64[1];

        do
        {
            _Random.GetBytes(data);
            Buffer.BlockCopy(data, 0, result, 0, INT64_SIZE);
        } while (result[0] < 0);

        return (UInt64)result[0];
    }

    /// <summary>
    /// Get the next random unsigned long to a maximum value
    /// </summary>
    /// <param name="MaxValue">Maximum value</param>
    /// <returns>Random [UInt64]</returns>
    public static UInt64 NextULong(UInt64 MaxValue)
    {
        UInt64 result = 0;

        do
        {
            result = NextULong();
        } while (result > MaxValue);

        return result;
    }
    #endregion

    #region Random Bytes
    /// <summary>
    /// Get random bytes
    /// </summary>
    /// <param name="data">Random [byte array]</param>
    public static byte[] NextBytes(long Size)
    {
        byte[] data = new byte[Size];
        _Random.GetBytes(data);
        return data;
    }
    #endregion
}
公共静态类SecureRandom
{
#区域常数
私有常量int_SIZE=4;
私有常量INT64_SIZE=8;
#端区
#区域字段
专用静态随机数生成器_Random;
#端区
#区域构造函数
静态SecureRandom()
{
_Random=新的RNGCryptoServiceProvider();
}
#端区
#区域随机Int32
/// 
///获取下一个随机整数
/// 
///随机[Int32]
公共静态Int32 Next()
{
字节[]数据=新字节[INT_SIZE];
Int32[]结果=新的Int32[1];
_Random.GetBytes(数据);
块复制(数据,0,结果,0,整数大小);
返回结果[0];
}
/// 
///将下一个随机整数设置为最大值
/// 
///最大值
///随机[Int32]
公共静态Int32 Next(Int32最大值)
{
Int32结果=0;
做
{
结果=下一步();
}而(结果>最大值);
返回结果;
}
#端区
#区域随机UInt32
/// 
///获取下一个随机无符号整数
/// 
///随机[UInt32]
公共静态UInt32 NextUInt()
{
字节[]数据=新字节[INT_SIZE];
Int32[]结果=新的Int32[1];
做
{
_Random.GetBytes(数据);
块复制(数据,0,结果,0,整数大小);
}而(结果[0]<0);
返回(UInt32)结果[0];
}
/// 
///获取下一个随机无符号整数的最大值
/// 
///最大值
///随机[UInt32]
公共静态UInt32 NextUInt(UInt32最大值)
{
UInt32结果=0;
做
{
结果=NextUInt();
}而(结果>最大值);
返回结果;
}
#端区
#区域随机Int64
/// 
///获取下一个随机整数
/// 
///随机[Int32]
公共静态Int64 NextLong()
{
字节[]数据=新字节[INT64_大小];
Int64[]结果=新的Int64[1];
_Random.GetBytes(数据);
块复制(数据,0,结果,0,INT64_大小);
返回结果[0];
}
/// 
///将下一个随机无符号long设置为最大值
/// 
///最大值
///随机[UInt64]
公共静态Int64 NextLong(Int64最大值)
{
Int64结果=0;
做
{
结果=
/// <summary> An implementation of System.Random whose default constructor uses a random seed value rather than the system time. </summary>
public class RandomEx : Random
{
    /// <summary> Initializes a new CryptoRandom instance using a random seed value. </summary>
    public RandomEx()
        : base(_GetSeed())
    { }

    /// <summary> Initializes a new CryptoRandom instance using the specified seed value. </summary>
    /// <param name="seed"> The seed value. </param>
    public RandomEx(int seed)
        : base(seed)
    { }

    // The static (shared by all callers!) RandomNumberGenerator instance
    private static RandomNumberGenerator _rng = null;

    /// <summary> Static method that returns a random integer. </summary>
    private static int _GetSeed()
    {
        var seed = new byte[sizeof(int)];

        lock (typeof(RandomEx)) {
            // Initialize the RandomNumberGenerator instance if necessary
            if (_rng == null) _rng = new RNGCryptoServiceProvider();

            // Get the random bytes
            _rng.GetBytes(seed);
        }

        // Convert the bytes to an int
        return BitConverter.ToInt32(seed, 0);
    }
}
/// <summary> An implementation of System.Random that uses RNGCryptoServiceProvider to provide random values. </summary>
public class CryptoRandom : Random, IDisposable
{
    // Class data
    RandomNumberGenerator _csp = new RNGCryptoServiceProvider();

    /// <summary> Returns a random number between 0.0 (inclusive) and 1.0 (exclusive). </summary>
    protected override double Sample()
    {
        // Get a nonnegative random Int64
        byte[] bytes = new byte[sizeof(long)];
        _csp.GetBytes(bytes);
        long value = BitConverter.ToInt64(bytes, 0) & long.MaxValue;

        // Scale it to 0->1
        return (double)value / (((double)Int64.MaxValue) + 1025.0d);
    }

    /// <summary> Fills the elements of the specified array of bytes with random numbers. </summary>
    /// <param name="buffer"> An array of bytes to contain random numbers. </param>
    public override void NextBytes(byte[] buffer)
    {
        _csp.GetBytes(buffer);
    }

    /// <summary> Returns a nonnegative random integer. </summary>
    /// <returns> A 32-bit signed integer greater than or equal to zero. </returns>
    public override int Next()
    {
        byte[] data = new byte[4];
        _csp.GetBytes(data);
        data[3] &= 0x7f;
        return BitConverter.ToInt32(data, 0);
    }

    /// <summary> Returns a random integer that is within a specified range. </summary>
    /// <param name="minValue"> The inclusive lower bound of the random number returned. </param>
    /// <param name="maxValue"> The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue. </param>
    /// <returns> A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned. </returns>
    public override int Next(int minValue, int maxValue)
    {
        // Special case
        if (minValue == maxValue) return minValue;

        double sample = Sample();
        double range = (double)maxValue - (double)minValue;
        return (int)((sample * (double)range) + (double)minValue);
    }

    #region IDisposible implementation

    /// <summary> Disposes the CryptoRandom instance and all of its allocated resources. </summary>
    public void Dispose()
    {
        // Do the actual work
        Dispose(true);

        // This object will be cleaned up by the Dispose method. Call GC.SupressFinalize to 
        // take this object off the finalization queue and prevent finalization code for this object 
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    // Dispose(bool disposing) executes in two distinct scenarios:
    //
    // If disposing is true, the method has been called directly or indirectly by a user's code and both
    // managed and unmanaged resources can be disposed. 
    //
    // If disposing is false, the method has been called by the runtime from inside the finalizer.
    // In this case, only unmanaged resources can be disposed. 
    protected virtual void Dispose(bool disposing)
    {
        if (disposing) {
            // The method has been called directly or indirectly by a user's code; dispose managed resources (if any)
            if (_csp != null) {
                _csp.Dispose();
                _csp = null;
            }

            // Dispose unmanaged resources (if any)
        }
    }

    #endregion
}
public double Random()
{
    using var csp = new RNGCryptoServiceProvider();

    byte[] b = new byte[8];
    csp.GetBytes(b);
    var lng = BitConverter.ToInt64(b, 0);
    var dbl = (double)(lng < 0 ? ~lng : lng);

    // Convert to a random number between 0 and 1
    return dbl / long.MaxValue;
}
public long RandomInt64(long min = 0, long max = long.MaxValue)
{
    // Check arguments
    if (min >= max)
    {
        throw new ArgumentOutOfRangeException(nameof(min), min, "Minimium value must be less than the maximum value.");
    }

    if (min < 0)
    {
        throw new ArgumentException("Minimum value must be at least 0.", nameof(min));
    }

    // Get the range between the specified minimum and maximum values
    var range = max - min;

    // Now add a random amount of the range to the minimum value - it will never exceed maximum value
    var add = Math.Round(range * Random());
    return (long)(min + add);
}