I want to strike up a discussion about generating random numbers in PHP, or should I say "with PHP". First of all, I will tell somethings that I know and one thing to be told is that the random number generation provided by PHP is not so "random". This applies to both rand() and mt_rand(). Both of these algorithms are seeded by a single 32-bit dword when they are first used in a process or one of the seeding functions srand() or mt_srand() is called. These random number generators are not enough for cryptographic usage. These 32-bit seeds have to be guessed and the amount of previously generated random numbers too in order to exploit their weaknesses. These functions seem fairly enough to protect from brute forcing, as the brute forcer has to spend its whole life on it.
Let's discuss more about weak seading first.
I often see something like this being used in scripts:
Code: Select all
mt_srand((double)microtime()*1000000);Because of weak seedings, not-so-truly randoms, problems with PHP's internal seedings, ... we have to find another way to do it.
Method #1
Code: Select all
if (($handle = @fopen('/dev/urandom','rb'))) // Remember to put parenthesis around the clause, so we assign the boolean success into our if statement :)
{
$rand = fread($handle,8); // 8 is just an example that we might want to use, type 64 for to get 512 bits strong random
fclose($handle);
}Method #2
Code: Select all
if (($handle = @fopen('/dev/random','rb')))
{
$rand = fread($handle,8);
fclose($handle);
}What other methods would you might use for generating random numbers?
I've been thinking about these:
Code: Select all
/usr/local/apache2/conf/rand.dat
/dev/egd-pool
/usr/local/ssl/bin/opensslAnother way of generating more random numbers without relying on these outside resources is to make a seeding system that is different from all other scripts even if they are on the same server. The following demonstration example is thanks to Stefan Esser.
Code: Select all
function rand2($min = 0,$max = 0)
{
global $rnd_value,$gseed;
$seed = $gseed;
// Reset $rnd_value after 14 uses
// 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
if ( strlen($rnd_value) < 8 ) {
$rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
$rnd_value .= sha1($rnd_value);
$rnd_value .= sha1($rnd_value . $seed);
$seed = md5($seed . $rnd_value);
$gseed = $seed;
}
// Take the first 8 digits for our value
$value = substr($rnd_value, 0, 8);
// Strip the first eight, leaving the remainder for the next call to rand2().
$rnd_value = substr($rnd_value, 8);
$value = abs(hexdec($value));
// Reduce the value to be within the min - max range
// 4294967295 = 0xffffffff = max random number
if ( $max != 0 )
$value = $min + (($max - $min + 1) * ($value / (4294967295 + 1)));
return abs(intval($value));
}So now I have said what I have been thinking, now it's your time to shed some light on us about what you know and possibly fix/improve my sentences or grammatic errors