From ed59911f9ee542da87ae7cddcb2d50da0e785079 Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Mon, 31 Mar 2008 20:50:05 +0000 Subject: - Patch #29706 by pwolanin, solardiz, et al: more secure password hashing. This is a big and important patch for Drupal's security. We are switching to much stronger password hashes that are also compatible with the Portable PHP password hashing framework. The new password hashes defeat a number of attacks, including: - The ability to try candidate passwords against multiple hashes at once. - The ability to use pre-hashed lists of candidate passwords. - The ability to determine whether two users have the same (or different) password without actually having to guess one of the passwords. Also implemented a pluggable password hashing API (similar to how an alternate cache mechanism can be used) to allow developers to readily substitute an alternative hashing and authentication scheme. Thanks all! --- includes/common.inc | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'includes/common.inc') diff --git a/includes/common.inc b/includes/common.inc index 52d8babd8..a77479e1f 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2307,6 +2307,44 @@ function drupal_urlencode($text) { } } +/** + * Returns a string of highly randomized bytes (over the full 8-bit range). + * + * This function is better than simply calling mt_rand() or any other built-in + * PHP function because it can return a long string of bytes (compared to < 4 + * bytes normally from mt_rand()) and uses the best available pseudo-random source. + * + * @param $count + * The number of characters (bytes) to return in the string. + */ +function drupal_random_bytes($count) { + static $random_state; + // We initialize with the somewhat random PHP process ID on the first call. + if (empty($random_state)) { + $random_state = getmypid(); + } + $output = ''; + // /dev/urandom is available on many *nix systems and is considered the best + // commonly available pseudo-random source. + if ($fh = @fopen('/dev/urandom', 'rb')) { + $output = fread($fh, $count); + fclose($fh); + } + // If /dev/urandom is not available or returns no bytes, this loop will + // generate a good set of pseudo-random bytes on any system. + // Note that it may be important that our $random_state is passed + // through md5() prior to being rolled into $output, that the two md5() + // invocations are different, and that the extra input into the first one - + // the microtime() - is prepended rather than appended. This is to avoid + // directly leaking $random_state via the $output stream, which could + // allow for trivial prediction of further "random" numbers. + while (strlen($output) < $count) { + $random_state = md5(microtime() . mt_rand() . $random_state); + $output .= md5(mt_rand() . $random_state, TRUE); + } + return substr($output, 0, $count); +} + /** * Ensure the private key variable used to generate tokens is set. * @@ -2315,7 +2353,7 @@ function drupal_urlencode($text) { */ function drupal_get_private_key() { if (!($key = variable_get('drupal_private_key', 0))) { - $key = md5(uniqid(mt_rand(), true)) . md5(uniqid(mt_rand(), true)); + $key = md5(drupal_random_bytes(64)); variable_set('drupal_private_key', $key); } return $key; -- cgit v1.2.3