diff --git a/html/class_passwordRecovery.inc b/html/class_passwordRecovery.inc index 569fdb62c5a69a91364a288c34ba91e799c79177..1bc84b093c64530fe35db9fa7979101bb102d304 100644 --- a/html/class_passwordRecovery.inc +++ b/html/class_passwordRecovery.inc @@ -229,9 +229,8 @@ class standAlonePage { $base = 'ABCDEFGHKLMNOPQRSTWXYZabcdefghjkmnpqrstwxyz123456789'; $max = strlen($base) - 1; $randomhash = ''; - mt_srand((double) microtime() * 1000000); while (strlen($randomhash) < $len + 1) { - $randomhash .= $base{mt_rand(0, $max)}; + $randomhash .= $base{random_int(0, $max)}; } return $randomhash; } diff --git a/include/class_templateHandling.inc b/include/class_templateHandling.inc index 54c5f8ec7528cb2b9591fddcb289621f5d744421..8b4789f8ab7fcdff93f4ecef34bf97b87201e6b1 100644 --- a/include/class_templateHandling.inc +++ b/include/class_templateHandling.inc @@ -310,7 +310,7 @@ class templateHandling $length = 8; $chars = 'b'; if (count($args) >= 2) { - $length = mt_rand($args[0], $args[1]); + $length = random_int($args[0], $args[1]); if (count($args) >= 3) { $chars = $args[2]; } @@ -322,11 +322,11 @@ class templateHandling switch ($chars) { case 'd': /* digits */ - $res .= (string)rand(0, 9); + $res .= (string)random_int(0, 9); break; case 'l': /* letters */ - $nb = mt_rand(65, 116); + $nb = random_int(65, 116); if ($nb > 90) { /* lowercase */ $nb += 6; @@ -336,7 +336,7 @@ class templateHandling case 'b': /* both */ default: - $nb = mt_rand(65, 126); + $nb = random_int(65, 126); if ($nb > 116) { /* digit */ $nb = (string)($nb - 117); diff --git a/include/functions.inc b/include/functions.inc index 0a025c0011db90b2243cd4fe716798ae126405ff..37e51681a89f355568746040b197c4934c1ced55 100644 --- a/include/functions.inc +++ b/include/functions.inc @@ -175,25 +175,6 @@ function load_plist ($ldap_available = TRUE) return session::global_get('plist'); } - -/*! - * \brief Create seed with microseconds - * - * Example: - * \code - * srand(make_seed()); - * $random = rand(); - * \endcode - * - * \return float a floating point number which can be used to feed srand() with it - */ -function make_seed() -{ - list($usec, $sec) = explode(' ', microtime()); - return (float) $sec + ((float) $usec * 100000); -} - - /*! * \brief Debug level action * @@ -1522,8 +1503,7 @@ function gen_uids($rule, $attributes) $size = preg_replace('/^.*{id#(\d+)}.*$/', '\\1', $uid); while (TRUE) { - mt_srand((double)microtime() * 1000000); - $number = sprintf("%0".$size."d", mt_rand(0, pow(10, $size) - 1)); + $number = sprintf("%0".$size."d", random_int(0, pow(10, $size) - 1)); $res = preg_replace('/{id#(\d+)}/', $number, $uid); $ldap->search('(uid='.ldap_escape_f(preg_replace('/[{}]/', '', $res)).')', array('dn')); if ($ldap->count() == 0) { @@ -2482,6 +2462,35 @@ if (!function_exists('ldap_escape')) { } } +if (!function_exists('random_int')) { + // PHP<7, we fallback on openssl_random_pseudo_bytes + function random_int($min, $max) + { + $range = $max - $min; + if ($range <= 0) { + return $min; + } + + $log = log($range, 2); + // length in bytes + $nbBytes = (int) ($log / 8) + 1; + // length in bits + $nbBits = (int) $log + 1; + // set all lower bits to 1 + $filter = (int) (1 << $nbBits) - 1; + do { + $randomBytes = openssl_random_pseudo_bytes($nbBytes, $strong); + if (!$strong || ($randomBytes === FALSE)) { + throw new Exception('Failed to get random bytes'); + } + $rnd = unpack('C', $randomBytes)[1]; + // discard irrelevant bits + $rnd = $rnd & $filter; + } while ($rnd >= $range); + return $min + $rnd; + } +} + function ldap_escape_f($str, $ignore = '') { return ldap_escape($str, $ignore, LDAP_ESCAPE_FILTER); diff --git a/include/password-methods/class_password-methods-smd5.inc b/include/password-methods/class_password-methods-smd5.inc index 96d56b3b68a58699a9b53b91e5ee33a7afd6027b..31258f8fc767b840709a0cd2d7522461a8b4edf1 100644 --- a/include/password-methods/class_password-methods-smd5.inc +++ b/include/password-methods/class_password-methods-smd5.inc @@ -55,8 +55,7 @@ class passwordMethodsmd5 extends passwordMethod */ function generate_hash($pwd) { - mt_srand(microtime() * 10000000); - $salt0 = substr(pack('h*', md5(mt_rand())), 0, 8); + $salt0 = substr(pack('h*', md5(random_int(0, PHP_INT_MAX))), 0, 8); $salt = substr(pack('H*', md5($salt0 . $pwd)), 0, 4); $hash = '{SMD5}'.base64_encode(pack('H*', md5($pwd . $salt)) . $salt); return $hash; diff --git a/include/password-methods/class_password-methods-ssha.inc b/include/password-methods/class_password-methods-ssha.inc index fa386d7aacf82f5beda9bb6a372d58c9c6504ebc..748c1704c2f89366c8e503e3b96d0cb595cf32cf 100644 --- a/include/password-methods/class_password-methods-ssha.inc +++ b/include/password-methods/class_password-methods-ssha.inc @@ -56,12 +56,12 @@ class passwordMethodssha extends passwordMethod function generate_hash($pwd) { if (function_exists('sha1')) { - $salt = substr(pack('h*', md5(mt_rand())), 0, 8); + $salt = substr(pack('h*', md5(random_int(0, PHP_INT_MAX))), 0, 8); $salt = substr(pack('H*', sha1($salt.$pwd)), 0, 4); $pwd = '{SSHA}'.base64_encode(pack('H*', sha1($pwd.$salt)).$salt); return $pwd; } elseif (function_exists('mhash')) { - $salt = mhash_keygen_s2k(MHASH_SHA1, $pwd, substr(pack('h*', md5(mt_rand())), 0, 8), 4); + $salt = mhash_keygen_s2k(MHASH_SHA1, $pwd, substr(pack('h*', md5(random_int(0, PHP_INT_MAX))), 0, 8), 4); $pwd = '{SSHA}'.base64_encode(mhash(MHASH_SHA1, $pwd.$salt).$salt); } else { msg_dialog::display(_('Configuration error'), msgPool::missingext('mhash'), ERROR_DIALOG); diff --git a/include/simpleplugin/attributes/class_FileAttribute.inc b/include/simpleplugin/attributes/class_FileAttribute.inc index a7a2455e4f7a3a969dcd7d1b81c4eac6ca2a0c18..422983e62f1c7587829d976842bd79b2b735a69d 100644 --- a/include/simpleplugin/attributes/class_FileAttribute.inc +++ b/include/simpleplugin/attributes/class_FileAttribute.inc @@ -354,8 +354,7 @@ class ImageAttribute extends FileAttribute $this->setValue($this->inputValue($this->getValue())); $id = $this->getHtmlId(); // Just to be sure the image is not cached - srand((double)microtime() * 1000000); - $key = $this->getLdapName().rand(0, 10000); + $key = $this->getLdapName().random_int(0, 10000); $display = '<img id="'.$id.'_img"'. ($this->disabled ? 'disabled="disabled"' : ''). ' src="getbin.php?key='.$key.'"'. diff --git a/setup/class_setupStepChecks.inc b/setup/class_setupStepChecks.inc index e66d2461f51afcd6e5f91b0e43caad1d0c45f252..bdd7aa8269d3506bbcbc2a052707d33f0b6f725a 100644 --- a/setup/class_setupStepChecks.inc +++ b/setup/class_setupStepChecks.inc @@ -95,6 +95,14 @@ class setupStepChecks extends setupStep $M = TRUE; $basic_checks[] = array('NAME' => $N , 'DESC' => $D , 'RESULT' => $R , 'SOLUTION' => $S , 'MUST' => $M ); + /* Pseudo-random check */ + $N = _('Checking cryptographically secure pseudo-random integers'); + $D = _('You must use PHP>=7 or have openssl module activated so that FusionDirectory can generate cryptographically secure pseudo-random integers.'); + $S = _('Please upgrade to PHP7 or activate openssl module.'); + $R = (is_callable('random_int') || is_callable('openssl_random_pseudo_bytes')); + $M = TRUE; + $basic_checks[] = array('NAME' => $N , 'DESC' => $D , 'RESULT' => $R , 'SOLUTION' => $S , 'MUST' => $M ); + /* Check for json support */ $N = msgPool::checkingFor('json'); $D = _('FusionDirectory requires this module to encode variables for javascript use.'); diff --git a/setup/class_setupStepMigrate.inc b/setup/class_setupStepMigrate.inc index 6613a3207d19f5b045d13fd88feed1514d9db6cf..a87966cd2e38998eb06aac94dfcccf9675548335 100644 --- a/setup/class_setupStepMigrate.inc +++ b/setup/class_setupStepMigrate.inc @@ -471,7 +471,7 @@ class setupStepMigrate extends setupStep $ldap = $config->get_ldap_link(); /* Create dummy entry */ - $name = 'GOsa_setup_text_entry_'.session_id().rand(0, 999999); + $name = 'GOsa_setup_text_entry_'.session_id().random_int(0, 999999); $dn = 'ou='.$name.','.$config->current['BASE']; $testEntry = array();