Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cryptographically Secure Random String Function

Goal: Find the most cryptographically secure random string generator. Using Alphabetic, numeric and if possible special characters in the string.

I have been reading on here and other places, but I still hear so many different answers/opinions. Can people who are up to date and knowledgeable about security and cryptography chime in here.

The following functions will be used to generate a 8 character random password and also generate a 128 character random token.

Function 1:

/**
 * Used for generating a random string.
 *
 * @param int $_Length  The lengtyh of the random string.
 * @return string The random string.
 */
function gfRandomString($_Length) {
    $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < $_Length; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

Function 2:

The PHP.net docs say: crypto_strong: If passed into the function, this will hold a boolean value that determines if the algorithm used was "cryptographically strong", e.g., safe for usage with GPG, passwords, etc. TRUE if it did, otherwise FALSE.

So is that based on the the server? If I test it once, and it is able to generate a crypto_strong string, will it always be able to? Or would I need to check each time and create a loop until it generates a crypto_strong string.

/**
 * Used for generating a random string.
 *
 * @param int $_Length  The length of bits.
 * @return string The random string.
 */
function gfSecureString($_Length) {
    $Str = bin2hex(openssl_random_pseudo_bytes($_Length));
    return $Str; 
}

I welcome any suggestions to improve the cryptographic strength.

like image 966
M H Avatar asked Jan 07 '23 23:01

M H


2 Answers

So you want to securely generate random strings in PHP. Neither of the two functions in the question will give you what you want, but the rand() solution is the worst of the two. rand() is not secure, while bin2hex(openssl_random_pseudo_bytes()) limits your output character set.

Also, openssl_random_pseudo_bytes() might not be reliable under extreme conditions or exotic setups.

From what I understand, crypto_strong will only be set to false if RAND_pseudo_bytes() fails to return any data. If OpenSSL is not seeded when it's invoked, it will silently return weak (and possibly predictable) pseudorandom bytes. You have no way, from PHP, to determine if it's random either.

How to generate secure random strings today

If you want a solution that has received substantial review for PHP 5.x, use RandomLib.

$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
$randomPassword = $generator->generateString(20, $alphabet);

Alternative solutions

If you'd rather not use RandomLib (even if, purely, because you want to have alternative options available), you can also use random_int() when PHP 7 comes out. If you can't wait until then, take a look at our random_compat project.

If you happen to be using the cryptography library, libsodium, you can generate random numbers like so:

/**
 * Depends on the PECL extension libsodium
 * 
 * @link https://stackoverflow.com/a/31498051/2224584
 * 
 * @param int $length How long should the string be?
 * @param string $alphabet Contains all of the allowed characters
 * 
 * @return string
 */
function sodium_random_str($length, $alphabet = 'abcdefghijklmnopqrstuvwxyz')
{
    $buf = '';
    $alphabetSize = strlen($alphabet);
    for ($i = 0; $i < $length; ++$i) {
        $buf .= $alphabet[\Sodium\randombytes_uniform($alphabetSize)];
    }
    return $buf;
}

See this answer for example code that uses random_int(). I'd rather not duplicate the effort of updating the code in the future, should the need ever arise.

like image 183
Scott Arciszewski Avatar answered Jan 15 '23 14:01

Scott Arciszewski


openssl_random_pseudo_bytes has a pretty large chance of being a cryptographically secure generator, while rand certainly isn't. However, it will only return binary data which you revert to hexadecimals. Hexadecimals are not enough to generate a password string. Neither function includes special characters as you seem to require.

So neither one of the code snippets fits your purpose.

like image 21
Maarten Bodewes Avatar answered Jan 15 '23 15:01

Maarten Bodewes