Redemption Steps

For the most part, you should use the system CRNG. The only exceptions are when youre coding for a system that doesnt have one, when you have a legitimate need to be able to replay number streams, or when you need more security than the system can produce (particularly if youre generating 192-bit or 256-bit keys on Windows using the default cryptographic provider).

Windows

The Windows CryptoAPI provides the routine CryptGenRandom(), which can be implemented by any cryptographic provider. This is a CRNG, where the system frequently reseeds with new entropy that is collected by the operating system.

This call fills a buffer with the specified number of bytes. Heres a simple example of getting a provider and using it to fill a buffer:

 #include <wincrypt.h> void GetRandomBytes(BYTE *pbBuffer, DWORD dwLen) {  HCRYPTPROV hProvider; /* You should probably just instantiate this once, really. */  if (!CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))  ExitProcess((UINT)-1);  if (!CryptGenRandom(hProvider, dwLen, pbBuffer)) {  ExitProcess((UINT)-1); } 

Assuming youre running a modern enough version of Windows to have this API at all (a pretty safe bet), the actual call to CryptGenRandom() never fails. Its good to leave the code as-is, though, because other providers might have an implementation that can fail; for instance, if an underlying true random number generator fails FIPS tests.

.NET Code

Rather than calling the hopelessly predictable Random class, you should use code like this C# code:

 using System.Security.Cryptography; try {  byte[] b = new byte[32];  new RNGCryptoServiceProvider().GetBytes(b);  // b contains 32 bytes of random data } catch(CryptographicException e) {  // Error } 

Or, in VB.NET:

 Imports System.Security.Cryptography Dim b(32) As Byte Dim i As Short Try  Dim r As New RNGCryptoServiceProvider()  r.GetBytes(b)  ' b now contains 32 bytes of random data Catch e As CryptographicException  ' Handle Error End Try 

Unix

On Unix systems, the cryptographic random number generator acts exactly like a file. Random numbers are served up by two special devices (generally, /dev/random and /dev/ urandom, but OpenBSD is an exception, providing /dev/srandom and /dev/urandom). Implementations differ , but they all have properties that are more or less alike. The devices are implemented in a way that allows you to get keys out of any reasonable size , because they all keep what is effectively a very large key that generally contains far more than 256 bits of entropy. As with Windows, these generators reseed themselves frequently, usually by incorporating all interesting asynchronous events, such as mouse and keyboard presses.

The difference between /dev/random and /dev/urandom is pretty subtle. One might think that the former would be an interface to true random numbers, and the latter, an interface to a CRNG. While that may have been the original intent, its not reflected in any real OS. Instead, in all cases, they are both CRNGs. They are also generally the exact same CRNG. The only difference is that /dev/random uses what is ultimately a very stupid metric to determine whether there might be some risk of not having enough entropy. The metric is conservative, which could be considered good. It is so conservative, in fact, that the system will be prone to denial of service attacks, particularly on servers that never have anybody sitting on the console. Unless you really have good reason to believe there was never any unguessable state in the system CRNG to begin with, there is no good reason to ever use /dev/random. Therefore, we recommend you always use /dev/urandom.

You use the same code to access the generator that youd use to read from a file. For example, in Python:

 f = open('/dev/urandom') # If this fails, an exception is thrown.  data = f.read(128) # Read 128 random bytes and stick the results in data 

Although, in Python, os.urandom() provides a single uniform interface, reading from the right device on Unix and calling CryptGenRandom() on Windows.

Java

Like Microsoft, Java has a provider-based architecture, and various providers could implement Javas API for cryptographically secure random numbers, and even have that API return raw entropy. But, in reality, youre probably going to get the default provider. And, with most Java Virtual Machines (JVMs), the default provider inexplicably collects its own entropy, instead of leveraging the system CRNG. Since Javas not inside the operating system, it isnt in the best place to collect this data; and as a result, it can take a noticeable amount of time (several seconds) to generate the first number. Worse, Java does this every time you start a new application.

If you know what platform youre on, you can just use the system generator to seed a SecureRandom instance, and that will avoid the lag. But, if youre looking for the most portable solution, most people still find the default good enough. Dont do what some people have done, and hardcode a seed, though!

SecureRandom provides a nice set of APIs for accessing the generator, allowing you to get a random byte array (nextBytes), Boolean (nextBoolean), Double (nextDouble), Float (nextFloat), Int (nextInt), or Long (nextLong). You can also get a number with a gaussian distribution (nextGaussian) instead of a uniform distribution.

To call the generator, you just need to instantiate the class (the default constructor works perfectly well), and then call one of the accessors above. For example:

 import java.security.SecureRandom; ... byte test[20]; SecureRandom crng = new SecureRandom(); crng.nextBytes(test); ... 

Replaying Number Streams

If, for some strange reason (like with Monte Carlo simulations), you want to use a random number generator where you can save the seed and reproduce the number stream, get a seed from the system generator, and then use it to key your favorite block cipher (lets say AES). Treat the 128-bit input to AES as a single 128-bit integer. Start it at 0. Produce 16 bytes of output by encrypting this value. Then, when you want more output, increment the value and encrypt again. You can keep doing this until the cows come home. If you also want to know what the 400,000th byte in a stream was, its incredibly easy to compute. (This was never the case with traditional pseudo-random number generator APIs.)

This random number generator is as good a cryptographic generator as you can get. Its a well-known construct for turning a block cipher into a stream cipher, called counter mode .



19 Deadly Sins of Software Security. Programming Flaws and How to Fix Them
Writing Secure Code
ISBN: 71626751
EAN: 2147483647
Year: 2003
Pages: 239

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net