Randomness in PHP-do you feel lucky? This article analyzes the issues related to generating random numbers for encryption. PHP 5 does not provide a simple mechanism to generate strong random numbers in cryptography, but PHP 7 solves this problem by introducing several CSPRNG functions.
What is CSPRNG?
Reference Wikipedia, a cryptology Secure pseudo-random Number Generator (Cryptographically Secure udorandom Number Generator abbreviated to CSPRNG) is a pseudo-random Number Generator (PRNG), and its pseudo-random Number generation is suitable for cryptographic algorithms.
CSPRNG may be mainly used:
A key aspect of achieving high-level security is high quality randomness.
CSPRNG in PHP 7
PHP 7 introduces two new functions that can be used to implement CSPRNG: random_bytes and random_int.
The random_bytes function returns a string that accepts an int input parameter representing the number of bytes of the returned result.
Example:
$bytes = random_bytes('10'); var_dump(bin2hex($bytes)); //possible ouput: string(20) "7dfab0af960d359388e6"
The random_int function returns an int-type number in the specified range.
Example:
var_dump(random_int(1, 100)); //possible output: 27
The randomness of the functions in the background running environment varies depending on the environment:
-
In Windows, CryptGenRandom () is always used.
-
On other platforms, arc4random_buf () will be used if available (established on BSD series or systems with libbsd)
-
If none of the above is true, a linux system call getrandom (2) will be used.
-
If not,/dev/urandom will be used as the last available tool.
-
If none of the above works, the system will throw an error.
A simple test
A good random number generation system ensures proper quality ". To check the quality, a series of statistical tests are usually executed. You do not need to study complex statistical topics in depth. comparing the results of a known behavior and a digital generator can help you evaluate the quality.
A simple test is a dice game. Assume that the probability of throwing a dice once is 1/6, if I throw three dice 100 times at the same time, the result is roughly as follows:
-
0, 6 = 57.9 times
-
1x6 = 34.7 times
-
2 6 = 6.9 times
-
3 6 = 0.5 times
The following code is used to roll the dice 1,000,000 times:
$times = 1000000; $result = []; for ($i=0; $i<$times; $i++){ $dieRoll = array(6 => 0); //initializes just the six counting to zero $dieRoll[roll()] += 1; //first die $dieRoll[roll()] += 1; //second die $dieRoll[roll()] += 1; //third die $result[$dieRoll[6]] += 1; //counts the sixes } function roll(){ return random_int(1,6); } var_dump($result);
The following results may be obtained by using the random_int and simple rand functions of PHP7:
Sixes |
Expected |
Random_int |
0 |
579000 |
579430 |
1 |
347000 |
346927 |
2 |
69000 |
68985 |
3 |
5000 |
4658 |
If we see a better comparison between rand and random_int, we can apply a formula to draw the result on the graph. The formula is: (php result-expected result)/0.5 to the power of the expected result.
The result is as follows:
(The value close to 0 is better)
Although the results of the three 6 s are not performing well, and this test is too simple for practical applications, we can still see that random_int is superior to rand.
Furthermore, the security level of our applications is enhanced by unpredictability and repetitive behavior of random number generators.
What about PHP5?
By default, PHP5 does not provide a strong random number generator. In fact, there are still some options, such as openssl_random_pseudo do_bytes (), mcrypt_create_iv (), or use the fread () function directly to use the/dev/random or/dev/urandom device. There are also some packages such as RandomLib or libsodium.
If you want to start using a better random number generator and are ready to use PHP7, you can use the Paragon Initiative random ISES random_compat Library. The random_compat Library allows you to use random_bytes () and random_int () in PHP 5.x project ()
This library can be installed through Composer:
composer require paragonie/random_compat require 'vendor/autoload.php'; $string = random_bytes(32); var_dump(bin2hex($string)); // string(64) "8757a27ce421b3b9363b7825104f8bc8cf27c4c3036573e5f0d4a91ad2aaec6f" $int = random_int(0,255); var_dump($int); // int(81)
The random_compat library and PHP7 use different sequence:
fread() /dev/urandom if available mcrypt_create_iv($bytes, MCRYPT_CREATE_IV) COM('CAPICOM.Utilities.1')->GetRandom() openssl_random_pseudo_bytes()
For more information, see documentation.
A simple application of this library is used to generate a password:
$passwordChar = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $passwordLength = 8; $max = strlen($passwordChar) - 1; $password = ''; for ($i = 0; $i < $passwordLength; ++$i) { $password .= $passwordChar[random_int(0, $max)]; } echo $password; //possible output: 7rgG8GHu
Summary
You should always use a cryptographic pseudo-random number generator. the random_compat Library provides a good implementation.
If you want to use a reliable random data source, we recommend that you use random_int and random_bytes as soon as possible.
Http://www.codeceo.com/article/php-random.html.
Randomness in PHP-Do You Feel Lucky?