Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a predictable replacement for os.urandom using Python's random module?

I'm looking to get n random bytes as a bytearray or bytes, as os.urandom does.

However I need to be able to set a random seed so the value is reproducable.

def urandom_from_random(rng, length):
    return bytes([rng.randint(0, 255) for i in range(length)])

import random
rng = random.Random(42)
data = urandom_from_random(rng, 120)
print(data)

The script above works, but isn't very efficient.

Is there a more direct way to do this besides creating many ints and converting them to bytes?


Note:

  • Making urandom return predictable results is possible on Linux, but needs root access.
like image 446
ideasman42 Avatar asked May 20 '16 21:05

ideasman42


People also ask

What is OS urandom in Python?

os. urandom() method is used to generate a string of size random bytes suitable for cryptographic use or we can say this method generates a string containing random characters. Syntax: os.urandom(size) Parameter: size: It is the size of string random bytes.

What is the use of random seed in Python?

Python Random seed() Method The seed() method is used to initialize the random number generator. The random number generator needs a number to start with (a seed value), to be able to generate a random number. By default the random number generator uses the current system time.

How secure is OS urandom?

/dev/urandom is widely considered safe for all cryptographic purposes, except by the most paranoid people."

What does urandom do?

The /dev/urandom device provides a reliable source of random output, however the output will not be generated from an equal amount of random input if insufficient input is available. Reads from the /dev/urandom device always return the quantity of output requested without blocking.

How random is random Python?

Most random data generated with Python is not fully random in the scientific sense of the word. Rather, it is pseudorandom: generated with a pseudorandom number generator (PRNG), which is essentially any algorithm for generating seemingly random but still reproducible data.


2 Answers

I think the closest function in random to what you want is getrandbits. It returns an integer with the requested number of bits. If you want to turn that into a bytes instance, you can use int.to_bytes.

Here's a quick function that pairs those two together:

def urandom_from_random(rng, length):
    if length == 0:
        return b''
    integer = rng.getrandbits(length * 8)
    result = integer.to_bytes(length, sys.byteorder)
    return result

The byte order you specify to to_bytes shouldn't matter. I tell it to use the system's native byte order, but I don't actually know if that makes it any faster than it would be otherwise.

like image 148
Blckknght Avatar answered Sep 21 '22 13:09

Blckknght


This is a modified version of @Blckknght's answer that takes into account the internal INT_MAX limit in getrandbits.

def urandom_from_random(rng, length):
    if length == 0:
        return b''

    import sys
    chunk_size = 65535
    chunks = []
    while length >= chunk_size:
        chunks.append(rng.getrandbits(
                chunk_size * 8).to_bytes(chunk_size, sys.byteorder))
        length -= chunk_size
    if length:
        chunks.append(rng.getrandbits(
                length * 8).to_bytes(length, sys.byteorder))
    result = b''.join(chunks)
    return result

Example use:

import random 
rng = random.Random(42)
print(len(urandom_from_random(rng, 300000000)))
like image 38
ideasman42 Avatar answered Sep 21 '22 13:09

ideasman42