diff --git a/core/includes/password.inc b/core/includes/password.inc
deleted file mode 100644
index b052a4a..0000000
--- a/core/includes/password.inc
+++ /dev/null
@@ -1,288 +0,0 @@
-<?php
-
-/**
- * @file
- * Secure password hashing functions for user authentication.
- *
- * Based on the Portable PHP password hashing framework.
- * @see http://www.openwall.com/phpass/
- *
- * An alternative or custom version of this password hashing API may be
- * used by setting the variable password_inc to the name of the PHP file
- * containing replacement user_hash_password(), user_check_password(), and
- * user_needs_new_hash() functions.
- */
-
-/**
- * The standard log2 number of iterations for password stretching. This should
- * increase by 1 every Drupal version in order to counteract increases in the
- * speed and power of computers available to crack the hashes.
- */
-const DRUPAL_HASH_COUNT = 16;
-
-/**
- * The minimum allowed log2 number of iterations for password stretching.
- */
-const DRUPAL_MIN_HASH_COUNT = 7;
-
-/**
- * The maximum allowed log2 number of iterations for password stretching.
- */
-const DRUPAL_MAX_HASH_COUNT = 30;
-
-/**
- * The expected (and maximum) number of characters in a hashed password.
- */
-const DRUPAL_HASH_LENGTH = 55;
-
-/**
- * Returns a string for mapping an int to the corresponding base 64 character.
- */
-function _password_itoa64() {
-  return './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
-}
-
-/**
- * Encode bytes into printable base 64 using the *nix standard from crypt().
- *
- * @param $input
- *   The string containing bytes to encode.
- * @param $count
- *   The number of characters (bytes) to encode.
- *
- * @return
- *   Encoded string
- */
-function _password_base64_encode($input, $count) {
-  $output = '';
-  $i = 0;
-  $itoa64 = _password_itoa64();
-  do {
-    $value = ord($input[$i++]);
-    $output .= $itoa64[$value & 0x3f];
-    if ($i < $count) {
-      $value |= ord($input[$i]) << 8;
-    }
-    $output .= $itoa64[($value >> 6) & 0x3f];
-    if ($i++ >= $count) {
-      break;
-    }
-    if ($i < $count) {
-      $value |= ord($input[$i]) << 16;
-    }
-    $output .= $itoa64[($value >> 12) & 0x3f];
-    if ($i++ >= $count) {
-      break;
-    }
-    $output .= $itoa64[($value >> 18) & 0x3f];
-  } while ($i < $count);
-
-  return $output;
-}
-
-/**
- * Generates a random base 64-encoded salt prefixed with settings for the hash.
- *
- * Proper use of salts may 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.
- *
- * @param $count_log2
- *   Integer that determines the number of iterations used in the hashing
- *   process. A larger value is more secure, but takes more time to complete.
- *
- * @return
- *   A 12 character string containing the iteration count and a random salt.
- */
-function _password_generate_salt($count_log2) {
-  $output = '$S$';
-  // Ensure that $count_log2 is within set bounds.
-  $count_log2 = _password_enforce_log2_boundaries($count_log2);
-  // We encode the final log2 iteration count in base 64.
-  $itoa64 = _password_itoa64();
-  $output .= $itoa64[$count_log2];
-  // 6 bytes is the standard salt for a portable phpass hash.
-  $output .= _password_base64_encode(drupal_random_bytes(6), 6);
-  return $output;
-}
-
-/**
- * Ensures that $count_log2 is within set bounds.
- *
- * @param $count_log2
- *   Integer that determines the number of iterations used in the hashing
- *   process. A larger value is more secure, but takes more time to complete.
- *
- * @return
- *   Integer within set bounds that is closest to $count_log2.
- */
-function _password_enforce_log2_boundaries($count_log2) {
-  if ($count_log2 < DRUPAL_MIN_HASH_COUNT) {
-    return DRUPAL_MIN_HASH_COUNT;
-  }
-  elseif ($count_log2 > DRUPAL_MAX_HASH_COUNT) {
-    return DRUPAL_MAX_HASH_COUNT;
-  }
-
-  return (int) $count_log2;
-}
-
-/**
- * Hash a password using a secure stretched hash.
- *
- * By using a salt and repeated hashing the password is "stretched". Its
- * security is increased because it becomes much more computationally costly
- * for an attacker to try to break the hash by brute-force computation of the
- * hashes of a large number of plain-text words or strings to find a match.
- *
- * @param $algo
- *   The string name of a hashing algorithm usable by hash(), like 'sha256'.
- * @param $password
- *   The plain-text password to hash.
- * @param $setting
- *   An existing hash or the output of _password_generate_salt().  Must be
- *   at least 12 characters (the settings and salt).
- *
- * @return
- *   A string containing the hashed password (and salt) or FALSE on failure.
- *   The return string will be truncated at DRUPAL_HASH_LENGTH characters max.
- */
-function _password_crypt($algo, $password, $setting) {
-  // The first 12 characters of an existing hash are its setting string.
-  $setting = substr($setting, 0, 12);
-
-  if ($setting[0] != '$' || $setting[2] != '$') {
-    return FALSE;
-  }
-  $count_log2 = _password_get_count_log2($setting);
-  // Hashes may be imported from elsewhere, so we allow != DRUPAL_HASH_COUNT
-  if ($count_log2 < DRUPAL_MIN_HASH_COUNT || $count_log2 > DRUPAL_MAX_HASH_COUNT) {
-    return FALSE;
-  }
-  $salt = substr($setting, 4, 8);
-  // Hashes must have an 8 character salt.
-  if (strlen($salt) != 8) {
-    return FALSE;
-  }
-
-  // Convert the base 2 logarithm into an integer.
-  $count = 1 << $count_log2;
-
-  // We rely on the hash() function being available in PHP 5.2+.
-  $hash = hash($algo, $salt . $password, TRUE);
-  do {
-    $hash = hash($algo, $hash . $password, TRUE);
-  } while (--$count);
-
-  $len = strlen($hash);
-  $output =  $setting . _password_base64_encode($hash, $len);
-  // _password_base64_encode() of a 16 byte MD5 will always be 22 characters.
-  // _password_base64_encode() of a 64 byte sha512 will always be 86 characters.
-  $expected = 12 + ceil((8 * $len) / 6);
-  return (strlen($output) == $expected) ? substr($output, 0, DRUPAL_HASH_LENGTH) : FALSE;
-}
-
-/**
- * Parse the log2 iteration count from a stored hash or setting string.
- */
-function _password_get_count_log2($setting) {
-  $itoa64 = _password_itoa64();
-  return strpos($itoa64, $setting[3]);
-}
-
-/**
- * Hash a password using a secure hash.
- *
- * @param $password
- *   A plain-text password.
- * @param $count_log2
- *   Optional integer to specify the iteration count. Generally used only during
- *   mass operations where a value less than the default is needed for speed.
- *
- * @return
- *   A string containing the hashed password (and a salt), or FALSE on failure.
- */
-function user_hash_password($password, $count_log2 = 0) {
-  if (empty($count_log2)) {
-    // Use the standard iteration count.
-    $count_log2 = variable_get('password_count_log2', DRUPAL_HASH_COUNT);
-  }
-  return _password_crypt('sha512', $password, _password_generate_salt($count_log2));
-}
-
-/**
- * Check whether a plain text password matches a stored hashed password.
- *
- * Alternative implementations of this function may use other data in the
- * $account object, for example the uid to look up the hash in a custom table
- * or remote database.
- *
- * @param $password
- *   A plain-text password
- * @param $account
- *   A user object with at least the fields from the {users} table.
- *
- * @return
- *   TRUE or FALSE.
- */
-function user_check_password($password, $account) {
-  if (substr($account->pass, 0, 2) == 'U$') {
-    // This may be an updated password from user_update_7000(). Such hashes
-    // have 'U' added as the first character and need an extra md5() (see the
-    // Drupal 7 documentation).
-    $stored_hash = substr($account->pass, 1);
-    $password = md5($password);
-  }
-  else {
-    $stored_hash = $account->pass;
-  }
-
-  $type = substr($stored_hash, 0, 3);
-  switch ($type) {
-    case '$S$':
-      // A normal Drupal 7 password using sha512.
-      $hash = _password_crypt('sha512', $password, $stored_hash);
-      break;
-    case '$H$':
-      // phpBB3 uses "$H$" for the same thing as "$P$".
-    case '$P$':
-      // A phpass password generated using md5.  This is an
-      // imported password or from an earlier Drupal version.
-      $hash = _password_crypt('md5', $password, $stored_hash);
-      break;
-    default:
-      return FALSE;
-  }
-  return ($hash && $stored_hash == $hash);
-}
-
-/**
- * Check whether a user's hashed password needs to be replaced with a new hash.
- *
- * This is typically called during the login process when the plain text
- * password is available. A new hash is needed when the desired iteration count
- * has changed through a change in the variable password_count_log2 or
- * DRUPAL_HASH_COUNT or if the user's password hash was generated in an update
- * like user_update_7000() (see the Drupal 7 documentation).
- *
- * Alternative implementations of this function might use other criteria based
- * on the fields in $account.
- *
- * @param $account
- *   A user object with at least the fields from the {users} table.
- *
- * @return
- *   TRUE or FALSE.
- */
-function user_needs_new_hash($account) {
-  // Check whether this was an updated password.
-  if ((substr($account->pass, 0, 3) != '$S$') || (strlen($account->pass) != DRUPAL_HASH_LENGTH)) {
-    return TRUE;
-  }
-  // Ensure that $count_log2 is within set bounds.
-  $count_log2 = _password_enforce_log2_boundaries(variable_get('password_count_log2', DRUPAL_HASH_COUNT));
-  // Check whether the iteration count used differs from the standard number.
-  return (_password_get_count_log2($account->pass) !== $count_log2);
-}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 017aa01..0893312 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -122,6 +122,7 @@ public function build(ContainerBuilder $container) {
       ->addArgument(new Reference('service_container'))
       ->setFactoryClass('Drupal\Core\ExceptionController')
       ->setFactoryMethod('getExceptionListener');
+    $container->register('password', 'Drupal\Core\Password\phpassHashedPassword');
 
     $container->addCompilerPass(new RegisterMatchersPass());
     $container->addCompilerPass(new RegisterNestedMatchersPass());
diff --git a/core/lib/Drupal/Core/Password/passwordInterface.php b/core/lib/Drupal/Core/Password/passwordInterface.php
new file mode 100644
index 0000000..079f0d6
--- /dev/null
+++ b/core/lib/Drupal/Core/Password/passwordInterface.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Password\passwordInterface.
+ *
+ * Secure password hashing functions for user authentication.
+ */
+
+namespace Drupal\Core\Password;
+
+interface passwordInterface {
+
+  /**
+   * Hash a password using a secure hash.
+   *
+   * @param String $password
+   *   A plain-text password.
+   * @param Integer $count_log2
+   *   Optional integer to specify the iteration count. Generally used only during
+   *   mass operations where a value less than the default is needed for speed.
+   *
+   * @return String
+   *   A string containing the hashed password (and a salt), or FALSE on failure.
+   */
+  public function hash($password, $count_log2 = 0);
+
+  /**
+   * Check whether a plain text password matches a stored hashed password.
+   *
+   * Alternative implementations of this function may use other data in the
+   * $account object, for example the uid to look up the hash in a custom table
+   * or remote database.
+   *
+   * @param String $password
+   *   A plain-text password
+   * @param Drupal\user\User
+   *   A user object with at least the fields from the {users} table.
+   *
+   * @return bolean.
+   *   TRUE or FALSE.
+   */
+  public function check($password, $account);
+
+  /**
+   * Check whether a user's hashed password needs to be replaced with a new hash.
+   *
+   * This is typically called during the login process when the plain text
+   * password is available. A new hash is needed when the desired iteration
+   * count has changed through a change in the variable password_count_log2 or
+   * DRUPAL_HASH_COUNT or if the user's password hash was generated in an
+   * update like user_update_7000() (see the Drupal 7 documentation).
+   *
+   * Alternative implementations of this function might use other criteria based
+   * on the fields in $account.
+   *
+   * @param Drupal\user\User
+   *   A user object with at least the fields from the {users} table.
+   *
+   * @return boolean
+   *   TRUE or FALSE.
+   */
+  public function userNeedsNewHash($account);
+
+}
diff --git a/core/lib/Drupal/Core/Password/phpassHashedPassword.php b/core/lib/Drupal/Core/Password/phpassHashedPassword.php
new file mode 100644
index 0000000..41f0590
--- /dev/null
+++ b/core/lib/Drupal/Core/Password/phpassHashedPassword.php
@@ -0,0 +1,255 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Password\phpassHashedPassword.
+ *
+ * Based on the Portable PHP password hashing framework.
+ * @see http://www.openwall.com/phpass/
+ */
+
+namespace Drupal\Core\Password;
+
+class phpassHashedPassword implements passwordInterface {
+  /**
+   * The standard log2 number of iterations for password stretching. This should
+   * increase by 1 every Drupal version in order to counteract increases in the
+   * speed and power of computers available to crack the hashes.
+   */
+  const DRUPAL_HASH_COUNT = 16;
+
+  /**
+   * The minimum allowed log2 number of iterations for password stretching.
+   */
+  const DRUPAL_MIN_HASH_COUNT = 7;
+
+  /**
+   * The maximum allowed log2 number of iterations for password stretching.
+   */
+  const DRUPAL_MAX_HASH_COUNT = 30;
+
+  /**
+   * The expected (and maximum) number of characters in a hashed password.
+   */
+  const DRUPAL_HASH_LENGTH = 55;
+
+  /**
+   * Returns a string for mapping an int to the corresponding base 64 character.
+   */
+  protected function itoa64() {
+    return './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+  }
+
+  /**
+   * Encode bytes into printable base 64 using the *nix standard from crypt().
+   *
+   * @param String $input
+   *   The string containing bytes to encode.
+   * @param Integer $count
+   *   The number of characters (bytes) to encode.
+   *
+   * @return String
+   *   Encoded string
+   */
+  protected function base64Encode($input, $count) {
+    $output = '';
+    $i = 0;
+    $itoa64 = $this->itoa64();
+    do {
+      $value = ord($input[$i++]);
+      $output .= $itoa64[$value & 0x3f];
+      if ($i < $count) {
+        $value |= ord($input[$i]) << 8;
+      }
+      $output .= $itoa64[($value >> 6) & 0x3f];
+      if ($i++ >= $count) {
+        break;
+      }
+      if ($i < $count) {
+        $value |= ord($input[$i]) << 16;
+      }
+      $output .= $itoa64[($value >> 12) & 0x3f];
+      if ($i++ >= $count) {
+        break;
+      }
+      $output .= $itoa64[($value >> 18) & 0x3f];
+    } while ($i < $count);
+
+    return $output;
+  }
+
+  /**
+   * Generates a random base 64-encoded salt prefixed with settings for the hash.
+   *
+   * Proper use of salts may 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.
+   *
+   * @param Integer $count_log2
+   *   Integer that determines the number of iterations used in the hashing
+   *   process. A larger value is more secure, but takes more time to complete.
+   *
+   * @return String
+   *   A 12 character string containing the iteration count and a random salt.
+   */
+  protected function generateSalt($count_log2) {
+    $output = '$S$';
+    // Ensure that $count_log2 is within set bounds.
+    $count_log2 = $this->enforceLog2Boundaries($count_log2);
+    // We encode the final log2 iteration count in base 64.
+    $itoa64 = $this->itoa64();
+    $output .= $itoa64[$count_log2];
+    // 6 bytes is the standard salt for a portable phpass hash.
+    $output .= $this->base64Encode(drupal_random_bytes(6), 6);
+    return $output;
+  }
+
+  /**
+   * Ensures that $count_log2 is within set bounds.
+   *
+   * @param Integer $count_log2
+   *   Integer that determines the number of iterations used in the hashing
+   *   process. A larger value is more secure, but takes more time to complete.
+   *
+   * @return Integer
+   *   Integer within set bounds that is closest to $count_log2.
+   */
+  protected function enforceLog2Boundaries($count_log2) {
+    if ($count_log2 < static::DRUPAL_MIN_HASH_COUNT) {
+      return static::DRUPAL_MIN_HASH_COUNT;
+    }
+    elseif ($count_log2 > static::DRUPAL_MAX_HASH_COUNT) {
+      return static::DRUPAL_MAX_HASH_COUNT;
+    }
+
+    return (int) $count_log2;
+  }
+
+  /**
+   * Hash a password using a secure stretched hash.
+   *
+   * By using a salt and repeated hashing the password is "stretched". Its
+   * security is increased because it becomes much more computationally costly
+   * for an attacker to try to break the hash by brute-force computation of the
+   * hashes of a large number of plain-text words or strings to find a match.
+   *
+   * @param String $algo
+   *   The string name of a hashing algorithm usable by hash(), like 'sha256'.
+   * @param String $password
+   *   The plain-text password to hash.
+   * @param String $setting
+   *   An existing hash or the output of $this->generateSalt().  Must be
+   *   at least 12 characters (the settings and salt).
+   *
+   * @return String
+   *   A string containing the hashed password (and salt) or FALSE on failure.
+   *   The return string will be truncated at DRUPAL_HASH_LENGTH characters max.
+   */
+  protected function crypt($algo, $password, $setting) {
+    // The first 12 characters of an existing hash are its setting string.
+    $setting = substr($setting, 0, 12);
+
+    if ($setting[0] != '$' || $setting[2] != '$') {
+      return FALSE;
+    }
+    $count_log2 = $this->getCountLog2($setting);
+    // Hashes may be imported from elsewhere, so we allow != DRUPAL_HASH_COUNT
+    if ($count_log2 < static::DRUPAL_MIN_HASH_COUNT || $count_log2 > static::DRUPAL_MAX_HASH_COUNT) {
+      return FALSE;
+    }
+    $salt = substr($setting, 4, 8);
+    // Hashes must have an 8 character salt.
+    if (strlen($salt) != 8) {
+      return FALSE;
+    }
+
+    // Convert the base 2 logarithm into an integer.
+    $count = 1 << $count_log2;
+
+    // We rely on the hash() function being available in PHP 5.2+.
+    $hash = hash($algo, $salt . $password, TRUE);
+    do {
+      $hash = hash($algo, $hash . $password, TRUE);
+    } while (--$count);
+
+    $len = strlen($hash);
+    $output =  $setting . $this->base64Encode($hash, $len);
+    // $this->base64Encode() of a 16 byte MD5 will always be 22 characters.
+    // $this->base64Encode() of a 64 byte sha512 will always be 86 characters.
+    $expected = 12 + ceil((8 * $len) / 6);
+    return (strlen($output) == $expected) ? substr($output, 0, static::DRUPAL_HASH_LENGTH) : FALSE;
+  }
+
+  /**
+   * Parse the log2 iteration count from a stored hash or setting string.
+   *
+   * @param String $setting
+   *   An existing hash or the output of $this->generateSalt().  Must be
+   *   at least 12 characters (the settings and salt).
+   */
+  public function getCountLog2($setting) {
+    $itoa64 = $this->itoa64();
+    return strpos($itoa64, $setting[3]);
+  }
+
+  /**
+   * Implements Drupal\Core\Password\passwordInterface::hash().
+   */
+  public function hash($password, $count_log2 = 0) {
+    if (empty($count_log2)) {
+      // Use the standard iteration count.
+      $count_log2 = variable_get('password_count_log2', static::DRUPAL_HASH_COUNT);
+    }
+    return $this->crypt('sha512', $password, $this->generateSalt($count_log2));
+  }
+
+  /**
+   * Implements Drupal\Core\Password\passwordInterface::checkPassword().
+   */
+  public function check($password, $account) {
+    if (substr($account->pass, 0, 2) == 'U$') {
+      // This may be an updated password from user_update_7000(). Such hashes
+      // have 'U' added as the first character and need an extra md5() (see the
+      // Drupal 7 documentation).
+      $stored_hash = substr($account->pass, 1);
+      $password = md5($password);
+    }
+    else {
+      $stored_hash = $account->pass;
+    }
+
+    $type = substr($stored_hash, 0, 3);
+    switch ($type) {
+      case '$S$':
+        // A normal Drupal 7 password using sha512.
+        $hash = $this->crypt('sha512', $password, $stored_hash);
+        break;
+      case '$H$':
+        // phpBB3 uses "$H$" for the same thing as "$P$".
+      case '$P$':
+        // A phpass password generated using md5.  This is an
+        // imported password or from an earlier Drupal version.
+        $hash = $this->crypt('md5', $password, $stored_hash);
+        break;
+      default:
+        return FALSE;
+    }
+    return ($hash && $stored_hash == $hash);
+  }
+
+  /**
+   * Implements Drupal\Core\Password\passwordInterface::userNeedsNewHash().
+   */
+  public function userNeedsNewHash($account) {
+    // Check whether this was an updated password.
+    if ((substr($account->pass, 0, 3) != '$S$') || (strlen($account->pass) != static::DRUPAL_HASH_LENGTH)) {
+      return TRUE;
+    }
+    // Ensure that $count_log2 is within set bounds.
+    $count_log2 = $this->enforceLog2Boundaries(variable_get('password_count_log2', static::DRUPAL_HASH_COUNT));
+    // Check whether the iteration count used differs from the standard number.
+    return ($this->getCountLog2($account->pass) !== $count_log2);
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php b/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php
index eb9c634..3e56e3b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/PasswordHashingTest.php
@@ -22,7 +22,6 @@ public static function getInfo() {
   }
 
   function setUp() {
-    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
     parent::setUp();
   }
 
@@ -30,6 +29,7 @@ function setUp() {
    * Test password hashing.
    */
   function testPasswordHashing() {
+    $password_hasher = drupal_container()->get('password');
     // Set a log2 iteration count that is deliberately out of bounds to test
     // that it is corrected to be within bounds.
     variable_set('password_count_log2', 1);
@@ -37,26 +37,26 @@ function testPasswordHashing() {
     $password = 'baz';
     $account = (object) array('name' => 'foo', 'pass' => md5($password));
     // The md5 password should be flagged as needing an update.
-    $this->assertTrue(user_needs_new_hash($account), 'User with md5 password needs a new hash.');
+    $this->assertTrue($password_hasher->userNeedsNewHash($account), 'User with md5 password needs a new hash.');
     // Re-hash the password.
     $old_hash = $account->pass;
-    $account->pass = user_hash_password($password);
-    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT, 'Re-hashed password has the minimum number of log2 iterations.');
+    $account->pass = $password_hasher->hash($password);
+    $this->assertIdentical($password_hasher->getCountLog2($account->pass), $password_hasher::DRUPAL_MIN_HASH_COUNT, 'Re-hashed password has the minimum number of log2 iterations.');
     $this->assertTrue($account->pass != $old_hash, 'Password hash changed.');
-    $this->assertTrue(user_check_password($password, $account), 'Password check succeeds.');
+    $this->assertTrue($password_hasher->check($password, $account), 'Password check succeeds.');
     // Since the log2 setting hasn't changed and the user has a valid password,
-    // user_needs_new_hash() should return FALSE.
-    $this->assertFalse(user_needs_new_hash($account), 'User does not need a new hash.');
+    // $password_hasher->userNeedsNewHash() should return FALSE.
+    $this->assertFalse($password_hasher->userNeedsNewHash($account), 'User does not need a new hash.');
     // Increment the log2 iteration to MIN + 1.
-    variable_set('password_count_log2', DRUPAL_MIN_HASH_COUNT + 1);
-    $this->assertTrue(user_needs_new_hash($account), 'User needs a new hash after incrementing the log2 count.');
+    variable_set('password_count_log2', $password_hasher::DRUPAL_MIN_HASH_COUNT + 1);
+    $this->assertTrue($password_hasher->userNeedsNewHash($account), 'User needs a new hash after incrementing the log2 count.');
     // Re-hash the password.
     $old_hash = $account->pass;
-    $account->pass = user_hash_password($password);
-    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT + 1, 'Re-hashed password has the correct number of log2 iterations.');
+    $account->pass = $password_hasher->hash($password);
+    $this->assertIdentical($password_hasher->getCountLog2($account->pass), $password_hasher::DRUPAL_MIN_HASH_COUNT + 1, 'Re-hashed password has the correct number of log2 iterations.');
     $this->assertTrue($account->pass != $old_hash, 'Password hash changed again.');
     // Now the hash should be OK.
-    $this->assertFalse(user_needs_new_hash($account), 'Re-hashed password does not need a new hash.');
-    $this->assertTrue(user_check_password($password, $account), 'Password check succeeds with re-hashed password.');
+    $this->assertFalse($password_hasher->userNeedsNewHash($account), 'Re-hashed password does not need a new hash.');
+    $this->assertTrue($password_hasher->check($password, $account), 'Password check succeeds with re-hashed password.');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php
index d1e8aef..2bb96b9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Update/UpdateScriptTest.php
@@ -61,8 +61,7 @@ function testUpdateAccess() {
     // Access the update page as user 1.
     $user1 = user_load(1);
     $user1->pass_raw = user_password();
-    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
-    $user1->pass = user_hash_password(trim($user1->pass_raw));
+    $user1->pass = drupal_container()->get('password')->hash(trim($user1->pass_raw));
     db_query("UPDATE {users} SET pass = :pass WHERE uid = :uid", array(':pass' => $user1->pass, ':uid' => $user1->uid));
     $this->drupalLogin($user1);
     $this->drupalGet($this->update_url, array('external' => TRUE));
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
index 8b51fe0..ee2194c 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserCancelTest.php
@@ -71,10 +71,9 @@ function testUserCancelWithoutPermission() {
   function testUserCancelUid1() {
     // Update uid 1's name and password to we know it.
     $password = user_password();
-    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
     $account = array(
       'name' => 'user1',
-      'pass' => user_hash_password(trim($password)),
+      'pass' => drupal_container()->get('password')->hash(trim($password)),
     );
     // We cannot use $account->save() here, because this would result in the
     // password being hashed again.
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
index 0b6eeba..751046e 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserLoginTest.php
@@ -103,9 +103,9 @@ function testPerUserLoginFloodControl() {
    */
   function testPasswordRehashOnLogin() {
     // Load password hashing API.
-    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
+    $password_hasher = drupal_container()->get('password');
     // Set initial $count_log2 to the default, DRUPAL_HASH_COUNT.
-    variable_set('password_count_log2', DRUPAL_HASH_COUNT);
+    variable_set('password_count_log2', $password_hasher::DRUPAL_HASH_COUNT);
     // Create a new user and authenticate.
     $account = $this->drupalCreateUser(array());
     $password = $account->pass_raw;
@@ -113,14 +113,14 @@ function testPasswordRehashOnLogin() {
     $this->drupalLogout();
     // Load the stored user. The password hash should reflect $count_log2.
     $account = user_load($account->uid);
-    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT);
+    $this->assertIdentical($password_hasher->getCountLog2($account->pass), $password_hasher::DRUPAL_HASH_COUNT);
     // Change $count_log2 and log in again.
-    variable_set('password_count_log2', DRUPAL_HASH_COUNT + 1);
+    variable_set('password_count_log2', $password_hasher::DRUPAL_HASH_COUNT + 1);
     $account->pass_raw = $password;
     $this->drupalLogin($account);
     // Load the stored user, which should have a different password hash now.
     $account = user_load($account->uid, TRUE);
-    $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT + 1);
+    $this->assertIdentical($password_hasher->getCountLog2($account->pass), $password_hasher::DRUPAL_HASH_COUNT + 1);
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 5f340e4..ca47505 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -90,8 +90,7 @@ protected function preSave(EntityInterface $entity) {
     // Update the user password if it has changed.
     if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) {
       // Allow alternate password hashing schemes.
-      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
-      $entity->pass = user_hash_password(trim($entity->pass));
+      $entity->pass = drupal_container()->get('password')->hash(trim($entity->pass));
       // Abort if the hashing failed and returned FALSE.
       if (!$entity->pass) {
         throw new EntityMalformedException('The entity does not have a password.');
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index b7ac23d..cc6a4a8 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -719,8 +719,7 @@ function user_validate_current_pass(&$form, &$form_state) {
     // form values like password_confirm that have their own validation
     // that prevent them from being empty if they are changed.
     if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
-      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
-      $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
+      $current_pass_failed = empty($form_state['values']['current_pass']) || !drupal_container()->get('password')->check($form_state['values']['current_pass'], $account);
       if ($current_pass_failed) {
         form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
         form_set_error($key);
@@ -1733,14 +1732,13 @@ function user_authenticate($name, $password) {
   if (!empty($name) && !empty($password)) {
     $account = user_load_by_name($name);
     if ($account) {
-      // Allow alternate password hashing schemes.
-      require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'core/includes/password.inc');
-      if (user_check_password($password, $account)) {
+      $password_hasher = drupal_container()->get('password');
+      if ($password_hasher->check($password, $account)) {
         // Successful authentication.
         $uid = $account->uid;
 
         // Update user to new password scheme if needed.
-        if (user_needs_new_hash($account)) {
+        if ($password_hasher->userNeedsNewHash($account)) {
           $account->pass = $password;
           $account->save();
         }
diff --git a/core/scripts/generate-d7-content.sh b/core/scripts/generate-d7-content.sh
index acfc1a3..3705fe6 100644
--- a/core/scripts/generate-d7-content.sh
+++ b/core/scripts/generate-d7-content.sh
@@ -30,7 +30,6 @@
 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
 // Enable requested modules
-require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
 include_once './modules/system/system.admin.inc';
 $form = system_modules();
 foreach ($modules_to_enable as $module) {
@@ -45,12 +44,13 @@
 
 // Create six users
 $query = db_insert('users')->fields(array('uid', 'name', 'pass', 'mail', 'status', 'created', 'access'));
+$password_hasher = drupal_container()->get('password');
 for ($i = 0; $i < 6; $i++) {
   $name = "test user $i";
   $pass = md5("test PassW0rd $i !(.)");
   $mail = "test$i@example.com";
   $now = mktime(0, 0, 0, 1, $i + 1, 2010);
-  $query->values(array(db_next_id(), $name, user_hash_password($pass), $mail, 1, $now, $now));
+  $query->values(array(db_next_id(), $name, $password_hasher->hash($pass), $mail, 1, $now, $now));
 }
 $query->execute();
 
diff --git a/core/scripts/password-hash.sh b/core/scripts/password-hash.sh
index 8109af4..b91cd41 100755
--- a/core/scripts/password-hash.sh
+++ b/core/scripts/password-hash.sh
@@ -81,11 +81,12 @@
 chdir('..');
 define('DRUPAL_ROOT', getcwd());
 
-include_once DRUPAL_ROOT . '/core/includes/password.inc';
 include_once DRUPAL_ROOT . '/core/includes/bootstrap.inc';
 
+$password_hasher = drupal_container()->get('password');
+
 foreach ($passwords as $password) {
-  print("\npassword: $password \t\thash: ". user_hash_password($password) ."\n");
+  print("\npassword: $password \t\thash: ". $password_hasher->hash($password) ."\n");
 }
 print("\n");
 
