I need to generate thousands (possibly millions) of unique codes for a client. These codes may have a monetary value, so it's vital that they are TRULY random, and that no pattern could be spotted and exploited by a clever hacker.
I've looked at various solutions for generating the code (cyclically generated = could be guessed, too risky, uniqid()
= good, but I may need a code of a different length).
Right now I'm thinking of generating the code using A-Z and 0-9 MINUS VOWELS (in order to ensure no rude words could be accidentally generated) although this may be increased in the future to lowercase characters, etc.
So far I have this (using a custom rand function taken from here):
function generateCode($length = 12) {
$chars = 'BCDFGHJKLMNPQRSTVWXYZ0123456789';
$count = mb_strlen($chars);
for ($i = 0, $result = ''; $i < $length; $i++) {
$randomIndex = devurandom_rand(0, $count - 1);
$result .= mb_substr($chars, $randomIndex, 1);
}
return $result;
}
// CUSTOM RAND FUNCTION
// equiv to rand, mt_rand
// returns int in *closed* interval [$min,$max]
function devurandom_rand($min = 0, $max = 0x7FFFFFFF) {
$diff = $max - $min;
if ($diff < 0 || $diff > 0x7FFFFFFF) {
throw new RuntimeException("Bad range");
}
$bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM);
if ($bytes === false || strlen($bytes) != 4) {
throw new RuntimeException("Unable to get 4 bytes");
}
$ary = unpack("Nint", $bytes);
$val = $ary['int'] & 0x7FFFFFFF; // 32-bit safe
$fp = (float) $val / 2147483647.0; // convert to [0,1]
return round($fp * $diff) + $min;
}
It's pretty basic, so I'm obviously concerned that it's not random enough. Can anyone tell me if this a decent way to ensure that the generated code is truly random?
(Note: Obviously a wannabe hacker will always be able to attempt a brute force attack. Such attempts will be handled elsewhere, I just want to make sure this code is truly random.)
$code = bin2hex(openssl_random_pseudo_bytes(12));
is the perfect solution to this problem?