RNGCryptoServiceProvider – 随机数查看

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

在这个片段上寻找意见。

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); } 

资料来源: http : //www.vcskicks.com/code-snippet/rng-int.php

这比使用滴答计数种子更受欢迎,例如:

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

注意:

我不是在寻找第三方随机数据提供者,例如Random.org ,因为这种依赖对应用程序来说是不现实的。

好吧,使用RNGCryptoServiceProvider为您提供了一个不可思议的加密强度种子,而Environment.TickCount在理论上是可预测的。

在快速连续多次调用NextInt方法时,另一个重要区别是显而易见的。 使用RNGCryptoServiceProvider将每次使用不同的加密强度数对种子进行种子播种,这意味着它将继续为每次调用返回不同的随机数。 使用TickCount冒每次使用相同数字播种Random对象的风险(如果在相同的“tick”期间多次调用该方法),这意味着它将继续为每个调用返回相同的(假设随机的)数字。

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

2年前我问了一个类似的问题 :)检查,看看它是否对你有所帮助。 我使用该代码生成用于支付处理的安全随机数。

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

 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); } } 

我真的不建议使用提供的示例。 虽然RNGCryptoServiceProvider返回真正好的随机(或至少它应该),但对于Random来说同样如此。 更多 – 不知道Random(value)是否对Next(..)重新调整的值创建了真正的双射。 更多 – 不能保证Next(min,max)以真正随机的方式返回值(意味着数字命中每个值的机会相等)。

我会首先将问题推迟到0区间的数字 – 最大(不包括)。 然后我将使用最接近2的幂来获得0 – (2 ^ n – 1)范围内的随机值。 现在你必须做的一件事就是使用modulo来获得优先范围内的数字,比如rand(0 – (2 ^ n – 1))%max,因为这样做可以增加在较低范围内编号的机会。

示例 – max = 3,n = 2(0 – (2 ^ 2 – 1))%2,数字(0,1,2,3),模数(0,1,2,0)后的对应值。 看到我们两次击中0,这实际上是糟糕的随机。

所以解决方案是使用加密随机获取最接近2的幂,如果值超出最大范围,重复procudre(得到另一个加密随机),直到值在给定范围内。 这将是更好的algorythm。

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

 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 ///  /// Get the next random integer ///  /// Random [Int32] 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]; } ///  /// Get the next random integer to a maximum value ///  /// Maximum value /// Random [Int32] public static Int32 Next(Int32 MaxValue) { Int32 result = 0; do { result = Next(); } while (result > MaxValue); return result; } #endregion #region Random UInt32 ///  /// Get the next random unsigned integer ///  /// Random [UInt32] 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]; } ///  /// Get the next random unsigned integer to a maximum value ///  /// Maximum value /// Random [UInt32] public static UInt32 NextUInt(UInt32 MaxValue) { UInt32 result = 0; do { result = NextUInt(); } while (result > MaxValue); return result; } #endregion #region Random Int64 ///  /// Get the next random integer ///  /// Random [Int32] 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]; } ///  /// Get the next random unsigned long to a maximum value ///  /// Maximum value /// Random [UInt64] public static Int64 NextLong(Int64 MaxValue) { Int64 result = 0; do { result = NextLong(); } while (result > MaxValue); return result; } #endregion #region Random UInt32 ///  /// Get the next random unsigned long ///  /// Random [UInt64] 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]; } ///  /// Get the next random unsigned long to a maximum value ///  /// Maximum value /// Random [UInt64] public static UInt64 NextULong(UInt64 MaxValue) { UInt64 result = 0; do { result = NextULong(); } while (result > MaxValue); return result; } #endregion #region Random Bytes ///  /// Get random bytes ///  /// Random [byte array] public static byte[] NextBytes(long Size) { byte[] data = new byte[Size]; _Random.GetBytes(data); return data; } #endregion } 

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

Random类对于实际随机化非常有用,例如随机化图像旋转器中的顺序图像显示或模具的卷。
另一方面,如果您需要需要更高安全性的随机数,比如生成密码或支付确认密钥,那么使用RNGCryptoServiceProvider等类或创建自己实现的抽象类RandomNumberGenerator实现加密算法是更好的选择。

好的,所以我在聚会上有点晚了,但我真的想要一个完整的System.Random实现,可以在同一个计时器tic中多次调用并产生不同的结果。 经过对不同实现的痛苦之后,我决定使用我提出的最简单的一个,它提供了一个默认构造函数,它为基本的System.Random构造函数提供了一个随机密钥:

 ///  An implementation of System.Random whose default constructor uses a random seed value rather than the system time.  public class RandomEx : Random { ///  Initializes a new CryptoRandom instance using a random seed value.  public RandomEx() : base(_GetSeed()) { } ///  Initializes a new CryptoRandom instance using the specified seed value.  ///  The seed value.  public RandomEx(int seed) : base(seed) { } // The static (shared by all callers!) RandomNumberGenerator instance private static RandomNumberGenerator _rng = null; ///  Static method that returns a random integer.  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); } } 

在此过程中,我还编写并测试了一个实现,该实现覆盖了使用RNGCryptoServiceProvider提供所有随机值所必需的方法(而不是依赖于随机数生成器被捆绑到System.Random类中)。 但是,当你获取我的随机Sample()值并推动它们通过转换产生整数值时,我不知道结果是如何加密的。 无论如何,这是代码,如果有人想要它:

 ///  An implementation of System.Random that uses RNGCryptoServiceProvider to provide random values.  public class CryptoRandom : Random, IDisposable { // Class data RandomNumberGenerator _csp = new RNGCryptoServiceProvider(); ///  Returns a random number between 0.0 (inclusive) and 1.0 (exclusive).  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); } ///  Fills the elements of the specified array of bytes with random numbers.  ///  An array of bytes to contain random numbers.  public override void NextBytes(byte[] buffer) { _csp.GetBytes(buffer); } ///  Returns a nonnegative random integer.  ///  A 32-bit signed integer greater than or equal to zero.  public override int Next() { byte[] data = new byte[4]; _csp.GetBytes(data); data[3] &= 0x7f; return BitConverter.ToInt32(data, 0); } ///  Returns a random integer that is within a specified range.  ///  The inclusive lower bound of the random number returned.  ///  The exclusive upper bound of the random number returned. maxValue must be greater than or equal to minValue.  ///  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.  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 ///  Disposes the CryptoRandom instance and all of its allocated resources.  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 }