Page MenuHomePhabricator

D8271.id19683.diff
No OneTemporary

D8271.id19683.diff

Index: src/infrastructure/util/password/PhabricatorBcryptPasswordHasher.php
===================================================================
--- src/infrastructure/util/password/PhabricatorBcryptPasswordHasher.php
+++ src/infrastructure/util/password/PhabricatorBcryptPasswordHasher.php
@@ -34,12 +34,8 @@
protected function getPasswordHash(PhutilOpaqueEnvelope $envelope) {
$raw_input = $envelope->openEnvelope();
- // NOTE: The default cost is "10", but my laptop can do a hash of cost
- // "12" in about 300ms. Since server hardware is often virtualized or old,
- // just split the difference.
-
$options = array(
- 'cost' => 11,
+ 'cost' => $this->getBcryptCost(),
);
$raw_hash = password_hash($raw_input, CRYPT_BLOWFISH, $options);
@@ -53,4 +49,27 @@
return password_verify($password->openEnvelope(), $hash->openEnvelope());
}
+ protected function canUpgradeInternalHash(PhutilOpaqueEnvelope $hash) {
+ $info = password_get_info($hash->openEnvelope());
+
+ // NOTE: If the costs don't match -- even if the new cost is lower than
+ // the old cost -- count this as an upgrade. This allows costs to be
+ // adjusted down and hashing to be migrated toward the new cost if costs
+ // are ever configured too high for some reason.
+
+ $cost = idx($info['options'], 'cost');
+ if ($cost != $this->getBcryptCost()) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private function getBcryptCost() {
+ // NOTE: The default cost is "10", but my laptop can do a hash of cost
+ // "12" in about 300ms. Since server hardware is often virtualized or old,
+ // just split the difference.
+ return 11;
+ }
+
}
Index: src/infrastructure/util/password/PhabricatorPasswordHasher.php
===================================================================
--- src/infrastructure/util/password/PhabricatorPasswordHasher.php
+++ src/infrastructure/util/password/PhabricatorPasswordHasher.php
@@ -130,6 +130,24 @@
}
+ /**
+ * Check if an existing hash created by this algorithm is upgradeable.
+ *
+ * The default implementation returns `false`. However, hash algorithms which
+ * have (for example) an internal cost function may be able to upgrade an
+ * existing hash to a stronger one with a higher cost.
+ *
+ * @param PhutilOpaqueEnvelope Bare hash.
+ * @return bool True if the hash can be upgraded without
+ * changing the algorithm (for example, to a
+ * higher cost).
+ * @task hasher
+ */
+ protected function canUpgradeInternalHash(PhutilOpaqueEnvelope $hash) {
+ return false;
+ }
+
+
/* -( Using Hashers )------------------------------------------------------ */
@@ -318,7 +336,19 @@
$current_hasher = self::getHasherForHash($hash);
$best_hasher = self::getBestHasher();
- return ($current_hasher->getHashName() != $best_hasher->getHashName());
+ if ($current_hasher->getHashName() != $best_hasher->getHashName()) {
+ // If the algorithm isn't the best one, we can upgrade.
+ return true;
+ }
+
+ $info = self::parseHashFromStorage($hash);
+ if ($current_hasher->canUpgradeInternalHash($info['hash'])) {
+ // If the algorithm provides an internal upgrade, we can also upgrade.
+ return true;
+ }
+
+ // Already on the best algorithm with the best settings.
+ return false;
}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 30, 10:02 PM (21 h, 1 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6810617
Default Alt Text
D8271.id19683.diff (3 KB)

Event Timeline