0

I want to study the behavior of the Windows pseudorandom number generator.

I can get a single random integer between 0 and 2^15 like this:

from subprocess import check_output
check_output('echo %random%', shell=True)

yields

b'28174\r\n'

But when I try to put this command in a list comprehension, it only sends the command to the OS once:

from subprocess import check_output
def rwin(n):
    return [int(check_output('echo %random%', shell=True)[:-2]) for i in range(n)]
rwin(12)

yields

[27511,
 27511,
 27514,
 27514,
 27514,
 27514,
 27514,
 27514,
 27514,
 27514,
 27514,
 27514]

I would like 12 different random numbers instead. My setup info is Python 3.7.4 (default, Aug 9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)].


The answers to similar questions have suggested workarounds (e.g. using the time module instead of subprocess), which won't work for me as my goal is to interface directly with Windows's PRNG.

Max
  • 695
  • 5
  • 18
  • 2
    Because of [this](https://devblogs.microsoft.com/oldnewthing/20100617-00/?p=13673). – Selcuk Mar 02 '20 at 06:35
  • Try adding 1 sec sleep in the loop. Maybe you are generating too many numbers at same system time. Not 100% sure though – SubhashR Mar 02 '20 at 06:36
  • @SubhashR this works, thank you. It's still impractical for large n, however. – Max Mar 02 '20 at 06:40
  • Reduce the sleep to 10 milliseconds, still won't be very practical but gets the work done – SubhashR Mar 02 '20 at 06:44
  • @SubhashR Actually, it looks like you have to have the sleep at 1 sec because Windows uses the time in seconds to seed its RNG. If you sleep for .5 seconds you get numbers in pairs. However, combining 1 sec of sleep with the crude approach I put in my answer (use `check_output('echo'+' %random%'*900, shell=True)` for 900 random integers at a time) is workable at my scale. – Max Mar 02 '20 at 07:07
  • But… why not use the `random` module from python? – LtWorf Mar 02 '20 at 07:08
  • @LtWorf My end goal is to compare the Python RNG to the one built into Windows – Max Mar 02 '20 at 07:09
  • 1
    @Max you're not really comparing Python's RNG to "the one built into Windows" here, you're specifically looking at cmd's `%RANDOM%` which is quite obviously garbage. You can access the Windows CSPRNG (`CryptGenRandom`) from Python using [`os.urandom`](https://docs.python.org/3/library/os.html#os.urandom), or [`random.SystemRandom`](https://docs.python.org/3/library/random.html#random.SystemRandom) for a higher-level interface to the same generator. – Masklinn Mar 02 '20 at 07:21
  • @Masklinn cmd's random is actually looking OK on the attractor plots (http://lcamtuf.coredump.cx/oldtcp/tcpseq.html) I've been making. Thanks for the tip, anyhow. – Max Mar 02 '20 at 07:23
  • @Max I don't see the relation between your link and cmd. Your link is about TCP ISNs, that has no reason to shell out to cmd (indeed it really should not as cmd generates 16 bit random numbers while the ISN is 32 bits). – Masklinn Mar 02 '20 at 07:50
  • @Masklinn The link is simply provided as an explanation of how the attractor plots are generated. The same methodology can be used to study any PRNG. – Max Mar 02 '20 at 07:53

1 Answers1

0

A very crude workaround is

def rwin(n):
    return [int(i) for i in check_output('echo'+' %random%'*n, shell=True)[:-2].split()]

Unsurprisingly, this doesn't work for large n.

Max
  • 695
  • 5
  • 18