Snippets

Craig Phillips BetterRandom - A C# drop-in replacement for the built-in Random class which uses the RNGCryptoServiceProvider to generate better (and cryptographically secure) random numbers.

Created by Craig Phillips last modified
using System;
using System.Security.Cryptography;
 
namespace BetterRandomNumbers
{
	// BetterRandom.cs
	// This class implements a random number generator that is based off the Windows "Next Generation" cryptographically secure
	// random number generator.  It inherits from the base Random class, so can be used as a "drop-in" replacement for the
	// built-in .NET System.Security.Random class, but providing a superior quality of random numbers.
	public class BetterRandom : Random, IDisposable
    {
        private const int BufferSize = 1024;  // must be a multiple of 4
        private readonly byte[] _randomBuffer;
        private int _bufferOffset;
        private RNGCryptoServiceProvider rng;

        public BetterRandom()
        {
            _randomBuffer = new byte[BufferSize];
            rng = new RNGCryptoServiceProvider();
            _bufferOffset = _randomBuffer.Length;
        }

        private void FillBuffer()
        {
            rng.GetBytes(_randomBuffer);
            _bufferOffset = 0;
        }

        public override int Next()
        {
            if (_bufferOffset >= _randomBuffer.Length)
            {
                FillBuffer();
            }

            var val = BitConverter.ToInt32(_randomBuffer, _bufferOffset) & 0x7fffffff;
            _bufferOffset += sizeof(int);
            
            return val;
        }

        public override int Next(int maxValue)
        {
            return Next() % maxValue;
        }

        public override int Next(int minValue, int maxValue)
        {
            if (maxValue < minValue)
            {
                throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than or equal to minValue");
            }
            var range = maxValue - minValue;
            return minValue + Next(range);
        }

        public override double NextDouble()
        {
            var val = Next();
            return (double)val / int.MaxValue;
        }

        public void GetBytes(byte[] buff)
        {
            rng.GetBytes(buff);
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (rng != null)
                {
                    rng.Dispose();
                    rng = null;
                }
            }
            GC.SuppressFinalize(this);
        }
    }
}

Comments (0)