OWASP category: MASVS-CRYPTO: Cryptography
Overview
A pseudorandom number generator (PRNG) is an algorithm that generates predictable number sequences based on a starting value called a seed. A PRNG-generated number sequence has approximately the same properties as a truly random number sequence, but is faster and less computationally expensive to create.
In other words, PRNGs have higher assurances than weak RNGs (e.g.
java.math.Random
) in terms of evenness of entropy distribution, which emulate
truly random number sequences. Truly random number generation requires
specialized equipment and is often outside the scope of normal development. This
document does not cover truly random number generation, and focuses only on
PRNGs as they are the standard methodology in use.
Weak PRNG vulnerabilities occur when developers use a regular PRNG for cryptographic purposes, instead of a cryptographically-secure PRNG (CSPRNG). CSPRNGs have stricter requirements, and when the seed is unknown, they must give an attacker only an insignificant advantage in differentiating an output sequence from an actual random sequence.
Attackers may also be able to guess the generated number sequence when predictable seeds – such as those hard coded by the developer – are used to initialize a PRNG or CSPRNG, as the attacker can guess the seed and thus predict the output generated by the PRNG.
Impact
If a non-cryptographically secure PRNG is used in a security context like authentication, an attacker may be able to guess the randomly-generated numbers and gain access to privileged data or features.
Mitigations
General
- Use
java.security.SecureRandom
when there are security implications - Use
java.util.Random
for any other cases - Never use
Math.random
!
java.security.SecureRandom
Recommended for security uses. If the Linux kernel version is 5.17+ or
blocking the thread is acceptable, wait for enough entropy to accumulate before
you generate the random numbers (i.e. use /dev/random
). To do so, call
getInstanceStrong()
:
Kotlin
val rand = SecureRandom.getInstanceStrong()
Java
SecureRandom rand = SecureRandom.getInstanceStrong();
Otherwise, on Linux kernel versions prior to 5.17 when blocking the thread is
unacceptable when generating random numbers, then the SecureRandom
constructor
should be called directly:
Kotlin
import java.security.SecureRandom
object generateRandom {
@JvmStatic
fun main(args: Array<String>) {
// Create instance of SecureRandom class
val rand = SecureRandom()
// Generate random integers in range 0 to 999
val rand_int = rand.nextInt(1000)
// Use rand_int for security & authentication
}
}
Java
import java.security.SecureRandom;
public class generateRandom {
public static void main(String args[])
{
// Create instance of SecureRandom class
SecureRandom rand = new SecureRandom();
// Generate random integers in range 0 to 999
int rand_int = rand.nextInt(1000);
// Use rand_int for security & authentication
}
}
SecureRandom
gets the default seed from /dev/urandom
, and is automatically
used when the object is constructed or obtained, so there is no need to
explicitly seed the PRNG. In general, any deterministic usage of SecureRandom
is discouraged (especially if this leads to hard coding a seed value, which
anyone decompiling the app can see). Developers who want to generate
reproducible pseudorandom output should use more appropriate primitives such as
HMAC, HKDF, and SHAKE.
java.util.Random
Avoid for security / authentication purposes, acceptable to use for anything else.
Kotlin
import java.util.Random
object generateRandom {
@JvmStatic
fun main(args: Array<String>) {
// Create instance of SecureRandom class
val rand = Random()
// Generate random integers in range 0 to 999
val rand_int = rand.nextInt(1000)
}
}
Java
import java.util.Random;
public class generateRandom {
public static void main(String args[])
{
// Create instance of Random class
Random rand = new Random();
// Generate random integers in range 0 to 999
int rand_int = rand.nextInt(1000);
}
}
Resources
- java.security.SecureRandom
- java.util.Random
- Math.random
- Predictable Seed CWE
- Cryptographically Weak PRNG CWE
- Java Secure Random
- Java Random versus SecureRandom
- How to use SecureRandom
- Python PRNG security guidance
- OWASP Cryptographic Storage Cheat Sheet
- CVE-2013-6386: Weak PRNG vuln in Drupal
- CVE-2006-3419: Weak PRNG vuln in Tor
- CVE-2008-4102: Predictable Seed in Joomla
- Linux Kernel random patch