}
/**
- * Compares a string of N random bytes.
- * This function effectively is a polyfill for the PHP 7 `random_bytes`.
+ * Generates a string of N random bytes.
+ * This function effectively is a polyfill for the PHP 7 `random_bytes` function.
*
* Requires either PHP 7 or 'openssl_random_pseudo_bytes' and throws a CryptoException
* if no sufficiently random data could be obtained.
}
}
+ /**
+ * Generates a random number.
+ * This function effectively is a polyfill for the PHP 7 `random_int` function.
+ *
+ * Requires that self::randomBytes() does not throw.
+ *
+ * @param int $min
+ * @param int $max
+ * @return int
+ * @throws CryptoException
+ */
+ public static function randomInt($min, $max) {
+ $range = $max - $min;
+ if ($range == 0) {
+ // not random
+ throw new CryptoException("Cannot generate a secure random number, min and max are the same");
+ }
+
+ if (function_exists('random_int')) {
+ return random_int($min, $max);
+ }
+
+ $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(self::randomBytes($bytes)));
+ $rnd = $rnd & $filter; // discard irrelevant bits
+ }
+ while ($rnd > $range);
+
+ return $min + $rnd;
+ }
+
/**
* Forbid creation of CryptoUtil objects.
*/
namespace wcf\util;
use wcf\system\exception\SystemException;
use wcf\system\Regex;
+use wcf\util\exception\CryptoException;
/**
* Provides functions to compute password hashes.
// not random
throw new SystemException("Cannot generate a secure random number, min and max are the same");
}
-
- // fallback to mt_rand() if OpenSSL is not available
- if (!function_exists('openssl_random_pseudo_bytes')) {
- return mt_rand($min, $max);
+
+ try {
+ return CryptoUtil::randomInt($min, $max);
}
-
- $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, $s)));
- $rnd = $rnd & $filter; // discard irrelevant bits
+ catch (CryptoException $e) {
+ // Backwards compatibility: This function never did throw.
+ return mt_rand($min, $max);
}
- while ($rnd >= $range);
-
- return $min + $rnd;
}
/**