 C++ Coding Standard

Rule:  MSC30-C Synopsis: Do not use the rand() function for generating pseudorandom numbers Language: C++ Severity Level: 2 Category: Security
Description:

Pseudorandom number generators use mathematical algorithms to produce a sequence of numbers with good statistical properties, but the numbers produced are not genuinely random.

The C Standard `rand()` function makes no guarantees as to the quality of the random sequence produced. The numbers generated by some implementations of  `rand()` have a comparatively short cycle and the numbers can be predictable. Applications that have strong pseudorandom number requirements must use a generator that is known to be sufficient for their needs.

Noncompliant Code Example

The following noncompliant code generates an ID with a numeric part produced by calling the `rand()` function. The IDs produced are predictable and have limited randomness.

 `#include ` `#include ` ` `   `enum` `{ len = 12 };` ` `   `void` `func(` `void` `) {` `  ` `/*` `   ` ```* id will hold the ID, starting with the characters``` `   ` ```*  "ID" followed by a random integer.``` `   ` `*/` `  ` `char` `id[len];  ` `  ` `int` `r;` `  ` `int` `num;` `  ` `/* ... */` `  ` `r = ` `rand` `();  ` ```/* Generate a random integer */``` `  ` `num = snprintf(id, len, ` `"ID%-d"` `, r);  ` `/* Generate the ID */` `  ` `/* ... */` `}`

Compliant Solution (POSIX)

This compliant solution replaces the `rand()` function with the POSIX `random()` function:

 `#include ` `#include ` `#include `   `enum` `{ len = 12 }; `   `void` `func(` `void` `) {` `  ` `/*` `   ` ```* id will hold the ID, starting with the characters``` `   ` ```*  "ID" followed by a random integer.``` `   ` `*/` `  ` `char` `id[len];  ` `  ` `int` `r;` `  ` `int` `num;` `  ` `/* ... */` `  ` `struct` `timespec ts;` `  ` `if` ```(timespec_get(&ts, TIME_UTC) == 0) {``` `    ` `/* Handle error */` `  ` `}` `  ` ```srandom(ts.tv_nsec ^ ts.tv_sec);  ``` `/* Seed the PRNG */` `  ` `/* ... */` `  ` `r = random();  ` ```/* Generate a random integer */``` `  ` `num = snprintf(id, len, ` `"ID%-d"` `, r);  ` `/* Generate the ID */` `  ` `/* ... */` `}`

The POSIX `random()` function is a better pseudorandom number generator. Although on some platforms the low dozen bits generated by `rand()` go through a cyclic pattern, all the bits generated by  `random()` are usable. The `rand48` family of functions provides another alternative for pseudorandom numbers.

Although not specified by POSIX, `arc4random()` is another possibility for systems that support it. The `arc4random(3)` manual page [OpenBSD] states

... provides higher quality of data than those described in rand(3), random(3), and drand48(3).

To achieve the best random numbers possible, an implementation-specific function must be used. When unpredictability is crucial and speed is not an issue, as in the creation of strong cryptographic keys, use a true entropy source, such as `/dev/random` , or a hardware device capable of generating random numbers. The `/dev/random` device can block for a long time if there are not enough events going on to generate sufficient entropy.

Compliant Solution (Windows)

On Windows platforms, the `BcryptGenRandom()` function can be used to generate cryptographically strong random numbers. The Microsoft Developer Network `BCryptGenRandom()` reference [MSDN] states:

The default random number provider implements an algorithm for generating random numbers that complies with the NIST SP800-90 standard, specifically the CTR_DRBG portion of that standard.

 ```#include ``` `#include ` `#include `   ```#pragma comment(lib, "Bcrypt")```   `void` `func(` `void` `) {` `  ` `BCRYPT_ALG_HANDLE Prov;` `  ` `int` `Buffer;` `  ` `if` `(!BCRYPT_SUCCESS(` `          ` ```BCryptOpenAlgorithmProvider(&Prov, BCRYPT_RNG_ALGORITHM,``` `                                      ` `NULL, 0))) {` `    ` `/* handle error */` `  ` `}` `  ` `if` ```(!BCRYPT_SUCCESS(BCryptGenRandom(Prov, (``` `PUCHAR` `) (&Buffer),` `                                      ` `sizeof` `(Buffer), 0))) {` `    ` `/* handle error */` `  ` `}` `  ` `printf` `(` `"Random number: %d\n"` `, Buffer);` `  ` ```BCryptCloseAlgorithmProvider(Prov, 0);``` `}`