CSPRNG: Random algorithms need security too!
February 9, 2023
0 mins readIf I throw a coin high up in the air, I know the outcome — it will either be heads or tails. However, I can’t predict which it will be. I will certainly be able to guess with a 50% chance, but I can’t be 100% certain. If I were to roll a die, my certainty becomes less (1 in 6). However, I still know what the output could be.
Computers are great at many things, especially predictability. They are deterministic and creating a truly random number is impossible. However, we can use functions to create approximate randomness. These functions are called pseudo-random number generators.
Let’s take a look at a little bit of code:
1import random
2
3# Generate a random integer between 0 and 10
4random_number = random.randint(0, 10)
5
6print(random_number)
This code will generate a random number from 0 to 10 (this includes both 0 and 10 as potential results). It’s similar to the coin toss and die throw earlier. We know what the outcome potentially could be, we just can’t accurately predict it.
When dealing with cryptography, we want the predictability aspect to be zero. This is to say we don’t want to ever be able to predict what the outcome will be. For example, let’s say we are going to generate a “random” token for a password reset. We can use the current time to generate a hash value. When this is displayed in the URL for a password reset, it will look random. But in fact, it’s predictable. And a hacker may take advantage of this, especially if the code is open source and available to view.
1import hashlib
2import time
3
4t = time.localtime()
5current_time = time.strftime("%H:%M:%S", t)
6
7MD5_hash = hashlib.md5(current_time.encode())
8
9print(MD5_hash.hexdigest())
Randomness is a topic that varies from field to field. In some cases, like at a casino, spinning the roulette wheel is random, even though statistically there is a 2.6% chance that the result could be “predicted.” With cryptography, this is not good enough!
Pseudo-random isn't secure
We looked at pseudo-random number generators (PRNG) above, but we need something better. In order for a random number to be secure for cryptographic purposes, it must be unpredictable, non-repeating, and free of patterns. We want to use cryptographically-secure pseudo-random number generators (CSPRNG).
A CSPRNG is a type of random number generator that is specifically designed to be secure for cryptographic applications. These generators are designed to produce a sequence of random numbers that is difficult to predict or reproduce, even with knowledge of the algorithm and the seed value used to initialize the generator. That is to say, it needs to be unpredictable. Not only that, but a CSPRNG should be able to produce a large amount of random numbers without any repeating or discernible patterns in the sequence of numbers.
CSPRNGs are used in a variety of cryptographic applications such as key generation, password hashing, and encryption. They are also used in non-cryptographic applications such as generating unique IDs, tokens, and session keys.
CSPRNG and entropy
How do we get the CS in CSPRNG? It comes down to entropy.
Entropy is the measure of the randomness or uncertainty in a source of data. It’s a vital part of a CSPRNG. Entropy pools are sources of random data that are used to seed CSPRNGs and periodically reseed them to ensure that the generated numbers remain unpredictable.
There are different types of entropy pools that CSPRNGs can pull from, and the specific implementation of a CSPRNG can determine which entropy pools it uses. There are hardware random number generators (HRNGs), which are physical devices that use various sources of randomness such as electronic noise, radioactive decay, or atmospheric noise to generate random numbers. They are considered to be a good source of entropy because the physical processes used to generate the numbers are difficult to predict or reproduce.
Some operating systems provide a source of entropy that can be used to seed CSPRNGs. For example, the /dev/random
or /dev/urandom
files on Linux and UNIX-like systems, and BCryptGenRandom()
on Windows. If you are using Python, you can use os.urandom()
to return random bytes using your OS-specific randomness source.
CSPRNGs can also gather entropy from various environmental sources, such as network traffic, mouse movements, or keyboard input. These sources can be unpredictable and can provide a good source of entropy. You can even go a step further, like CloudFlare, and use lava lamps!
CSPRNG example
Sticking with Python, here is an example of generating a URL-safe token:
1import secrets
2
3print (secrets.token_urlsafe(16))
This will generate a cryptographically secure pseudo-random number. We can use this for a variety of reasons, such as generating a password reset token. This token then goes into the URL and might look something like this: https://supersecurereset.io/forgot-password?token=3PDhWtzkTo9QGAq6mvLxYA
Learn more about randomness and security
Insecure randomness and password recovery are just one small part of computer security. A lot goes into creating a secure environment and application. We don’t expect anyone to know everything which is why we have Snyk Learn.
Snyk Learn is a great learning tool with content from security experts. And the best part is it’s free. Actually free. Not a demo — and certainly no limits on how many lessons you can take.
To learn more about randomness and password recovery methods, check out these two lessons:
Improve your secure coding skills
Free, high quality developer security education when and where you want it.