3

I need to create random integers between the values of 0 and 10,000,000, and I will need several million such numbers. The numbers must be as close to a CSPRNG as possible in that should (for example) someone get to read, so 1 million out of 2 million such numbers that they would find it impracticable to work out the remaining 1 million numbers.

After some research I’ve come to the conclusion that with the tools I have available, (Unix/PHP) using /dev/urandom will be my best bet.

I came across this solution:

// equiv to rand, mt_rand
// returns int in *closed* interval [$min,$max]
function devurandom_rand($min = 0, $max = 0x7FFFFFFF) {
    $diff = $max - $min;
        if ($diff < 0 || $diff > 0x7FFFFFFF) {
     throw new RuntimeException("Bad range");
        }
        $bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
    if ($bytes === false || strlen($bytes) != 4) {
        throw new RuntimeException("Unable to get 4 bytes");
    }
    $ary = unpack("Nint", $bytes);
    $val = $ary['int'] & 0x7FFFFFFF;   // 32-bit safe
    $fp = (float) $val / 2147483647.0; // convert to [0,1]
    return round($fp * $diff) + $min;
}

Source: https://codeascraft.com/2012/07/19/better-random-numbers-in-php-using-devurandom/

Given that I need to create a large amount of random numbers, would I be better piping /dev/urandom to a file(s), and then read 3 bytes (2^24 = 16 million) at a time and convert to integer?

Is either solution suitable for my needs?

Paul
  • 51
  • 1
  • 5

1 Answers1

3

When PHP 7 comes out, it has a new function called random_int() that serves this purpose.

If you need this today (i.e. in a PHP 5 project), check out random_compat.

At the very least, look at how random_int() is implemented in random_compat. Among other reasons, it still works for ranges larger than PHP_INT_MAX. (Yes, it uses /dev/urandom.)

Demo: http://3v4l.org/VJGCb

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
  • 1
    many thanks and good to see I was on the right track re /dev/urandom - one of the links in your code was already in my bookmarks (http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers). I did know about random_int() but still using PHP5 and do need it today. I will use random_compat - it is able to produce 10M numbers in 250 seconds and on my server it uses the `$fp = fopen('/dev/urandom', 'rb')` source. Will the 'quality' of the randomness suffer from calling random_int() so many times in a simple for loop? – Paul Aug 05 '15 at 12:52
  • I don't buy the Linux man page superstition about running out of entropy. It should be fine – Scott Arciszewski Aug 05 '15 at 12:59
  • 1
    Thanks Scott - I'm on freeBSD I assume that will be OK too? PS tried to upvote your answer but will not allow me. – Paul Aug 05 '15 at 13:10
  • Yeah if anything FreeBSD is saner than Linux in this regard. I mean, their TCP/IP stack keeps being a source of vulnerabilities, but damn if they don't make better decisions with randomness. – Scott Arciszewski Aug 05 '15 at 13:17
  • Thanks again - if I may ask one last (probably stupid) question - I've read /dev/urandom gets its entropy from such things as electrical noise from the hard drive, network card etc. I'll be running this from my server in the office and it's just me in the office, so it get very little work to do. Would there be any benefit/need to give the server some work to do (such as optimize some databases, copy some large files etc) to create reserves of entropy? – Paul Aug 05 '15 at 13:58
  • 1
    @Paul urandom (being a good csprng as far as known today) will not *run out of entropy*. That is, with sufficient amount of entropy once collected even without acquiring any new it will not allow to infer internal state from almost any amount of output (or rather, to do that it will require attacker to enumerate more possible internal states then he can in any reasonable (think millennia) amount of time). – Cthulhu Aug 14 '15 at 14:08