Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/util/password/PhabricatorPasswordHasher.php
Show First 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | /* -( Implementing a Hasher )---------------------------------------------- */ | ||||
* | * | ||||
* @param PhutilOpaqueEnvelope Text to be hashed. | * @param PhutilOpaqueEnvelope Text to be hashed. | ||||
* @return PhutilOpaqueEnvelope Hashed text. | * @return PhutilOpaqueEnvelope Hashed text. | ||||
* @task hasher | * @task hasher | ||||
*/ | */ | ||||
abstract protected function getPasswordHash(PhutilOpaqueEnvelope $envelope); | abstract protected function getPasswordHash(PhutilOpaqueEnvelope $envelope); | ||||
/** | |||||
* Verify that a password matches a hash. | |||||
* | |||||
* The default implementation checks for equality; if a hasher embeds salt in | |||||
* hashes it should override this method and perform a salt-aware comparison. | |||||
* | |||||
* @param PhutilOpaqueEnvelope Password to compare. | |||||
* @param PhutilOpaqueEnvelope Bare password hash. | |||||
* @return bool True if the passwords match. | |||||
* @task hasher | |||||
*/ | |||||
protected function verifyPassword( | |||||
PhutilOpaqueEnvelope $password, | |||||
PhutilOpaqueEnvelope $hash) { | |||||
$actual_hash = $this->getPasswordHash($password)->openEnvelope(); | |||||
$expect_hash = $hash->openEnvelope(); | |||||
return ($actual_hash === $expect_hash); | |||||
} | |||||
epriestley: bcrypt has salt embedded in the hash, so we need to be slightly more clever here. | |||||
/* -( Using Hashers )------------------------------------------------------ */ | /* -( Using Hashers )------------------------------------------------------ */ | ||||
/** | /** | ||||
* Get the hash of a password for storage. | * Get the hash of a password for storage. | ||||
* | * | ||||
* @param PhutilOpaqueEnvelope Password text. | * @param PhutilOpaqueEnvelope Password text. | ||||
* @return PhutilOpaqueEnvelope Hashed text. | * @return PhutilOpaqueEnvelope Hashed text. | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | /* -( Using Hashers )------------------------------------------------------ */ | ||||
/** | /** | ||||
* Get the best (strongest) available hasher. | * Get the best (strongest) available hasher. | ||||
* | * | ||||
* @return PhabicatorPasswordHasher Best hasher. | * @return PhabicatorPasswordHasher Best hasher. | ||||
* @task hashing | * @task hashing | ||||
*/ | */ | ||||
public static function getBestHasher() { | public static function getBestHasher() { | ||||
$hashers = self::getAllUsableHashers(); | $hashers = self::getAllUsableHashers(); | ||||
msort($hashers, 'getStrength'); | $hashers = msort($hashers, 'getStrength'); | ||||
Not Done Inline ActionsFixes a bug which is only relevant now that we have two hashers. epriestley: Fixes a bug which is only relevant now that we have two hashers. | |||||
$hasher = last($hashers); | $hasher = last($hashers); | ||||
if (!$hasher) { | if (!$hasher) { | ||||
throw new PhabricatorPasswordHasherUnavailableException( | throw new PhabricatorPasswordHasherUnavailableException( | ||||
pht( | pht( | ||||
'There are no password hashers available which are usable for '. | 'There are no password hashers available which are usable for '. | ||||
'new passwords.')); | 'new passwords.')); | ||||
} | } | ||||
Show All 39 Lines | /* -( Using Hashers )------------------------------------------------------ */ | ||||
* Test if a password is using an weaker hash than the strongest available | * Test if a password is using an weaker hash than the strongest available | ||||
* hash. This can be used to prompt users to upgrade, or automatically upgrade | * hash. This can be used to prompt users to upgrade, or automatically upgrade | ||||
* on login. | * on login. | ||||
* | * | ||||
* @return bool True to indicate that rehashing this password will improve | * @return bool True to indicate that rehashing this password will improve | ||||
* the hash strength. | * the hash strength. | ||||
* @task hashing | * @task hashing | ||||
*/ | */ | ||||
public static function canHashBeUpgraded(PhutilOpaqueEnvelope $hash) { | public static function canUpgradeHash(PhutilOpaqueEnvelope $hash) { | ||||
$current_hasher = self::getHasherForHash($hash); | $current_hasher = self::getHasherForHash($hash); | ||||
$best_hasher = self::getBestHasher(); | $best_hasher = self::getBestHasher(); | ||||
return ($current_hasher->getHashName() != $best_hasher->getHashName()); | return ($current_hasher->getHashName() != $best_hasher->getHashName()); | ||||
} | } | ||||
/** | /** | ||||
Show All 19 Lines | /* -( Using Hashers )------------------------------------------------------ */ | ||||
* @return bool True if the passwords match. | * @return bool True if the passwords match. | ||||
* @task hashing | * @task hashing | ||||
*/ | */ | ||||
public static function comparePassword( | public static function comparePassword( | ||||
PhutilOpaqueEnvelope $password, | PhutilOpaqueEnvelope $password, | ||||
PhutilOpaqueEnvelope $hash) { | PhutilOpaqueEnvelope $hash) { | ||||
$hasher = self::getHasherForHash($hash); | $hasher = self::getHasherForHash($hash); | ||||
$password_hash = $hasher->getPasswordHashForStorage($password); | $parts = self::parseHashFromStorage($hash); | ||||
return ($password_hash->openEnvelope() == $hash->openEnvelope()); | return $hasher->verifyPassword($password, $parts['hash']); | ||||
} | } | ||||
} | } |
bcrypt has salt embedded in the hash, so we need to be slightly more clever here.