[ Team LiB ] Previous Section Next Section

11.9 Using the OpenSSL Random Number API

11.9.1 Problem

Many functions in the OpenSSL library require the use of the OpenSSL pseudo-random number generator. Even if you use something like /dev/urandom yourself, OpenSSL will use its own API under the hood and thus must be seeded properly.

Unfortunately, some platforms and some older versions of OpenSSL require the user to provide a secure seed. Even modern implementations of OpenSSL merely read a seed from /dev/urandom when it is available; a paranoid user may wish to do better.

When using OpenSSL, you may want to use the provided PRNG for other needs, just for the sake of consistency.

11.9.2 Solution

OpenSSL exports its own API for manipulating random numbers, which we discuss in the next section. It has its own cryptographic PRNG, which must be securely seeded.

To use the OpenSSL randomness API, you must include openssl/rand.h in your code and link against the OpenSSL crypto library.

11.9.3 Discussion

Be sure to check all return values for the functions below; they may return errors.

With OpenSSL, you get a cryptographic PRNG but no entropy gateway. Recent versions of OpenSSL try to seed its PRNG using /dev/random, /dev/urandom, and EGD, trying several well-known EGD socket locations. However, OpenSSL does not try to estimate how much entropy its PRNG has. It is up to you to ensure that it has enough before the PRNG is used.

On Windows systems, a variety of sources are used to attempt to gather entropy, although none of them actually provides much real entropy. If an insufficient amount of entropy is available, OpenSSL will issue a warning, but it will keep going anyway. You can use any of the sources we have discussed elsewhere in this chapter for seeding the OpenSSL PRNG. Multiple API functions are available that allow seed information to be passed to the PRNG.

One such function is RAND_seed( ), which allows you to pass in arbitrary data that should be completely full of entropy. It has the following signature:

void RAND_seed(const void *buf, int num);

This function has the following arguments:

buf

Buffer containing the entropy to seed the PRNG.

num

Length of the seed buffer in bytes.

If you have data that you believe contains entropy but does not come close to one bit of entropy per bit of data, you can call RAND_add( ), which is similar to RAND_seed( ) except that it allows you to provide an indication of how many bits of entropy the data has:

void RAND_add(const void *buf, int num, double entropy);

If you want to seed from a device or some other file (usually, you only want to use a stored seed), you can use the function RAND_load_file( ), which will read the requested number of bytes from the file. Because there is no way to determine how much entropy is contained in the data, OpenSSL assumes that the data it reads from the file is purely entropic.

int RAND_load_file(const char *filename, long max_bytes);

If -1 is specified as the length parameter to this function, it reads the entire file. This function returns the number of bytes read. The function can be used to read from the /dev/random and /dev/urandom devices on Unix systems that have them, but you must make sure that you don't specify -1 for the number of bytes to read from these files; otherwise, the function will never return!

To implement PRNG state saving with OpenSSL, you can use RAND_write_file( ), which writes out a representation of the PRNG's internal state that can be used to reseed the PRNG when needed (e.g., after a reboot):

int RAND_write_file(const char *filename);

If there is any sort of error, RAND_write_file( ) will return -1. Note that the system may write a seed file without enough entropy, in which case it will also return -1. Otherwise, this function returns the number of bytes written to the seed file.

To obtain pseudo-random data from the PRNG, use the function RAND_bytes( ):

int RAND_bytes(unsigned char *buf, int num);

If the generator is not seeded with enough entropy, this function could produce output that may be insecure. In such a case, the function will return 0. Make sure that you always check for this condition!

Do not, under any circumstances, use the API function, RAND_pseudo_bytes( ). It is not a cryptographically strong PRNG and therefore is not worth using for anything that has even a remote possibility of being security-relevant.

You can implement spc_rand( ), the cryptographic pseudo-randomness function from Recipe 11.2, by simply calling RAND_bytes( ) and aborting if that function returns 0.

#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>
   
unsigned char *spc_rand(unsigned char *buf, size_t l) {
  if (!RAND_bytes(buf, l)) {
    fprintf(stderr, "The PRNG is not seeded!\n");
    abort(  );
  }
  return buf;
}

11.9.4 See Also

Recipe 11.2

    [ Team LiB ] Previous Section Next Section