在指定范围内使用RNGCRYPTOSERVICEPROVIDER生成随机数

时间:2012-12-03 04:35:46

标签: .net vb.net random cryptography

我已经使用以下编码来生成1000-9999范围内的范围:

Dim byt As Byte() = New Byte(1000) {}

Dim rngCrypto As New RNGCryptoServiceProvider()
rngCrypto.GetBytes(byt)

Dim randomNumber As Integer = BitConverter.ToInt32(byt, 9999)
Label4.Text = randomNumber

显示错误:

  

指数超出范围。必须是非负数且小于集合的大小。参数名称:startIndex

我已经完成了以下代码。这是对的吗?

Public Sub secrand()

    Static r As Random = Nothing

    If r Is Nothing Then
        Dim seed() As Byte = New Byte(4) {}
        Dim rng As New RNGCryptoServiceProvider
        rng.GetBytes(seed)
        r = New Random(BitConverter.ToInt32(seed, 0))
        Label4.Text = r.Next(1000, 9999)
    End If
End Sub

1 个答案:

答案 0 :(得分:5)

BitConverter.ToInt32的第二个参数是字节数组的偏移量。它应该是0。如果你只使用其中的4个,也没有理由获得1000个字节。

C#中的工作版本:

public static int RandomUniform(int count)
{
    if(count <= 0)
         throw new ArgumentOutOfRangeException("count");
    var rng=new RNGCryptoServiceProvider();
    var bytes=new byte[8];
    rng.GetBytes(bytes, 0);
    return BitConverter.ToUInt64() % (uint)count;
}

Label4.Text = 1000 + RandomUniform(9000);

在VB.net中,这看起来类似于

Public Shared Function RandomUniform(count As Integer) As Integer
    If count <= 0 Then
        Throw New ArgumentOutOfRangeException("count")
    End If
    Dim rng = New RNGCryptoServiceProvider()
    Dim bytes = New Byte(8) {}
    rng.GetBytes(bytes, 0)
    Return BitConverter.ToUInt64() Mod CUInt(count)
End Function

此代码有两个缺点:

  1. 这很慢。 RNGCryptoServiceProvider.GetBytes的每次呼叫开销很大。 为了获得更好的性能,请使用几千字节的缓冲区,并在用完时调用GetBytes
  2. 它并不完全一致,但对于大多数应用来说,偏差应该足够小。

    即使使用显示最大偏差的count值,您也需要超过100亿个样本来检测它,而对于System.Random来说,少数就足够了。即偏差比System.Random小约80亿倍。

  3. 如果您无法接受任何一个弱点,您可以查看我的random number generator project,它提供快速,安全且无偏见的号码。但这是以添加外部库而不是简单地编写几行代码为代价的。