I'm making a project in python and I would like to create a random number that is cryptographically secure, How can I do that? I have read online that the numbers generated by the regular randomizer are not cryptographically secure, and that the function os.urandom(n)
returns me a string, and not a number.

- 233,700
- 52
- 457
- 497

- 944
- 1
- 6
- 7
-
The answer you got is the right start, but you need to precisely define what you mean by "a number". A float? An integer? Signed or unsigned? What range? Etc. – Tim Peters Jan 05 '14 at 17:56
-
I have already gotten my anwer, but my intenton was and integer (should have mentioned that). is there any way to set a specific range in the suggestion that thefourtheye has made? – user2835118 Jan 05 '14 at 18:01
-
@TimPeters Can you please check if my updated answer will be okay? – thefourtheye Jan 05 '14 at 18:06
-
@thefourtheye, it's fine so far as it goes ;-) I added another answer suggesting an easier approach. – Tim Peters Jan 05 '14 at 18:16
-
5[There are no cryptographically secure random numbers](http://xkcd.com/221/), but a random number *generator* can be cryptographically secure. ;) – ntoskrnl Jan 05 '14 at 20:45
-
You can try https://docs.python.org/3/library/secrets.html#module-secrets I can elaborate in an answer if you like.. :-) – hola Jun 09 '17 at 09:15
5 Answers
Since you want to generate integers in some specific range, it's a lot easier to use the random.SystemRandom
class instead. Creating an instance of that class gives you an object that supports all the methods of the random
module, but using os.urandom()
under the covers. Examples:
>>> from random import SystemRandom
>>> cryptogen = SystemRandom()
>>> [cryptogen.randrange(3) for i in range(20)] # random ints in range(3)
[2, 2, 2, 2, 1, 2, 1, 2, 1, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0]
>>> [cryptogen.random() for i in range(3)] # random floats in [0., 1.)
[0.2710009745425236, 0.016722063038868695, 0.8207742461236148]
Etc. Using urandom()
directly, you have to invent your own algorithms for converting the random bytes it produces to the results you want. Don't do that ;-) SystemRandom
does it for you.
Note this part of the docs:
class random.SystemRandom([seed])
Class that uses the os.urandom() function for generating random numbers from sources provided by the operating system. Not available on all systems. Does not rely on software state and sequences are not reproducible. Accordingly, the seed() and jumpahead() methods have no effect and are ignored. The getstate() and setstate() methods raise NotImplementedError if called.

- 1
- 1

- 67,464
- 13
- 126
- 132
-
This is a very nice answer too, I think ill implement it (was going to fiddle around until I would get a range I wanted with the other answer). Are you sure it is cryptographiclly safe? – user2835118 Jan 05 '14 at 18:20
-
9@user2835118, it's exactly as secure - or insecure - as your operating system's implementation of `os.urandom`. Which means "as secure as the people who wrote your operating system knew how to make it". There are no absolute guarantees in life ;-) But for all practical purposes, yes, it would be astonishing if it weren't cryptographically secure based on all current knowledge. – Tim Peters Jan 05 '14 at 18:23
-
2@user2835118 You might want to go through this answer once http://security.stackexchange.com/a/3939/24680 – thefourtheye Jan 05 '14 at 18:27
-
1Though `base64.b64encode(os.urandom(32))` is a bit cleaner than `''.join(random.choice(b64chars) for i in range(43)` or `b64encode(bytes(random.randrange(256) for _ in range(32)))` or whatever other variant you want to use. – Nick T Oct 31 '15 at 02:57
-
-
You can get a list of random numbers by just applying ord
function over the bytes returned by os.urandom
, like this
>>> import os
>>> os.urandom(10)
'm\xd4\x94\x00x7\xbe\x04\xa2R'
>>> type(os.urandom(10))
<type 'str'>
>>> map(ord, os.urandom(10))
[65, 120, 218, 135, 66, 134, 141, 140, 178, 25]
Quoting os.urandom
documentation,
Return a string of
n
random bytes suitable for cryptographic use.This function returns random bytes from an OS-specific randomness source. The returned data should be unpredictable enough for cryptographic applications, though its exact quality depends on the OS implementation. On a UNIX-like system this will query
/dev/urandom
, and on Windows it will useCryptGenRandom()
.

- 1
- 1

- 233,700
- 52
- 457
- 497
-
3For those wondering whether `urandom` is truly suitable for cryptographic use, [apparently it is](http://security.stackexchange.com/questions/3936/is-a-rand-from-dev-urandom-secure-for-a-login-key). – Claudiu Apr 25 '16 at 16:10
-
if I only need one is it sufficient to change the argument to `os.urandom` to 1? i.e. `os.urandom(1)` – Charlie Parker Mar 25 '18 at 01:04
-
From Python 3.11, on Windows, os.urandom() now uses BCryptGenRandom(), instead of CryptGenRandom() which is deprecated – Ash Nazg Nov 09 '22 at 05:00
-
-
Python 3.6 introduces a new secrets module, which "provides access to the most secure source of randomness that your operating system provides." In order to generate some cryptographically secure numbers, you can call secrets.randbelow()
.
secrets.randbelow(n)
which will return a number between 0 and n
.

- 8,312
- 2
- 43
- 57
-
And it uses `random.SystemRandom` for this. So I don't really see the point of using it via this module. – BlackJack Jul 24 '19 at 11:43
-
7@BlackJack See the [rationale section of the PEP](https://www.python.org/dev/peps/pep-0506/#rationale) for the reasons the module was added. Apart from that, I would add that using the `secrets` module directly lets readers of your code know your intention, in a way that using `random.SystemRandom` directly doesn't. – Cody Piersall Jul 24 '19 at 14:33
If you want an n
-bit random number, under Python 2.4+, the easiest method I've found is
import random
random.SystemRandom().getrandbits(n)
Note that SystemRandom
uses os.urandom()
, so the result of this method is only as good as your system's urandom()
implementation.

- 4,462
- 1
- 30
- 23
To generate a cryptographically secure pseudorandom integer, you can use the following code:
int(binascii.hexlify(os.urandom(n)),16)
Where n
is an integer and, the larger n
is, the larger the integer generated is.
You will have to import os
and binascii
first.
The result of this code can vary by platform.

- 57
- 5