Generate random random string in PHP

5

How to use the PHP language to generate a string, preferably with configurable size, random enough to be used in routines that handle encryption and that for security reasons can not be not too random?

If you propose more than one solution, preferably specify which one you think is most random, possibly with additional external references . Solutions that involve more than one source of randomness are also welcome, especially if accompanied by an explanation of advantages, such as reducing problems with an operating system explicitly altered by a NSA of life to generate less chaos when it comes to producing randomness .

Even if two people propose the same code, if one of these explains better or proves with real examples the dispersion of values, it will be considered as the best answer. Do not just copy and paste code, you should give it a try because it's a good solution.

Solutions that directly access an operating system resource, for example using shell_exec , although not desirable, are also welcome with an explanation of what context would be advantageous, such as older versions of PHP or not having a specific PHP module that would allow you to use a more appropriate routine.

    
asked by anonymous 15.02.2014 / 20:20

4 answers

5

When it comes to encryption / security issues, it's best to use the same tools.

An example in PHP is openssl_random_pseudo_bytes , a function that was made to generate random numbers (with a configurable number of bytes).

$bytes = openssl_random_pseudo_bytes($length, $strong);
if (!$strong) {
    //Tratar o erro
    exit();
}
$hex = bin2hex($bytes);

This library is not always available, which can be problematic.

On Linux, /dev/random is a special "file" that allows you to extract random bytes. The /dev/urandom is very similar to the /dev/random , although they have slightly different behaviors when the computer is "without entropy", that is, it does not have more data to go to to use as a source of random numbers.

Supposedly, as far as know , using this file is for security purposes.

$file = fopen('/dev/urandom', 'r');
if (!$file) {
    // Falhou
    exit();
}
$bytes = fread($file, $length);
fclose($file);
$hex = bin2hex($bytes);

This second solution has the disadvantage of not being available in Windows.

What does not work

rand and mt_rand were not thought of in encryption, so they do not work. The mt_rand function is described by the documentation as "better" than rand , but still has this warning :

  

Caution

     

This function does not generate cryptographically secure values, and   should not be used for cryptographic purposes. If you need to   cryptographically secure value, consider using   openssl_random_pseudo_bytes () instead.

In Portuguese:

  

Caution

     

This function does not generate cryptographically safe values, and should not   be used for cryptographic purposes. If you need a   cryptographically secure, consider using openssl_random_pseudo_bytes in   instead of this.

The uniqid function is also useless (see the notice in the documentation itself , the warning is not available in all languages ):

  

This function does not create random nor unpredictable string. This   function must not be used for security purposes. Use cryptographically   secure random function / generator and cryptographically secure hash   functions to create unpredictable secure ID.

In Portuguese:

  

This function does not create random or unpredictable strings. This function   can not be used for safety purposes. Use number generators   secure encryption and cryptographically secure hash functions for   create unpredictable secure IDs.

The hash (md5, sha, etc.) of a value that is not sufficiently random for cryptographic purposes is still not cryptographically secure.

    
15.02.2014 / 21:27
2
  

PHP 7 or higher

You can use random_bytes() , it is cryptographically secure and uses /dev/urandom :

$numero_de_bytes = 12;
$random = random_bytes($numero_de_bytes);

To have a data in hexadecimal you will have to use bin2hex :

echo bin2hex($random);

This will take 24 out humanly understandable letters. ;)

  

Libsodium possibly already embedded in PHP 7.2 with other syntax.

Libsodium is a library PECL which is one of the safest and should be inserted into PHP 7.2, with change in syntax.

$numero_de_bytes = 12;
$random = \Sodium\randombytes_buf($numero_de_bytes);

While Libsodium has a function that replaces the original bin2hex of PHP, because it is vulnerable to side-channel attacks, then use:

echo \Sodium\bin2hex($random);

Another option is to use:

echo \Sodium\bin2hex(
          \Sodium\randombytes_buf($numero_de_bytes)
     );
    
06.03.2017 / 04:04
1

It already exists in PHP 5.3.0 or higher specific routine for this.

link

Uses Openssl to generate the strings, with one parameter being the size and the other a Boolean that returns True if it is considered safe enough for use with encryption.

Reference to the OpenSSL site on how it works.

link

And if you want to test you can take the results of the convert function to binary and run a statistical test suite to validate how random the values are generated using NIST's Cryptographic Toolkit.

    
15.02.2014 / 21:25
1

There are several ways to generate "random" strings, and usually the key question in algorithms is seed that will be the source of the entropy and the algorithm that will generate the random string. p>

A very simple way to generate a pseudo-random string in PHP is:

$size = 2; // até 40
$seed = time(); // time() só para exemplo!
echo substr(sha1($seed), 40 - min($size,40));

The advantage is that it's pretty simple, but it's not so random. But resolve if it is for a simple application.

Another solution is to use the mt_rand () function that uses the Mersenne twister algorithm as a pseudo-randomness generator. With this function you can generate pseudo-random strings with higher quality. However, for some cases it can be quite slow (compared to rand () that uses LCG ).

There are other variations of MT (best up), SFMT (uses SSE) and MTGP (optimized for GPUs), but I do not know if there are implementations of them for PHP.

You can use the following to generate your strings with MT like this:

function random_str_mt($size) 
{
    $keys = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));

    $key = '';
    for ($i = 0; $i < ($size+10); $i++) 
    {
        $key .= $keys[array_rand($keys)];
    }

    return substr($key, 0, $size);
}

echo random_str_mt(20);

In the example above, substr () breaks a piece of the generated string to improve the quality of the result.

For encryption, the best solution is to use proper functions for this purpose. If you use PGP the openssl_random_pseudo_bytes function. For example:

function random_str_ossl($size) 
{
    return bin2hex(openssl_random_pseudo_bytes($size));
}

echo random_str_ossl(20);

On Windows, the openssl_random_pseudo_bytes call is pretty slow in some versions of PHP (I think the new ones have already fixed that).

Alternatively, you can use dev/urandom or /dev/random . As I've never tested, I'll just leave this link .

    
15.02.2014 / 22:10