Skip to content

Instantly share code, notes, and snippets.

@codeyu
Forked from prettycode/CryptoRandom.cs
Created December 24, 2017 14:31
Show Gist options
  • Save codeyu/7d2171c304078bd4a4af0b63c51dfebe to your computer and use it in GitHub Desktop.
Save codeyu/7d2171c304078bd4a4af0b63c51dfebe 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);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment