2

I know that PHP used the system implementation for its rand() function, which is usually a weak LCG or LFSR implementation. Did this change? In case it still does, I am using Fedora 32.

PHP states in its documentation that rand() does not create cryptographically secure values.

I've written a small script, that creates a 400x400px PNG by randomly coloring pixels black or white:

<?php

$resolution = 400;

header("Content-type: image/png");
$im = imagecreatetruecolor($resolution, $resolution)
    or die("Cannot Initialize new GD image stream");

$white = imagecolorallocate($im, 255,255,255);

for ($y = 0; $y < $resolution; $y++) {
    for ($x = 0; $x < $resolution; $x++) {
        if (rand(0, 1)) {
            imagesetpixel($im, $x, $y, $white);
        }
    }
}
imagepng($im);
imagedestroy($im);

?>

I cannot see patterns anymore when using the function in PHP7.3 though. May there be patterns at a level I cannot display in my experiment?

rand():

enter image description here
random_int(),

for use where unbiased results are critical

according to PHP's docs

enter image description here

2
  • 3
    To point out succinctly: An RNG can provide perfect statistical randomness while providing no cryptographic security at all.
    – Xander
    Commented Jun 11, 2020 at 15:11
  • The image doesn't need to reveal any pattern and even it shows a pattern than the rand() is a very bad random number generator. The only obvious pattern should occur when the width of the image equal to is period.
    – kelalaka
    Commented Jun 11, 2020 at 19:07

1 Answer 1

10

If you can't see obvious patterns, that does not make it cryptographically secure! See also my answer to this question on our sibling site: What does it mean for a random number generator to be cryptographically secure?

At the risk of stating the obvious, rand() and mt_rand() are NOT SECURE for security purposes. Do NOT use them for things like shuffling a deck of virtual cards in games where there is (virtual) money at stake, generating security tokens, or any such thing. Such random functions are meant for fast randomness where security does not matter. Common applications for insecure randomness are simulations and games (the game AI repeating itself in 1 out of every 2 billion games is fine, but a secret key repeating itself 1 in every 2 billion keys can be crackable in a reasonable amount of time).

By coincidence I was looking at this 2 hours ago as well, since I was curious if they had finally aliased rand() to use mt_rand() instead, since mt_rand has been both faster and better since its introduction many years ago, but this does not appear to be the case. Therefore:

  • To generate insecure, fast random: $n = mt_rand(0, 10); generates a number from 0 through 10 (inclusive) (docs)
  • To generate secure random data: $data = random_bytes(32); generates 32 bytes of random data (docs)
  • To generate a secure random number: $n = random_int(0, 10); generates a number from 0 through 10 (inclusive) (docs)
    Note that this only goes up to PHP_INT_MAX, which is at most approximately 264, so too small as a security key by itself. Use random_bytes() for generating secret keys, security tokens, etc. This function may aid in generating an unpredictable number, like for shuffling a deck of cards, where you may need a random number ≤52 instead of random bytes.
8
  • 1
    don't use random_int(lower,upper) to get randomness for cryptographic applications - on all relevant platforms, the underlying randomness is always defined on powers of two (byte-wise, in fact, usually), and doing a modulo on doesn't yield a uniform distribution. The random_int function is hence broken by design (if you recognize that as a PHP design pattern: not surprisingly.).You want random_bytes, or an openssl_ function. Commented Jun 11, 2020 at 14:30
  • 1
    @MarcusMüller Wait what? Can you provide a reference for that, like source code or a bug ticket or anything? Because that sounds like a super beginner's mistake to do modulo on raw bytes (see the first link in my post, I even gave that as example).
    – Luc
    Commented Jun 11, 2020 at 16:53
  • 1
    Not that I don't believe you per se, but it would be good to get that fixed so a reference would be helpful to pinpoint the issue.
    – Luc
    Commented Jun 11, 2020 at 17:47
  • 1
    you're right, just modulo would be dangerous, and I'm relieved to say the PHP code is not as I remembered it. They simply draw random numbers, then restrict the range to be a multiple of the range, and then do the modulo operation: github.com/php/php-src/blob/master/ext/standard/random.c#L257 Commented Jun 11, 2020 at 17:53
  • 1
    @MarcusMüller Thanks for getting back on that! Overdrawing randomness (within bounds) is not really a bug to me since I don't subscribe to the entropy disappearance theory ("entropy_avail"), so I'm happy to hear the answer didn't include insecure advice after all :)
    – Luc
    Commented Jun 11, 2020 at 22:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .