A simple C# wrapper class for RNGCryptoServiceProvider

These lab notes describe a program written in C# to test various cryptographic algorithms. In our first note, we presented a C# program shell for an algorithm test program. That shell prompts the user to indicate which algorithms will be tested. In our shell program example, we referred to a krandom class that would act as a pseudo-random number generator.

This is the second note in our series. In this note, we will implement the krandom class as a thin wrapper around the .NET RNGCryptoServiceProvider class. In addition we will add test logic to our test driver program ktest, to implement one of several pseudo-random algorithm tests described by the National Institute of Standards and Technology (NIST) in the publication "A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications."

In a later note, we will substitute a different implementation of krandom, using a variation of a well-known pseudorandom algorithm created by George Marsaglia in 1999.

Step 1. The krandom class using .NET RNGCryptoServiceProvider

Here is the implementation of krandom using the .NET RNGCryptoServiceProvider.

We add a "using" statement to allow references within the System.Security.Cryptography namespace. We define an instance of the RNGCryptoServiceProvider class within our krandom class. The krandom class as a default constructor krandom() that instantiates the RNGCryptoServiceProvider instance. The krandom class also has a Random() method that returns an unsigned integer containing pseudo-random bits. The RNGCryptoServiceProvider instance, m_rngcsp, exposes a GetBytes methods. We call this method to fill a local Byte array with pseudo-random bits. Then, BitConverter.ToUInt32 is called to safely place these bits in our uint return value.

Step 2. Implementing a "monobit" test in C#.

The National Institute of Science and Technology (NIST) is a part of the United States Commerce Department. NIST promulgates standards in the field of information security through its Computer Security Division which provides publications through the Computer Security Resource Center (CSRC). The standards related to information processing and available through the CSRC is known collective as the Federal Information Processing Standards (FIPS). Of particular interest here, is FIPS Special Publication 800-22 Revision 1a. This document describes tests for pseudo-random number generators. These tests developed from an earlier, simpler, set of tests published in FIPS 140-1. We will implement one of these tests, a "monobit" test, below. The monobit test counts the number of 1's in a stream of 20,000 pseudo-random bits and verifies that the sum is within an acceptable range. Our test routine, part of the ktest class introduced in our previous lab note, will perform the monobit test on pseudo-random bits generated by a krandom instance and output test results.

Building on the sample program introduced in our last note, we first add two constant integers to define the bounds of the acceptable range test used in the monobit test.

Next, we add an array to our ktest class. This array specifies the number of 1's in each of the 256 possible byte values. This array will help us quickly accumulate the total number of 1's in a series of bytes or integers.

Next, we add a new helper method, Prompt(), to our class. This method will be called between tests, to allow the user to view the results of preceding tests before continuing. In a later note, we will add more control to the behavior of Prompt(). The Prompt() method introduces Console.ReadKey(), which will wait for the user to press a key.

Now, we add content to the body of the TestPseudoRandom() method, which we left as simply a shell in our last note. This method now begins by defining local variables including a managed array of unsigned integers to hold our pseudo-random bits and several other unsigned integers and doubles. After logging our function header, we iterate calls to our krandom class instance, m_prng, calling the Random() method to return pseudo-random bits in an unsigned integer. We log each returned unsigned integer using the Log() method, passing the output of String.Format. Then we add the pseudo-random to our array. At the end of this step, we prompt the user to hit a key to continue.

Next, before running our monobit test, we add a section of code to report the random distributoin by bit. In other words, we determine the percentage that each bit in an unsigned integer returned by Random() was set to 1. We test this result, for each of the 32 bits in an unsigned integer, against an acceptable range. For our purposes, an acceptable percentage is between 45% and 55%.

Now we perform the monobit test. For the first 20,000 bits of our pseudo-random sample, we count the number of 1's. This sum is tested against a valid range. At the end of this test, we notify the user that our tests are completed.

The output of our ktest program is shown below. In our next note, we will insert additional tests. We will also substitute the .NET RNGCryptoServiceProvider implementation of krandom with an alternative algorithm and compare our test results.