[C#]RNGCryptoServiceProvider亂數產生器
Assemble
mscorlib (在 mscorlib.dll 中)
Namespace
System.Security.Cryptography
RNGCryptoServiceProvider
RNGCryptoServiceProvider類別是Thread Safe型別,是使用由密碼編譯服務供應者 (CSP) 提供的實作 (implementation),實作密碼編譯亂數產生器 (RNG)。它能產生較Random類別這種「有限性數學演算法」還亂的亂數。
在RNGCryptoServiceProvider的成員中,其主要方法有兩個 :
|
名稱 |
說明 |
|
覆寫。 在位元組陣列中填入在密碼編譯方面強式的隨機值序列。 |
|
|
覆寫。 在位元組陣列中填入在密碼編譯方面強式的隨機非零值序列。 |
兩者的用法都是傳入一個Byte陣列,用法大同小異。主要只是差在GetNonZeroBytes所產的隨機值是不為零的而已。
使用步驟主要如下:
- 建立RNGCryptoServiceProvider物件實體
- 建立欲存放亂數的Byte陣列
- 呼叫GetBytes或GetNonZeroBytes並帶入Byte陣列
簡單的操作範例如下:
static void Main(string[] args)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] random = new Byte[100];
rng.GetBytes (random);
foreach (byte b in random)
Console.Write(b.ToString() + " ");
Console.WriteLine();
}
接著測試一下RNGCryptoServiceProvider是否會有跟Random類別一樣,當在極短時間內使用,會因亂數種子一樣而產生相同亂數組的問題。
static void Main(string[] args)
{
RNGCryptoServiceProvider rng1 = new RNGCryptoServiceProvider();
RNGCryptoServiceProvider rng2 = new RNGCryptoServiceProvider();
PrintRandomNumber(rng1);
Console.WriteLine(new string('=',70));
PrintRandomNumber(rng2);
}
static void PrintRandomNumber(RNGCryptoServiceProvider rng)
{
byte[] random = new Byte[100];
rng.GetBytes(random);
foreach (byte b in random)
Console.Write(b.ToString() + " ");
Console.WriteLine();
}
依測試結果,我們可以發現使用RNGCryptoServiceProvider,並不會有亂數種子的問題。
另外一提,為方便使用,好心的保哥已經幫我們整理好了簡單的靜態類別。使用上就跟使用Random類別類似。
using System;
using System.Security.Cryptography;
/// <summary>
/// 使用 RNGCryptoServiceProvider 產生由密碼編譯服務供應者 (CSP) 提供的亂數產生器。
/// </summary>
public static class RNG
{
private static RNGCryptoServiceProvider rngp = new RNGCryptoServiceProvider();
private static byte[] rb = new byte[4];
/// <summary>
/// 產生一個非負數的亂數
/// </summary>
public static int Next()
{
rngp.GetBytes(rb);
int value = BitConverter.ToInt32(rb, 0);
if (value < 0) value = -value;
return value;
}
/// <summary>
/// 產生一個非負數且最大值 max 以下的亂數
/// </summary>
/// <param name="max">最大值</param>
public static int Next(int max)
{
rngp.GetBytes(rb);
int value = BitConverter.ToInt32(rb, 0);
value = value % (max + 1);
if (value < 0) value = -value;
return value;
}
/// <summary>
/// 產生一個非負數且最小值在 min 以上最大值在 max 以下的亂數
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
public static int Next(int min, int max)
{
int value = Next(max - min) + min;
return value;
}
}
這邊我稍微整理了一下,把保哥的程式包成擴充方法:
using System;
using System.Security.Cryptography;
/// <summary>
/// 使用 RNGCryptoServiceProvider 產生由密碼編譯服務供應者 (CSP) 提供的亂數產生器。
/// </summary>
public static class RNGCryptoServiceProviderExtensions
{
private static byte[] rb = new byte[4];
/// <summary>
/// 產生一個非負數的亂數
/// </summary>
public static int Next(this RNGCryptoServiceProvider rngp)
{
rngp.GetBytes(rb);
int value = BitConverter.ToInt32(rb, 0);
return (value < 0)?-value:value;
}
/// <summary>
/// 產生一個非負數且最大值 max 以下的亂數
/// </summary>
/// <param name="max">最大值</param>
public static int Next(this RNGCryptoServiceProvider rngp,int max)
{
return Next(rngp) % (max + 1);
}
/// <summary>
/// 產生一個非負數且最小值在 min 以上最大值在 max 以下的亂數
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
public static int Next(this RNGCryptoServiceProvider rngp,int min, int max)
{
return Next(rngp, max - min) + min;
}
}
使用上就會像這樣
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
Console.WriteLine (rng.Next(10, 15));