The .NET Framework includes the System.Random class, whose job it is to generate random numbers. It does so using a sequence based on a seed value, which is based on the system time by default. There are numerous possible seeds and predicting the exact time that a Random object will be created is not easy. That, coupled with the fact that the distribution of numbers generated by the sequence satisfies various statistical requirements for randomness, means that the Random class is quite suitable for most of your random number needs.
The main issue with the Random class is that, given a particular seed, the sequence will always produce the same numbers. That can actually be good for some testing scenarios but it does mean that the results could be manipulated. Where very high levels of unpredictability are required, the Random class is not suitable.
I've seen a number of people use various methods to generate more random random numbers. That's not really necessary though. The .NET Framework also includes the System.Security.Cryptography.RNGCryptoServiceProvider class for generating random numbers. It's output is sufficiently random for use in cryptography, so there's really no need for anything more random than that.
One issue with the RNGCryptoServiceProvider class, though, is that it populates Byte arrays with random values. That's not always completely convenient though, as the most common need in applications is a random Integer within a specific range. The Random class is nice and easy to use in that scenario, thanks to its Next method. What if we could combine the ease of use of the Random class with the increased randomness of the RNGCryptoServiceProvider class?
As it happens, we can. The Random class has a Protected method named Sample that generates a Double in the range 0.0 <= x < 1.0. The result of that method is then used in the other methods to generate Integers in a range. We can define our own class that inherits Random and overrides that Sample method to use RNGCryptoServiceProvider internally. Here's one I prepared earlier:
vb.net Code:
Imports System.Security.Cryptography
''' <summary>
''' Represents a random number generator, a device that produces a sequence of numbers that meet cryptographic requirements for randomness.
''' </summary>
''' <remarks>
''' Seed values are meaningless because this class uses a cryptographic service provider internally rather than a pseudo-random sequence.
''' </remarks>
Public Class CryptoRandom
Inherits Random
Implements IDisposable
''' <summary>
''' The internal random number generator.
''' </summary>
Private ReadOnly rng As New RNGCryptoServiceProvider
''' <summary>
''' Returns a random number between 0.0 and 1.0.
''' </summary>
''' <returns>
''' A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
''' </returns>
''' <remarks>
''' Uses a cryptographic service provider internally rather than a pseudo-random sequence.
''' </remarks>
Protected Overrides Function Sample() As Double
Dim data(7) As Byte
Dim number As ULong
Do
'Get 8 random bytes.
rng.GetBytes(data)
'Convert the bytes to an unsigned 64-bit number.
number = BitConverter.ToUInt64(data, 0)
Loop While number = ULong.MaxValue 'The result must be less than 1.0
'Divide the number by the largest possible unsigned 64-bit number to get a value in the range 0.0 <= N < 1.0.
Return number / ULong.MaxValue
End Function
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
'Dispose the underlying cryptographic random number generator.
rng.Dispose()
End If
End If
Me.disposedValue = True
End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
You can create an instance of that class and use it in pretty much exactly the same way as you would a Random object. The only difference is that you will need to call its Dispose method when you're done, in order to dispose the internal RNGCryptoServiceProvider object. Sample usage:
vb.net Code:
Public Class Form1
Private ReadOnly rng As New CryptoRandom
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
1) The RNGCryptoServiceProvider didn't have a Dispose method until Framework 4.0, so if you use this class while compiling against framework 3.5, you will need to comment out the rng.Dispose line in the Dispose method.
2) A comparison test of the relative speed of this random test versus the basic Random object shows what should be expected: The standard Random class is about 100x faster than the cryptographic random test. Both are VERY fast, though, so speed really isn't an issue. The speed might become an issue if you are going to be generating LOTS of random values in a time-critical loop, but for all other purposes, either method will be suitably fast.
The RNGCryptoServiceProvider didn't have a Dispose method until Framework 4.0, so if you use this class while compiling against framework 3.5, you will need to comment out the rng.Dispose line in the Dispose method.
I didn't realise that. Thanks for pointing it out.