diff --git includes/bootstrap.inc includes/bootstrap.inc
index 203b052..838c471 100644
--- includes/bootstrap.inc
+++ includes/bootstrap.inc
@@ -1709,6 +1709,55 @@ function drupal_block_denied($ip) {
 }
 
 /**
+ * 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)  {
+  // $random_state does not use drupal_static as it stores random bytes.
+  static $random_state, $bytes;
+  // Initialize on the first call. The contents of $_SERVER includes a mix of
+  // user-specific and system information that varies a little with each page.
+  if (!isset($random_state)) {
+    $random_state = print_r($_SERVER, TRUE) . uniqid(mt_rand(), TRUE);
+    $bytes = '';
+  }
+  if (strlen($bytes) < $count) {
+    // We generate the requested bytes plus a thousand extra to make
+    // additional invocations faster.
+    $desired_bytes = $count + 1000;
+    // /dev/urandom is available on many *nix systems and is considered the
+    // best commonly available pseudo-random source.
+    if ($fh = @fopen('/dev/urandom', 'rb')) {
+      $bytes = fread($fh, $desired_bytes);
+      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 hash() prior to being rolled into $output, that the two hash()
+    // 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($bytes) < $desired_bytes) {
+      $random_state = hash('sha256', microtime() . mt_rand() . $random_state);
+      $bytes .= hash('sha256', mt_rand() . $random_state, TRUE);
+    }
+  }
+  // Return the bytes from the end, since these will be the most random if
+  // we used the fallback method.
+  $output = substr($bytes, -$count);
+  $bytes = substr($bytes, 0, -$count);
+  return $output;
+}
+
+/**
  * Generates a default anonymous $user object.
  *
  * @return Object - the user object.
diff --git includes/common.inc includes/common.inc
index 8026209..9585974 100644
--- includes/common.inc
+++ includes/common.inc
@@ -4183,45 +4183,6 @@ function drupal_json_output($var = NULL) {
 }
 
 /**
- * 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)  {
-  // $random_state does not use drupal_static as it stores random bytes.
-  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);
-}
-
-/**
  * Get a salt useful for hardening against SQL injection.
  *
  * @return
@@ -4242,7 +4203,7 @@ function drupal_get_hash_salt() {
  */
 function drupal_get_private_key() {
   if (!($key = variable_get('drupal_private_key', 0))) {
-    $key = md5(drupal_random_bytes(64));
+    $key = hash('sha256', drupal_random_bytes(64));
     variable_set('drupal_private_key', $key);
   }
   return $key;
@@ -4255,10 +4216,41 @@ function drupal_get_private_key() {
  *   An additional value to base the token on.
  */
 function drupal_get_token($value = '') {
-  $private_key = drupal_get_private_key();
-  // A single md5() is vulnerable to length-extension attacks, so use it twice.
-  // @todo:  add md5 and sha1 hmac functions to core.
-  return md5(drupal_get_hash_salt() . md5(session_id() . $value . $private_key));
+  return drupal_hmac_base64(session_id() . $value, drupal_get_private_key() . drupal_get_hash_salt());
+}
+
+/**
+ * Calculate a base-64 encoded, URL-safe sha-256 hmac.
+ *
+ * @param $data
+ *   String to be validated with the hmac.
+ * @param $key
+ *   A secret string key.
+ *
+ * @return
+ *   A base-64 encoded sha-256 hmac, with + replaced with -, / with _ and
+ *   any = padding characters removed.
+ */
+function drupal_hmac_base64($data, $key) {
+  $hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+  // Modify the hmac so it's safe to use in URLs.
+  return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
+}
+
+/**
+ * Calculate a base-64 encoded, URL-safe sha-256 hash.
+ *
+ * @param $data
+ *   String to be hashed.
+ *
+ * @return
+ *   A base-64 encoded sha-256 hash, with + replaced with -, / with _ and
+ *   any = padding characters removed.
+ */
+function drupal_hash_base64($data) {
+  $hash = base64_encode(hash('sha256', $data, TRUE));
+  // Modify the hash so it's safe to use in URLs.
+  return strtr($hash, array('+' => '-', '/' => '_', '=' => ''));
 }
 
 /**
@@ -5142,7 +5134,7 @@ function drupal_render_cache_set(&$markup, $elements) {
 function drupal_render_cache_by_query($query, $function, $expire = CACHE_TEMPORARY, $granularity = NULL) {
   $cache_keys = array_merge(array($function), drupal_render_cid_parts($granularity));
   $query->preExecute();
-  $cache_keys[] = md5(serialize(array((string) $query, $query->getArguments())));
+  $cache_keys[] = drupal_hash_base64(serialize(array((string) $query, $query->getArguments())));
   return array(
     '#query' => $query,
     '#pre_render' => array($function . '_pre_render'),
diff --git includes/form.inc includes/form.inc
index 1ed3c98..577d893 100644
--- includes/form.inc
+++ includes/form.inc
@@ -203,7 +203,7 @@ function drupal_build_form($form_id, &$form_state) {
       }
 
       $form = drupal_retrieve_form($form_id, $form_state);
-      $form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
+      $form_build_id = 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
       $form['#build_id'] = $form_build_id;
 
       // Fix the form method, if it is 'get' in $form_state, but not in $form.
@@ -331,7 +331,7 @@ function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
   // Otherwise, a new #build_id is generated, to not clobber the previous
   // build's data in the form cache; also allowing the user to go back to an
   // earlier build, make changes, and re-submit.
-  $form['#build_id'] = isset($old_form['#build_id']) ? $old_form['#build_id'] : 'form-' . md5(mt_rand());
+  $form['#build_id'] = isset($old_form['#build_id']) ? $old_form['#build_id'] : 'form-' . drupal_hash_base64(uniqid(mt_rand(), TRUE) . mt_rand());
 
   // #action defaults to request_uri(), but in case of AJAX and other partial
   // rebuilds, the form is submitted to an alternate URL, and the original
diff --git includes/install.core.inc includes/install.core.inc
index c0715e2..06446bc 100644
--- includes/install.core.inc
+++ includes/install.core.inc
@@ -1004,7 +1004,7 @@ function install_settings_form_submit($form, &$form_state) {
     'required' => TRUE,
   );
   $settings['drupal_hash_salt'] = array(
-    'value'    => sha1(drupal_random_bytes(64)),
+    'value'    => hash('sha256', drupal_random_bytes(64)),
     'required' => TRUE,
   );
   drupal_rewrite_settings($settings);
diff --git includes/menu.inc includes/menu.inc
index 3c355ce..e7a099a 100644
--- includes/menu.inc
+++ includes/menu.inc
@@ -408,8 +408,8 @@ function menu_get_item($path = NULL, $router_item = NULL) {
     $ancestors = menu_get_ancestors($parts);
 
     // Since there is no limit to the length of $path, but the cids are
-    // restricted to 255 characters, use md5() to keep it short yet unique.
-    $cid = 'menu_item:' . md5($path);
+    // restricted to 255 characters, use sha256 to keep it short yet unique.
+    $cid = 'menu_item:' . hash('sha256', $path);
     if ($cached = cache_get($cid, 'cache_menu')) {
       $router_item = $cached->data;
     }
@@ -1238,7 +1238,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
  * Helper function - compute the real cache ID for menu tree data.
  */
 function _menu_tree_cid($menu_name, $data) {
-  return 'links:' . $menu_name . ':tree-data:' . $GLOBALS['language']->language . ':' . md5(serialize($data));
+  return 'links:' . $menu_name . ':tree-data:' . $GLOBALS['language']->language . ':' . hash('sha256', serialize($data));
 }
 
 /**
diff --git includes/session.inc includes/session.inc
index 438d47d..35cfd79 100644
--- includes/session.inc
+++ includes/session.inc
@@ -206,7 +206,10 @@ function drupal_session_initialize() {
     // processes (like drupal_get_token()) needs to know the future
     // session ID in advance.
     $user = drupal_anonymous_user();
-    session_id(md5(uniqid('', TRUE)));
+    // Less random sessions (which are much faster to generate) are used for
+    // anoymous users than are generated in drupal_session_regenerate() when
+    // a user becomes authenticated.
+    session_id(hash('sha256', uniqid(mt_rand(), TRUE)));
   }
 }
 
@@ -283,7 +286,7 @@ function drupal_session_regenerate() {
   if ($is_https && variable_get('https', FALSE)) {
     $insecure_session_name = substr(session_name(), 1);
     $params = session_get_cookie_params();
-    $session_id = md5(uniqid(mt_rand(), TRUE));
+    $session_id = hash('sha256', uniqid(mt_rand(), TRUE) . drupal_random_bytes(55));
     setcookie($insecure_session_name, $session_id, REQUEST_TIME + $params['lifetime'], $params['path'], $params['domain'], FALSE, $params['httponly']);
     $_COOKIE[$insecure_session_name] = $session_id;
   }
diff --git modules/book/book.admin.inc modules/book/book.admin.inc
index 8ed7216..771c9df 100644
--- modules/book/book.admin.inc
+++ modules/book/book.admin.inc
@@ -154,7 +154,7 @@ function _book_admin_table($node, &$form) {
   $tree = book_menu_subtree_data($node->book);
   $tree = array_shift($tree); // Do not include the book item itself.
   if ($tree['below']) {
-    $hash = sha1(serialize($tree['below']));
+    $hash = drupal_hash_base64(serialize($tree['below']));
     // Store the hash value as a hidden form element so that we can detect
     // if another user changed the book hierarchy.
     $form['tree_hash'] = array(
diff --git modules/book/book.module modules/book/book.module
index d60ab18..0811a9f 100644
--- modules/book/book.module
+++ modules/book/book.module
@@ -1246,7 +1246,7 @@ function book_menu_subtree_data($link) {
       $data['node_links'] = array();
       menu_tree_collect_node_links($data['tree'], $data['node_links']);
       // Compute the real cid for book subtree data.
-      $tree_cid = 'links:' . $item['menu_name'] . ':subtree-data:' . md5(serialize($data));
+      $tree_cid = 'links:' . $item['menu_name'] . ':subtree-data:' . hash('sha256', serialize($data));
       // Cache the data, if it is not already in the cache.
 
       if (!cache_get($tree_cid, 'cache_menu')) {
diff --git modules/system/system.install modules/system/system.install
index 5e3804b..11d068e 100644
--- modules/system/system.install
+++ modules/system/system.install
@@ -414,7 +414,7 @@ function system_install() {
     ->execute();
 
   // Populate the cron key variable.
-  $cron_key = md5(mt_rand());
+  $cron_key = drupal_hash_base64(drupal_random_bytes(55));
   variable_set('cron_key', $cron_key);
 }
 
@@ -1650,7 +1650,7 @@ function system_update_7000() {
  * Generate a cron key and save it in the variables table.
  */
 function system_update_7001() {
-  variable_set('cron_key', md5(mt_rand()));
+  variable_set('cron_key', drupal_hash_base64(drupal_random_bytes(55)));
 }
 
 /**
diff --git modules/update/update.fetch.inc modules/update/update.fetch.inc
index 7944828..9db4d1c 100644
--- modules/update/update.fetch.inc
+++ modules/update/update.fetch.inc
@@ -137,7 +137,7 @@ function _update_process_fetch_task($project) {
 
   $success = FALSE;
   $available = array();
-  $site_key = md5($base_url . drupal_get_private_key());
+  $site_key = drupal_hmac_base64($base_url, drupal_get_private_key());
   $url = _update_build_fetch_url($project, $site_key);
   $fetch_url_base = _update_get_fetch_url_base($project);
   $project_name = $project['name'];
diff --git modules/user/user.module modules/user/user.module
index 51e4db5..30f45d4 100644
--- modules/user/user.module
+++ modules/user/user.module
@@ -2079,8 +2079,7 @@ function user_cancel_url($account) {
 }
 
 function user_pass_rehash($password, $timestamp, $login) {
-  // A single md5() is vulnerable to length-extension attacks, so use it twice.
-  return md5(drupal_get_hash_salt() . md5($timestamp . $password . $login));
+  return drupal_hmac_base64($timestamp . $login, drupal_get_hash_salt() . $password);
 }
 
 /**
diff --git modules/user/user.pages.inc modules/user/user.pages.inc
index db70017..cd9134c 100644
--- modules/user/user.pages.inc
+++ modules/user/user.pages.inc
@@ -133,7 +133,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
           user_login_finalize();
           drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
           // Let the user's password be changed without the current password check.
-          $token = md5(drupal_random_bytes(55));
+          $token = drupal_hash_base64(drupal_random_bytes(55));
           $_SESSION['pass_reset_' . $user->uid] = $token;
           drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
         }
