C
omputer games use random numbers extensively for rolling dice, shuffling cards, simulating nature, generating realistic physics, and performing secure multi-player transactions. Computers are great at generating pseudo-random numbers, but not so good at creating genuine random numbers. Pseudo-random numbers are num-bers that appear to be random, but are algorithmically computed based on the previ-ous random number. Genuine, or real, random numbers are numbers that not only appear random, but are unpredictable, nonrepeating and nondeterministic. They are generated without the input of the previous random number. This gem presents a method of creating genuine random numbers in software.Pseudo-Randomness
Pseudo-random number sequences eventually repeat themselves and can always be precisely reproduced given the same seed. This leads to distinct problems in gaming scenarios. Consider the common case of a game that initializes its random number generator (RNG) with the current tick count - the number of ticks since the machine was booted up. Now assume the player turns on their gaming console every time they begin playing this game. The level of randomness in the game is gated by the choice of seed, and the number of bits of randomness in the seed is unacceptably small.
Now consider the use of a pseudo-RNG to create secret keys for encrypting secure multiplayer game transmissions. At the core of all public key cryptographic sys-tems is the generation of unpredictable random numbers. The use of pseudo-random numbers leads to false security, because a pseudo-random number is fully pre-dictable—translate: easily hacked—if the initial state is known. It's not uncommon for the weakest part of crypto systems to be the secret key generation techniques
[Kelsey98].
Genuine Randomness
A genuine random number meets the following criteria: it appears random, has uniform distribution, is unpredictable, and is nonrepeating. The quality of
127
unpredictability is paramount for security purposes. Even given full knowledge of the algorithm, an attacker should find it computationally infeasible to predict the output [Schneier96].
The ideal way of creating genuine random numbers is to use a physical source of randomness, such as radioactive decay or thermal noise. Many such devices exist; see [Walker(a)] for one example. However, PCs and video game consoles do not typically have access to these types of devices. In the absence of a hardware source, the tech-nique recommended by RFC 1750 [Eastlake94] is "to obtain random input from a large number of uncorrelated sources and mix them with a strong mixing function."
By taking input from many unrelated sources, each with a few bits of randomness, and thoroughly hashing and mashing them up, we get a value with a high degree of entropy—a truly random number.
Random Input Sources
Examples of random input available on many PCs and game consoles include:
• System date and time
• Time since boot at highest resolution available
• Username or ID
• Computer name or ID
• State of CPU registers
• State of system threads and processes
• Contents of the stack
• Mouse or joystick position
• Timing between last N keystrokes or controller input
• Last N keystroke or controller data
• Memory status (bytes allocated, free, etc.)
• Hard drive state (bytes available, used, etc.)
• Last N system messages
• GUI state (window positions, etc.)
• Timing between last N network packets
• Last N network packet data
• Data stored at a semi-random address in main memory, video memory, etc.
• Hardware identifiers: CPU ID, hard drive ID, BIOS ID, network card ID, video card ID, and sound card ID
Some of these sources will always be the same for a given system, like the user ID or hardware IDs. The reason to include these values is that they're variable across machines, so they're useful in generating secret keys for transmitting network data.
Some sources change very little from sample to sample. For instance, the hard drive state and memory load may only change slightly from one read to the next. However, each input provides a few bits of randomness. Mixed together, they give many bits of randomness.
The more bits of entropy that can be obtained from input sources, the more ran-dom the output. It's useful to buffer sources such as mouse positions, keystrokes, and network packets over time in a circular queue. Then the entire queue can be used as an input source.
Hardware Sources
Some gaming platforms have access to physical sources of randomness. When these sources are available, they make excellent input sources. Examples of physical sources include:
• Input from sound card (for example, the microphone jack) with no source plugged in
• Input from a video camera
• Disk drive seek time (hard drive, CD-ROM, DVD)
• Intel 810 chipset hardware RNG (a thermal noise-based RNG implemented in silicon) [Intel99]
Mixing Function
In the context of creating genuine random numbers, a strong mixing function is a function where each bit of the output is a different complex and nonlinear function of each and every bit of the input. A good mixing function will change approximately half of the output bits given a single bit change in the input.
Examples of strong mixing functions include:
• DES (and most other symmetric ciphers)
• Diffie-Hellman (and most other public key ciphers)
• MD5, SHA-1 (and most other cryptographic hashes)
Secure hashing functions such as MD5 are the perfect mixers for many reasons:
they meet the basic requirements of a good mixing function, they've been widely ana-lyzed for security flaws, they're typically faster than either symmetric or asymmetric encryption, and they're not subject to any export restrictions. Public implementations are also widely available.
Limitations
Unlike generating pseudo-random numbers, creating genuine random numbers in software is very slow. For the output to be truly random, many sources must be sam-pled. Some of the sampling is slow, such as reading from the hard drive or sound card.
Furthermore, the sampled input must be mixed using complex algorithms.
Game consoles have a more limited selection of input sources compared to PCs, so they will tend to produce less random results. However, newer consoles often have disk drives of some sort (CD-ROM, DVD, hard disk) that can be used as good hard-ware sources of entropy.
The randomness of the results depends solely on the level of entropy in the input samples. The more input samples and the more entropy in each sample, the better the output. Keep in mind that the more often this algorithm is invoked in quick succes-sion, the less random the output, because the smaller the change in the input bits. To sum up, this technique is not a replacement for pseudo-RNG. Use this technique for the one-time generation of your RNG seed value or for generating network session keys that can then be used for hours or days.
Implementation
A C++ example of a genuine random number generator is provided on the accompa-nying CD. Any implementation of this algorithm will naturally be platform depen-dent. This particular version is specific to the Win32 platform, but is designed to be easily extensible to other platforms. It uses hardware sources of randomness, such as the Intel RNG and sound card input, when those sources are available. In the inter-ests of efficiency and simplicity, it does not use all of the examples listed previously as input, but uses enough to produce a high level of randomness.
The primary functionality resides in the GenRand object within the TrueRand namespace. Here is an example use of GenRand to create a genuine seed value:
#include "GenRand. h" // Genuine random number header unsigned int nSeed = TrueRand: :GenRand() .GetRandInt() ;
Here's another example showing the generation of a session key for secure net-work communication. The Buffer object is a simple wrapper around stof: :toasic__
string<unsigned char>, which provides the functionality we need for reserving space, appending data, and tracking the size of the sample buffer:
TrueRand: : GenRand randGen;
TrueRand: : Buffer bufSessionKey = randGen. GetRand( );
The Get/tend () function is the heart of the program. It samples the random inputs, and then uses a strong mixing function to produce the output. This imple-mentation uses MD5 hashing, so the resulting buffer is the length of an MD5 hash (16 bytes). The mCrypto object is a wrapper around the Win32 Crypto API, which includes MD5 hashing.
Buffer GenRand: :GetRand() {
// Build sample buffer
Buffer randlnputs = GetRandomlnputsO ; // Mix well and serve
return mCrypto.GetHash( CALG_MD5, randlnputs );
The GetRandomlnputsf) function is the input sampler. It returns a buffer with approximately 10K of sampled data. This function can easily be modified to include more or less input as desired. Because the time spent in the function varies according to system (drive, sound card) access, we can use the hardware latency as a source of random input; hence, the snapshot of the current time at the beginning and end of the function.
Buffer GenRand: :GetRandomInputs() {
// For speed, preallocate input buffer Buffer randln;
randln. reserve ( GetMaxRandInputSize() );
GetCurrTime( randln ); // append time to buffer GetStackState( randln ); // stack state
GetHardwareRng( randln ); // hardware RNG, if avail GetPendingMsgs( randln ); // pending Win32 msgs GetMemoryStatus( randln ); // memory load
GetCurrMousePos( randln ); // mouse position // . . . etc.
GetCurrTime( randln ); // random hardware latency return randln;
}
Finally, here's one of the input sampling functions. It extracts the current time, and then appends the data to the m R a n d l n p u t s buffer object. QueryPerformance-Counter() is the highest resolution timer in Windows, so it provides the most bits of randomness. We can ignore API failures in this case (and many others), because the worst that happens is that we append whatever random stack data happens to be in Perf Counter if the function fails.
void GenRand: :GetCurrTime( Buffer& randln ) {
LARGE_INTEGER Perf Counter;
QueryPerformanceCounter( &PerfCounter ); // Win32 API Append( randln, PerfCounter );
How Random Is GenRand?
There are many tests for examining the quality of random numbers. One test is the
^ c """) publicly available program ENT [Walker(b)], included on the accompanying CD, mm CD which applies a suite of tests to any data stream. Tests of GenRand () without using any sources of hardware input (including hard drive seek time), and generating a file of 25,000 random integers using GetRandInt() gives the following results:
• Entropy = 7.998199 bits per byte.
• Optimum compression would reduce the size of this 100,000-byte file by 0 percent.
• Chi square distribution for 100,000 samples is 250.13, and randomly would exceed this value 50 percent of the time.
• Arithmetic mean value of data bytes is 127.4918 (127.5 = random).
• Monte Carlo value for Pi is 3.157326293 (error 0.50 percent).
• Serial correlation coefficient is 0.000272 (totally uncorrelated = 0.0).
These results indicate that the output has a high degree of randomness. For instance, the chi square test—the most common test for randomness [Knuth98]—
indicates that we have a very random generator.
References
[Callas96] Callas, Jon, "Using and Creating Cryptographic-Quality Random Num-bers," available online at www.merrymeet.com/jon/usingrandom.html, June 1996.
[Eastlake94] Eastlake, D., Network Working Group, et al, "Randomness Recommen-dations for Security," RFC 1750, available online at www.faqs.org/rfcs/
rfcl750.html, December 1994. ] [Kelsey98] Kelsey, J., et al, "Cryptanalytic Attacks on Pseudorandom Number
Gener-ators," available online at www.counterpane.com/pseudorandom_number .html, March 1998.
[Intel99] Intel Corporation, "Intel Random Number Generator," available online at http://developer.intel.com/design/security/rng/rng.htm, 1999.
[Knuth98] Knuth, Donald, The Art of Computer Programming, Volume 2: Seminu-merical Algorithmsi Third Edition. Addison-Wesley. 1998.
[Schneier96] Schneier, Bruce, Applied Cryptography, Second Edition. John Wiley &
Sons. 1996.
[Walker(a)] Walker, John, "HotBits: Genuine Random Numbers Generated by Radioactive Decay," available online at www.fourmilab.ch/hotbits/.
[Walker(b)] Walker, John, "ENT: A Pseudorandom Number Sequence Test Pro-gram," available online at www.fourmilab.ch/random/.