It’s tough to get a computer to generate good, random numbers. The randomizing functions of most programming languages are largely parlor tricks to make the numbers “appear” to be random while really being a predetermined data set cleverly disguised as random. This is fine for basic applications, but it just isn’t sufficient for special security, encryption or bulk use of random features. Patterns you can find in the predefined “random” functions can be identified and exploited. So how can you make your code stronger?

Randomness has always be difficult for computers. Computers work off predictable logic and math, and true randomness is, well, unpredictable. There is often a need to introduce random elements in code for a variety of reasons. Because of this, most programming languages have a pseudo-random number generator built in. Most of the time, these can produce what appear at a glance to be random numbers. However, they are typically manufactured by an table or algorithm, and not really random at all.

Take the Microsoft .NET System.Random class, for example. Believe it or not, this (effectively) uses a pre-defined number table to cycle a list of “random” numbers. The result is a predictable series of numbers. In fact, if you initialize two instances quickly, you’ll see them both repeat the same list of “random” numbers! Since there are a finite number of elements in the table, the pattern eventually repeats itself. Don’t believe me? Check out the official MSDN documentation on System.Random. Scary stuff if you are expecting more from your random numbers.

System.Random is simply not reliable enough for specializations like cryptography. To combat this, Microsoft added a RandomNumberGenerator abstract class specifically engineered to be strong enough for cryptographic use. You can find this in System.Security.Cryptography. While slower than System.Random, it has no obvious discernible patterns because it uses a variety of less predictable elements and more complex algorithms to calculate the “random” numbers. Still, they are not true random numbers… But you would have a hard time finding a pattern in them without a tremendous amount of data to reference.

You might be thinking: OK, I’ll just use RandomNumberGenerator class next time instead of System.Random! Not so fast… The more random class is built for cryptography, so it’s only easy to generate random byte arrays. It’s intended for use in derived classes, not really be used on its own–that’s why it’s an abstract class. Not very helpful for general use. One benefit of System.Random is you can easily call some helpful functions. For example:

  • Random.Next() – Generates a random, nonnegative integer
  • Random.Next(10) – Generates a random, nonnegative integer less than 10
  • Random.Next(18, 22)  – Generates a random integer 18 or greater but less than 22
  • Random.NextDouble() – Generates a random double between 0.0 and 1.0

RandomNumberGenerator doesn’t have any of these functions for your everyday randomization needs. Good new, though: I wrote a derrived class that add the equivalent functionality! Simply add this class to your project, and instanciate a CryptoRandom object, and you can use them just like System.Random:

CryptoRandom rng = new CryptoRandom();
Console.WriteLine(rng.Next());
Console.WriteLine(rng.Next(10));
Console.WriteLine(rng.Next(18, 22));
Console.WriteLine(rng.NextDouble());

Here’s the code for the CryptoRandom class.

[CryptoRandom.cs] 

using System;
using
System.Security.Cryptography;

///<summary>
/// Represents a pseudo-random number generator, a device that produces random data.
///</summary>
classCryptoRandom : RandomNumberGenerator
{
privatestaticRandomNumberGenerator r;

///<summary>
/// Creates an instance of the default implementation of a cryptographic random number generator that can be used to generate random data.
///</summary>
public CryptoRandom()
 
  r = RandomNumberGenerator.Create();
 }

 ///<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>
 publicoverridevoid GetBytes(byte[] buffer)
 {
  r.GetBytes(buffer);

 }

 ///<summary>
 /// Returns a random number between 0.0 and 1.0.
 ///</summary>
 publicdouble NextDouble()
 {
  byte[] b = newbyte[4];
  r.GetBytes(b);
  return (double)BitConverter.ToUInt32(b, 0) / UInt32.MaxValue;
 }

 ///<summary>
 /// Returns a random number within the specified range.
 ///</summary>
 ///<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. maxValue must be greater than or equal to minValue.</param>
 publicint Next(int minValue, int maxValue)
 {
  return (int)Math.Round(NextDouble() * (maxValue – minValue – 1)) + minValue;
 }

 ///<summary>
 /// Returns a nonnegative random number.
 ///</summary>
 publicint Next()
 {
  return Next(0, Int32.MaxValue);
 }

 ///<summary>
 /// Returns a nonnegative random number less than the specified maximum
 ///</summary>
 ///<param name=”maxValue”>The inclusive upper bound of the random number returned. maxValue must be greater than or equal 0</param>
 publicint Next(int maxValue)
 {
  return Next(0, maxValue);
 }
}

Like this post? Share it!