Safeguard
Application Security•

How do you get secure random numbers in C and C++?

Never use rand or a time-seeded generator for secrets. Ask the OS through getrandom, arc4random_buf or BCryptGenRandom, or use OpenSSL RAND_bytes.

Safeguard Security Team
5 min read

In C and C++, get secrets from the operating system's random generator: getrandom on Linux, arc4random_buf on BSD systems, BCryptGenRandom on Windows, or RAND_bytes from OpenSSL. Do not use rand, srand seeded with the clock, or other general purpose generators for keys, tokens or session identifiers.

Why is rand the wrong tool?

The Linux manual page for rand says it returns a pseudo-random integer, that srand sets a seed, and that sequences are repeatable by calling srand with the same seed. If no seed is provided, rand is automatically seeded with the value 1. The page also warns that on older implementations and some other systems the lower-order bits are much less random than the higher ones.

CERT's rule MSC30-C is blunt: the C Standard rand function makes no guarantees about the quality of the sequence, some implementations have a short cycle, and the numbers can be predictable. Its companion rule MSC32-C explains why seeding matters. A generator in the same initial state produces the same sequence in different runs, so after the first run an attacker can predict later sequences. That is how a program that seeds with the current time in seconds ends up with guessable tokens: the attacker only has to try a small range of start times.

What should you call instead?

Linux: getrandom. The manual says it fills a buffer with random bytes that can be used to seed user-space generators or for cryptographic purposes. By default it draws from the same source as /dev/urandom. It does not need file paths or descriptors, which helps in a chroot or after a library closes descriptors. Two cautions from the page: reads of up to 256 bytes are guaranteed to return in full when the source is initialised, but larger requests might return partial results or fail with EINTR, so check the return value and loop. And before the entropy pool is initialised it blocks unless told not to, which matters for early boot code.

BSD and others: arc4random_buf. The OpenBSD manual says this family gives higher quality data than rand, random and rand48 and is encouraged for almost all random number consumption. It reseeds from the kernel regularly and after fork. arc4random_uniform returns a value below an upper bound without modulo bias, which is better than taking the result modulo a number that is not a power of two. The functions are described as always successful.

Windows: BCryptGenRandom. Microsoft documents it as generating random numbers, with a flag to use the system preferred generator, and states the default provider follows NIST SP 800-90, specifically CTR_DRBG. Check the NTSTATUS return value.

Portable libraries: OpenSSL. RAND_bytes generates random bytes using a cryptographically secure pseudo random generator. RAND_priv_bytes is for values that should remain private and uses a separate private instance so that a compromise of the public one does not expose private values. Both return 1 on success, and you must check for 0 or -1.

A constructed example

A small server issues password reset tokens with srand(time(NULL)) at start and rand() for each character. An attacker requests a token, notes the server's start time to within a minute, and tries 60 seeds offline until one reproduces the observed token. Every other token from that process is now known. The fix is a few lines: read 16 bytes from the OS source, check the return value, and encode them as hex.

What does it take to review this?

Search the codebase for rand(, srand(, random(, drand48, rand_r and time(NULL) near seeding. Then ask of each hit: does the value protect anything? Nonces, salts, keys, tokens, IDs that gate access and shuffles in security checks all count. Game logic and test data do not.

Also handle failure. A random call that fails and leaves a zeroed buffer is worse than a crash. Make the failure path abort the operation.

What to do

  1. Inventory every use of a random function and classify it as security relevant or not.
  2. Replace security uses with the OS source or RAND_bytes.
  3. Use uniform helpers such as arc4random_uniform for ranges.
  4. Check every return value and treat failure as fatal for that operation.
  5. Never seed security-relevant generators from the clock or process ID.
  6. Wrap randomness in one small internal function so there is a single place to audit.
  7. Add a static analysis rule that flags rand in security code.
  8. Write a test that the function fails closed when the source is unavailable.

Safeguard's static scan can flag weak randomness in source, see the SAST code scan demo.

Quick check

Is random() safe for tokens?

No. CERT calls it a better generator than rand, but a general purpose generator is not designed for secrets. Use the OS source or a CSPRNG.

Why check the return value of getrandom?

Large requests can return fewer bytes than asked, or fail with EINTR. Using a partly filled buffer can weaken or zero a key.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.