Seeding the PRNG Random Number Generation

81 resulting bit would have a 50 chance of being 0, and a 50 chance of being 1. The output can be said to have one bit of entropy. We can also say that the value of the bit is truly random. If the coin flip was not fair, then we would have less than a bit of entropy, indicating that the resulting output isnt truly random. It is difficult for a deterministic machine like a computer to produce true entropy. Often, entropy is collected in small bits from all sorts of unpredictable events such as the low-order bits of the time between keystrokes, thread exits, and hard-disk interrupts. Its hard to determine how much entropy actually exists in a piece of data, though. Its fairly common to overestimate how much entropy is available. In general, entropy is unpredictable data, whereas pseudorandom numbers generated by a PRNG are not unpredictable at all if both the algorithm and the seed are known. Aside from using entropic data to seed the PRNG, its also a good idea to use pure entropy for generating important keys. If we generate a 256-bit key using a pseudorandom number generator that has a 128-bit seed, then our key does not contain 256-bits of strength, despite its length. At most, it has 128 bits. Similarly, if multiple keys are generated using the same seed, there will be correlations between the keys that are undesirable. The security of the keys should be independent. For all other random number requirements, pseudorandom numbers generated by the PRNG are suitable for use.

4.4.1 Seeding the PRNG

A common security pitfall is the incorrect seeding of the OpenSSL PRNG. There are functions that seed the generator easily enough, but the problems occur when a developer uses some predictable data for the seed. While the internal routines can quantify the amount of seed data, they can do nothing to determine the quality of that data i.e., how much entropy the data contains. Weve stated that the seed is an important value, but we havent explicitly looked at why this is so. For example, when using a session key to secure a connection, the basis for security is both the encryption algorithm used to encrypt the messages and the inability of the attacker to simply guess the session key. If an insecure seed is used, the PRNG output is predictable. If the output is predictable, the keys generated are predictable; thus the security of even a correctly designed application will be compromised. Clearly, a lot depends on the PRNGs output and as such, OpenSSL provides several functions for manipulating it. Its important to understand how to use these functions so that security can be assured. The function RAND_add seeds the PRNG with the specified data, considering only the specified number of bytes to be entropic. For example, suppose the buffer contained a pointer to the current time as returned by the standard C runtime function, time . The buffer size would be four bytes, but only a single byte of that could be reasonably considered entropic because the high bytes dont change frequently and are extremely predictable. The current time by itself is never a good source of entropy; weve only used it here for clarity. void RAND_addconst void buf, int num, double entropy; buf The buffer that contains the data to be used as the seed for the PRNG. num The number of bytes contained in the buffer. entropy 82 An estimate of the quantity of entropy contained in the buffer. Like RAND_add , the function RAND_seed seeds the PRNG with the specified data, but considers it to contain pure entropy. In fact, the default implementation of RAND_seed is simply to call RAND_add using the number of bytes in the buffer as the amount of entropy contained in the buffers data. void RAND_seedconst void buf, int num; buf The buffer that contains the data to be used as the seed for the PRNG. num The number of bytes contained in the buffer. Two additional functions are provided for use on Windows systems. Theyre not the best sources of entropy, but lacking a better source, theyre better than what most programmers would typically use or devise on their own. In general, its a good idea to avoid using either of these two functions unless there is no other entropy source available, especially if your application is running on a machine that ordinarily has no user interaction, such as a server. Theyre intended to be a last resort, and you should treat them as such. int RAND_eventUINT iMsg, WPARAM wParam, LPARAM lParam; RAND_event should be called from message handling functions and pass each messages identifier and parameters. The current implementation uses only the WM_KEYDOWN and WM_MOUSEMOVE messages for gathering entropy. void RAND_screenvoid; RAND_screen can be called periodically to gather entropy as well. The function will take a snapshot of the contents of the screen, generate a hash for each scan-line, and use the hash value as entropy. This function should not be called too frequently for a couple of reasons. One reason is that the screen wont change much, which can lead to predictability. The other reason is that the function is not particularly fast. A common misuse of the PRNG seeding functions is to use a static string as the seed buffer. Most often, this is done for no reason other than to silence OpenSSL because it will generate warning messages whenever the PRNG is not seeded and an attempt to use it is made. Another bad idea is to use an uninitialized memory segment, assuming its contents will be unpredictable enough. There are plenty of other examples of how not to seed the PRNG, but rather than enumerate them all here, well concentrate on the right way. A good rule of thumb to determine whether youre seeding the PRNG correctly is this: if youre not seeding it with data from a service whose explicit purpose is to gather entropy, youre not seeding the PRNG correctly. On many Unix systems, devrandom is available as an entropy-gathering service. On systems that provide such a device, there is usually another device, devurandom. The reason for this is that the devrandom device will block if there is not enough entropy available to produce the output requested. The devurandom device, on the other hand, will use a cryptographic PRNG to assure that it never blocks. Its actually most accurate to say that devrandom produces entropy and that devurandom produces pseudorandom numbers. 83 The OpenSSL package provides a function, RAND_load_file , which will seed the PRNG with the contents of a file up to the number of bytes specified, or its entirety if the limit is specified as - 1. It is expected that the file read will contain pure entropy. Since OpenSSL has no way of knowing whether the file actually does contain pure entropy, it assumes that the file does; OpenSSL leaves it to the programmer. Example 4-9 shows some example uses of this function and its counterpart, RAND_write_file . On systems that do have devrandom available, seeding the PRNG with RAND_load_file from devrandom is the best thing to do. Be sure to limit the number of bytes read from devrandom to some reasonable value, though If you specify -1 to read the entire file, RAND_load_file will read data forever and never return. The RAND_write_file function will write 1,024 bytes of random bytes obtained from the PRNG to the specified file. The bytes written are not purely entropic, but they can be safely used to seed an unseeded PRNG in the absence of a better entropy source. This can be particularly useful for a server that starts running immediately when a system boots up because devrandom will not have much entropy available when the system first boots. Example 4-9 demonstrates various methods of employing RAND_load_file and RAND_write_file . Example 4-9. Using RAND_load_file and RAND_write_file int RAND_load_fileconst char filename, long bytes; int RAND_write_fileconst char filename; Read 1024 bytes from devrandom and seed the PRNG with it RAND_load_filedevrandom, 1024; Write a seed file RAND_write_fileprngseed.dat; Read the seed file in its entirety and print the number of bytes obtained nb = RAND_load_fileprngseed.dat, -1; printfSeeded the PRNG with d bytes of data from prngseed.dat.\n, nb; When you write seed data to a file with RAND_write_file , you must be sure that youre writing the file to a secure location. On a Unix system, this means the file should be owned by the user ID of the application, and all access to group members and other users should be disallowed. Additionally, the directory in which the file resides and all parent directories should have only write access enabled for the directory owner. On a Windows system, the file should be owned by the Administrator and allow no permissions to any other users. One final point worth mentioning is that OpenSSL will try to seed the PRNG transparently with devurandom on systems that have it available. While this is better than nothing, its a good idea to go ahead and read better entropy from devrandom, unless there is a compelling reason not to. On systems that dont have devurandom, the PRNG will not be seeded at all, and you must make sure that you seed it properly before you attempt to use the PRNG or any other part of OpenSSL that utilizes the PRNG. For systems that have devrandom, Example 4-10 demonstrates how to use it to seed the OpenSSL PRNG. Example 4-10. Seeding OpenSSLs PRNG with devrandom int seed_prngint bytes { if RAND_load_filedevrandom, bytes return 0; return 1; } 84

4.4.2 Using an Alternate Entropy Source