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.
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.
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);
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With