Skip to content

Instantly share code, notes, and snippets.

@prettycode
Last active November 10, 2021 15:27
Show Gist options
  • Save prettycode/5471944 to your computer and use it in GitHub Desktop.
Save prettycode/5471944 to your computer and use it in GitHub Desktop.
Cryptographically-strong random number generator in C#.
// Cryptographically-strong random number generator
// Source: MSDN Magazine > 2007 > September > .NET Matters: Tales from the CryptoRandom
// Source URL: http://msdn.microsoft.com/en-us/magazine/cc163367.aspx
// Authors: Stephen Toub & Shawn Farkas
public class CryptoRandom : Random
{
private RNGCryptoServiceProvider cryptoProvider = new RNGCryptoServiceProvider();
private byte[] uint32Buffer = new byte[4];
/// <summary>
/// An implementation of System.Random used for cryptographically-strong random number generation.
/// </summary>
public CryptoRandom() { }
/// <summary>
/// An implementation of System.Random used for cryptographically-strong random number generation.
/// </summary>
public CryptoRandom(Int32 seedIgnored) { }
/// <summary>
/// Returns a nonnegative random number.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>.
/// </returns>
public override Int32 Next()
{
cryptoProvider.GetBytes(uint32Buffer);
return BitConverter.ToInt32(uint32Buffer, 0) & 0x7FFFFFFF;
}
/// <summary>
/// Returns a nonnegative random number less than the specified maximum.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to zero, and less than <paramref name="maxValue"/>; that is, the range of return values ordinarily includes zero but not <paramref name="maxValue"/>. However, if <paramref name="maxValue"/> equals zero, <paramref name="maxValue"/> is returned.
/// </returns>
/// <param name="maxValue">The exclusive upper bound of the random number to be generated. <paramref name="maxValue"/> must be greater than or equal to zero.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxValue"/> is less than zero.</exception>
public override Int32 Next(Int32 maxValue)
{
if (maxValue < 0) throw new ArgumentOutOfRangeException("maxValue");
return Next(0, maxValue);
}
/// <summary>
/// Returns a random number within a specified range.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to <paramref name="minValue"/> and less than <paramref name="maxValue"/>; that is, the range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>. If <paramref name="minValue"/> equals <paramref name="maxValue"/>, <paramref name="minValue"/> is returned.
/// </returns>
/// <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. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
public override Int32 Next(Int32 minValue, Int32 maxValue)
{
if (minValue > maxValue) throw new ArgumentOutOfRangeException("minValue");
if (minValue == maxValue) return minValue;
Int64 diff = maxValue - minValue;
while (true)
{
cryptoProvider.GetBytes(uint32Buffer);
UInt32 rand = BitConverter.ToUInt32(uint32Buffer, 0);
Int64 max = (1 + (Int64)UInt32.MaxValue);
Int64 remainder = max % diff;
if (rand < max - remainder)
{
return (Int32)(minValue + (rand % diff));
}
}
}
/// <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>
public override double NextDouble()
{
cryptoProvider.GetBytes(uint32Buffer);
UInt32 rand = BitConverter.ToUInt32(uint32Buffer, 0);
return rand / (1.0 + UInt32.MaxValue);
}
/// <summary>
/// Fills the elements of a specified array of bytes with random numbers.
/// </summary>
/// <param name="buffer">An array of bytes to contain random numbers.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="buffer"/> is null.
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
cryptoProvider.GetBytes(buffer);
}
}
@marceloaugusto80
Copy link

Hi, brother. Very smart implementation of RNGCryptoServiceProvider .

My only doubt is if the class should not implement IDisposable interface and dispose the RNGCryptoServiceProvider instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment