From 2a358417318c8b17eb0f7035b992b4b796879763 Mon Sep 17 00:00:00 2001 From: Jared Hancock <jared@osticket.com> Date: Tue, 13 Jan 2015 10:58:22 -0600 Subject: [PATCH] Fix very predictable random data on some platforms Misc::randCode does not generate significantly random data for Windows platforms with a local database. This stems from the random seed using the milliseconds from the current time of day and the database connection time, in microseconds. Because Windows has especially poor sub-second time resolution via the microtime() function, the seed does not have many variations. This patch addresses the issue by using the included Crypto::random() function as a source of random data rather than the mt_rand() function, as it uses native cryptographic random data generators if possible to generate the data, and uses microtime() as a fallback if no other source of random data is available on the platform. --- include/class.misc.php | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/include/class.misc.php b/include/class.misc.php index 84871c539..cf1d0b32d 100644 --- a/include/class.misc.php +++ b/include/class.misc.php @@ -16,14 +16,31 @@ class Misc { - function randCode($count=8, $chars=false) { - $chars = $chars ? $chars - : 'abcdefghijklmnopqrstuvwzyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.'; - $data = ''; - $m = strlen($chars) - 1; - for ($i=0; $i < $count; $i++) - $data .= $chars[mt_rand(0,$m)]; - return $data; + function randCode($len=8, $chars=false) { + $chars = $chars ?: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_='; + + // Determine the number of bits we need + $char_count = strlen($chars); + $bits_per_char = ceil(log($char_count, 2)); + $bytes = ceil(4 * $len / floor(32 / $bits_per_char)); + // Pad to 4 byte boundary + $bytes += (4 - ($bytes % 4)) % 4; + + // Fetch some random data blocks + $data = Crypto::random($bytes); + + $mask = (1 << $bits_per_char) - 1; + $loops = (int) (32 / $bits_per_char); + $output = ''; + $ints = unpack('V*', $data); + array_shift($ints); + foreach ($ints as $int) { + for ($i = $loops; $i > 0; $i--) { + $output .= $chars[($int & $mask) % $char_count]; + $int >>= $bits_per_char; + } + } + return substr($output, 0, $len); } function __rand_seed($value=0) { -- GitLab