Introduction
Do you know Python has a built-in module called secrets that can be used to generate cryptographically strong passwords, tokens, and other related secrets? The secrets module was first introduced in Python 3.6 (PEP 506).
Before the introduction of the secrets module into Python, the random module was used by the majority of developers for generating passwords, tokens, etc. But the random numbers generated by the random module are pseudo-random numbers and are not cryptographically secure. Hence, the secrets module was introduced into Python 3.6 onwards.
Secrets
The secrets module functions can be divided into two sections — generating random numbers and generating tokens.
Generating random numbers
1) secrets.choice(sequence) – returns a random element from a non-empty sequence. The below two examples returns a random character in the rage A-Za-z and a random number in the range 0–10.
>>> secrets.choice(seq=string.ascii_letters)
'B'
>>> secrets.choice(seq=range(10))
2
2) secrets.randbelow(n) — returns a random integer in the range 0-n (excluding n). The below example returns a random integer in the range 0–10.
>>> secrets.randbelow(exclusive_upper_bound=10)
5
3) secrets.randbits(k) — returns a random integer with k-bits. The below example return a random integer formed with 8-bits.
- If k=4 then the random integer will be from 0 to 15.
- if k=8 then the random integer will be from 0 to 255.
- If k=16 then the random integer will be from 0 to 65,535, and so on.
>>> secrets.randbits(k=8)
46
4) secrets.SystemRandom() — Each operating system comes up with a source to generate secure and strong random numbers. The SystemRandom is a class available in the random module which in turn uses os.urandom() function for generating the secure random numbers.
As highlighted earlier, before the introduction of the secrets module, SystemRandom class was used to generate secure and cryptographically strong random numbers/tokens. In fact, you can access all the random module functions/methods using the SystemRandom object.
As you can see from the below code, you are able to access random module functions using SystemRandom class. You can try other functions/methods available in the random module.
>>> import secrets
>>> sys_random = secrets.SystemRandom()
>>> sys_random.choice(seq=range(10))
6
>>> sys_random.getrandbits(k=8)
88
>>> sys_random.randrange(1, 100)
45
>>> sys_random.sample(range(100), 5)
[85, 73, 31, 88, 48]
Generating tokens
The secrets module also provides functions that can be used for applications such as password reset, hard-to-guess URLs, etc. as discussed below.
1) secrets.token_bytes —returns secure random byte strings with the bytes specified in nbytes parameter. If nbytes is None or not supplied, a reasonable default is used.
The below examples return 8 and 16 token bytes as specified in the parameter.
>>> secrets.token_bytes(8)
b'>k\t\xbcO\x8dg\xd6'
>>> secrets.token_bytes(16)
b'\xe81\xedT\xfcOP\xe9\x9e\x87\xa4\xec\xa0\xffH9'
2) secrets.token_hex — returns secure random byte strings in hexadecimal format with the bytes specified in nbytes parameter. If nbytes is None or not supplied, a reasonable default is used.
The below examples return 8 and 16 token bytes in hexa-decimal format as specified in the parameter.
>>> secrets.token_hex(8)
'796d446a4dcbe000'
>>> secrets.token_hex(16)
'6e8b324b58f0d94d5f6440b90c59d350'
3) secrets.token_urlsafe — returns a secure random URL-safe text string with the bytes specified in nbytes parameter.
The below examples return 8 and 16 bytes string as specified in the parameter.
>>> secrets.token_urlsafe(8)
'GLyhe4JD72g'
>>> secrets.token_urlsafe(16)
'kJkUOJIUZRAYkEgFR6X52w'
Examples
Based on the knowledge we gained from the above functions, we can now create cryptographically strong passwords, OTP, tokens, etc. Let’s look at a few use cases.
(1) Generate 8 character alpha-numeric password
>>> import string
>>> import secrets
>>> alphabet = string.ascii_letters + string.digits
>>> password = ''.join(secrets.choice(alphabet) for i in range(8))
>>> password
'ubHLOZY1'
(2) Generate 6 digit numeric OTP
>>> import string
>>> import secrets
>>> numbers = string.digits
>>> OTP = ''.join(secrets.choice(numbers) for i in range(8))
>>> OTP
'904447'
(3) Generate a 10-character password with at least one upper-case, one lower-case, one digit, one special character, and at least 5 alphabets.
>>> import string
>>> import secrets
>>> alphabet = string.ascii_letters + string.digits + string.punctuation
>>> while True:
... password = ''.join(secrets.choice(alphabet) for i in range(10))
... if (any(c.islower() for c in password)
... and any(c.isupper() for c in password)
... and any(c.islower() for c in password)
... and any(c.isdigit() for c in password)
... and any(c in string.punctuation for c in password)
... and sum(c.isalpha() for c in password) >= 5):
... break
>>> password
"hMyo>'A5<="
(4) Generate temporary URL secure token for password reset
Assume that you may have forgotten the password to a website. When you request for a password reset, after the authentication of user-id, email-id, or other authentication methods, you will be provided with a secure URL for a password reset. Below is the sample code using token_urlsafe().
>>> print("Password Reset link:")
>>> SecureURL = "https://mysite.com/user/chetanambi/passwordreset="
>>> SecureURL += secrets.token_urlsafe(32)
>>> print(SecureURL)
Password Reset link:
https://mysite.com/user/chetanambi/passwordreset=urtFK4CeJvJ0f7nVbPAAZw
PRNG Vs CSPRNG
PRNG stands for Pseudo-Random Number Generator and CSPRNG means Cryptographically Strong Pseudo-Random Number Generator.
The random numbers generated by any software are pseudo-random in nature as they come from some distribution and can be predicted if the seed is known. On other hand, truly random numbers use some external source that is unpredictable for random number generation. The CSPRNG in Python is a true random number generator as it uses OS as random number generator source.
Conclusion
In this article, you have been introduced to the Python secrets module. The secrets module is used to generate cryptographically strong and secure passwords, OTPs, tokens, and other related secrets. The random module in Python can also be used to generate random numbers but it is not secure. I hope that the above examples we discussed above will help you get started using the secrets module.