In this lesson, I will tell you how to generate a cryptographically secure random number in Python. Random numbers and data generated by the random class are not cryptographically protected. An output of all random module functions is not cryptographically secure, whether it is used to create a random number or pick random elements from a sequence.
What is cryptographically secure pseudo-random number generator?
A cryptographically secure pseudo-random number generator is a random number generator that generates the random number or data using synchronization methods so that no two processes can obtain the same random number simultaneously.
Also, see: –
A secure random generator is useful in cryptography applications where data security is essential. Most cryptographic applications require safe random numbers and String. For example, key and secrets generation, nonces, OTP, Passwords, PINs, secure tokens, and URLs.
In this lesson, you’ll learn the following ways to cryptographically secure random number generators in Python
- The
os.urandom()
method - The
random.SystemRandom
class - Python 3.6’s Secrets module to secure random data
Table of contents
os.urandom()
function
The os.urandom()
returns a string of size random bytes suitable for cryptographic use.
It can returns a string and random bytes. Random bytes returned by this function depend on the underlying operating system’s random data source (OS.randoms
). The quality of randomness is different for each operating system.
- On Windows,
os.urandom()
internally uses CryptGenRandom() - Linux 3.17 and newer, the
getrandom()
syscall is used when available. On OpenBSD 5.6 and newer, the Cgetentropy()
function is used.
The data returned by the os.urandom()
is enough for cryptographic applications.
Example
import os
data = os.urandom(5)
print("secure data from os.urandom ", data)
# Output b'\n4.F\x08'
The os.urandom()
generates a string of random bytes. Use the struct module to convert bytes into the format you want such as integer, float or string.
- The
struct.unpack(format, buffer)
method is used to convert bytes into the format you want – for example,i
for integer, andf
for float. - A buffer is the source of bytes. In our case, it is
os.urandom()
.
Note: the struct.unpack(format, buffer)
returns the result in tuple format.
Let see the example to convert os.urandom()
to string, integer, and float.
import os
import struct
# random integer using os.urandom()
print(struct.unpack('i', os.urandom(4)))
# Output (258871565,)
# unsigned random integer using os.urandom()
print(struct.unpack('I', os.urandom(4)))
print(struct.unpack('I', os.urandom(4))[0] % 100)
# Output (1015967885,)
# random short number using os.urandom()
print(struct.unpack('h', os.urandom(2)))
# Output (-28882,)
# unsigned random short using os.urandom()
print(struct.unpack('H', os.urandom(2)))
# Output (29492,)
# Print random float using os.urandom()
print(struct.unpack('f', os.urandom(4)))
# Output (-4.651611836498911e+20,)
# un-singed random decimal using os.urandom()
print(struct.unpack('d', os.urandom(8)))
# Output (-1.7024488468332834e-120,)
# random char using os.urandom()
print(struct.unpack('c', os.urandom(1)))
# Output (b'\xce',)
Use SystemRandom class to cryptographically secure the random generator
Instead of doing the conversion on your own, you can directly use random.SystemRandom
class. The SystemRandom
class internally uses os.urandom()
function to provide the secure random numbers.
SystemRandom class internally uses the os.urandom()
function for generating random numbers from sources provided by the operating system.
Use the random module to get this class. Use random.SystemRandom()
function to get the instance of SystemRandom
class. Using this instance, you can call all random module functions to secure your random data.
Syntax of SystemRandom
class
random.SystemRandom([seed])
- The
seed()
method has no effect and is ignored. - The
random.getState()
andrandom.setState()
function is not available under this class and raisesNotImplementedError
if called.
Examples
Let see how to use random.SystemRandom
to generate cryptographically secure random numbers.
Let’s see the example to secure the output of the functions of the random module such as random()
, randint()
, randrange()
, choice
, sample()
, uniform()
.
import random
# getting systemRandom instance out of random class
system_random = random.SystemRandom()
# Secure random number
print(system_random.randint(1, 30))
# Output 22
# Secure random number within a range
print(system_random.randrange(50, 100))
# Output 59
# secure random choice
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(system_random.choice(list1))
# Output 9
# secure random sample
print(system_random.sample(list1, 3))
# Output [1, 4, 9]
# secure random float
print(system_random.uniform(5.5, 25.5))
# Output 18.666415244982193
Secrets module to secure random data
Python 3.6 introduced a new module called secrets for generating a reliable, secure random number, URLs, and tokens.
Refer to our complete guide on Secrets Module to explore this module in detail.
Example
import secrets
print("Random integer number generated using secrets module is ")
number = secrets.randbelow(30)
print(number) # 27
number = secrets.randbelow(30)
print(number) # 20
Next Steps
Try to solve the following exercise and quiz to have a better understanding of working with random data in Python.
- Python random data generation Exercise to practice and master the random data generation techniques in Python.
- Python random data generation Quiz to test your random data generation concepts.