Skip to content

Instantly share code, notes, and snippets.

@raveren
Last active November 21, 2023 12:35
Show Gist options
  • Save raveren/5555297 to your computer and use it in GitHub Desktop.
Save raveren/5555297 to your computer and use it in GitHub Desktop.
Generate cryptographically secure random strings. Based on Kohana's Text::random() method and this answer: http://stackoverflow.com/a/13733588/179104
function random_text( $type = 'alnum', $length = 8 )
{
switch ( $type ) {
case 'alnum':
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
break;
case 'alpha':
$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
break;
case 'hexdec':
$pool = '0123456789abcdef';
break;
case 'numeric':
$pool = '0123456789';
break;
case 'nozero':
$pool = '123456789';
break;
case 'distinct':
$pool = '2345679ACDEFHJKLMNPRSTUVWXYZ';
break;
default:
$pool = (string) $type;
break;
}
$crypto_rand_secure = function ( $min, $max ) {
$range = $max - $min;
if ( $range < 0 ) return $min; // not so random...
$log = log( $range, 2 );
$bytes = (int) ( $log / 8 ) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) ( 1 << $bits ) - 1; // set all lower bits to 1
do {
$rnd = hexdec( bin2hex( openssl_random_pseudo_bytes( $bytes ) ) );
$rnd = $rnd & $filter; // discard irrelevant bits
} while ( $rnd >= $range );
return $min + $rnd;
};
$token = "";
$max = strlen( $pool );
for ( $i = 0; $i < $length; $i++ ) {
$token .= $pool[$crypto_rand_secure( 0, $max )];
}
return $token;
}
@captn3m0
Copy link

Thanks for upgrading to random_int. There is detailed prior discussion on this at https://paragonie.com/blog/2015/07/how-safely-generate-random-strings-and-integers-in-php, paragonie/random_compat#5 which covers issues and fixes. To copy the summary:

Given the above, we cannot in good conscience recommend openssl_random_pseudo_bytes() as a CSPRNG. If you can use an alternative to openssl_random_pseudo_bytes(), please do so.

Look at the polyfill for a list of issues that need to be tackled for a secure CSPRNG in PHP. The current version refuses to fallback to OpenSSL.

It is much more tricker than the implementation here. People should just use https://github.com/paragonie/random_compat

@ph33nx
Copy link

ph33nx commented Dec 18, 2019

1 out of 5-6 times, php throws this error:
Notice: Uninitialized string offset: 62

My fix was to remove the check for 'random_int'

if (function_exists('random_int')) {
		$crypto_rand_secure = 'random_int';
} else { }

& just using the

$crypto_rand_secure = function ( $min, $max ) {
*******************************************

@raveren
Copy link
Author

raveren commented Dec 18, 2019

UPDATE: reverted to the age-old, tested function, seriously just go and use https://github.com/paragonie/random_compat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment