-
Notifications
You must be signed in to change notification settings - Fork 28
Adds support for something better than md5 hashes. #177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -171,6 +171,34 @@ class GalleryUser extends GalleryEntity { | |
| */ | ||
| function isCorrectPassword($password) { | ||
| $valid = $this->getHashedPassword(); | ||
|
|
||
| /* Match crypt methods, which start with $x$ */ | ||
| if (isset($valid[0]) && $valid[0] === '$') { | ||
| if (strlen($valid) == 34 && (strpos($valid, '$P$') === 0 || strpos($valid, '$H$') === 0)) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, did not realised gallery2 had such an old version it didn't support the |
||
| GalleryCoreApi::requireOnce('lib/phpass/PasswordHash.inc'); | ||
| $hashGenerator = new PasswordHash(10, true); | ||
| return $hashGenerator->CheckPassword($password, $valid); | ||
| } | ||
|
|
||
| if (function_exists('password_verify')) { | ||
| if (preg_match('/^\$(2[axy]|argon2i|argon2id)\$/', $valid)) { | ||
| return password_verify($password, $valid); | ||
| } | ||
| } | ||
|
|
||
| $hash = crypt($password, $valid); | ||
| if (function_exists('hash_equals')) { | ||
| if (hash_equals($valid, $hash)) { | ||
| return true; | ||
| } | ||
| } else { | ||
| if ($hash === $valid) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| $salt = substr($valid, 0, 4); | ||
| /* Support both old (G1 thru 1.4.0; G2 thru alpha-4) and new password schemes: */ | ||
| $guess = (strlen($valid) == 32) ? md5($password) : ($salt . md5($salt . $password)); | ||
|
|
@@ -203,7 +231,7 @@ class GalleryUser extends GalleryEntity { | |
| * @param string $newPassword a plaintext password | ||
| */ | ||
| function changePassword($newPassword) { | ||
| $this->setHashedPassword(GalleryUtilities::md5Salt($newPassword)); | ||
| $this->setHashedPassword(GalleryUtilities::hashPassword($newPassword)); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are a handful of uses of
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, must of missed these. |
||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1290,9 +1290,80 @@ class GalleryUtilities { | |
| * @return boolean true if correct | ||
| */ | ||
| static function isCorrectPassword($guess, $hashedPassword) { | ||
| /* Match crypt methods, which start with $x$ */ | ||
| if (isset($hashedPassword[0]) && $hashedPassword[0] === '$') { | ||
| if (strlen($hashedPassword) == 34 && (strpos($hashedPassword, '$P$') === 0 || strpos($hashedPassword, '$H$') === 0)) { | ||
| GalleryCoreApi::requireOnce('lib/phpass/PasswordHash.inc'); | ||
| $hashGenerator = new PasswordHash(10, true); | ||
| return $hashGenerator->CheckPassword($guess, $hashedPassword); | ||
| } | ||
|
|
||
| if (function_exists('password_verify')) { | ||
| if (preg_match('/^\$(2[axy]|argon2i|argon2id)\$/', $hashedPassword)) { | ||
| return password_verify($guess, $hashedPassword); | ||
| } | ||
| } | ||
|
|
||
| $hash = crypt($guess, $hashedPassword); | ||
| if (function_exists('hash_equals')) { | ||
| if (hash_equals($hashedPassword, $hash)) { | ||
| return true; | ||
| } | ||
| } else { | ||
| if ($hash === $hashedPassword) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| return (GalleryUtilities::md5Salt($guess, $hashedPassword) === $hashedPassword); | ||
| } | ||
|
|
||
| /** | ||
| * Create a hashed password using the configured hashing algorithm. | ||
| * @param string $password plaintext password | ||
| * @return string hashed password | ||
| */ | ||
| static function hashPassword($password) { | ||
| global $gallery; | ||
| if ($gallery->isConfig('passwordHashMethod')) { | ||
|
gregstoll marked this conversation as resolved.
|
||
| $method = $gallery->getConfig('passwordHashMethod'); | ||
| } | ||
| if (empty($method)) { | ||
| $method = 'salted md5'; | ||
| } | ||
|
|
||
| if ($method == 'phpass') { | ||
| GalleryCoreApi::requireOnce('lib/phpass/PasswordHash.inc'); | ||
| $hashGenerator = new PasswordHash(10, true); | ||
| return $hashGenerator->HashPassword($password); | ||
| } else if ($method == 'bcrypt') { | ||
| if (function_exists('password_hash')) { | ||
| return password_hash($password, PASSWORD_BCRYPT); | ||
| } else { | ||
| $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
| $salt = '$2y$10$'; | ||
| for ($i = 0; $i < 22; $i++) { | ||
| $salt .= $chars[mt_rand(0, 63)]; | ||
|
gregstoll marked this conversation as resolved.
|
||
| } | ||
| return crypt($password, $salt); | ||
| } | ||
| } else if ($method == 'crypt-sha256') { | ||
| $salt = '$5$rounds=5000$' . substr(md5(mt_rand()), 0, 16) . '$'; | ||
| return crypt($password, $salt); | ||
| } else if ($method == 'crypt-sha512') { | ||
| $salt = '$6$rounds=5000$' . substr(md5(mt_rand()), 0, 16) . '$'; | ||
| return crypt($password, $salt); | ||
| } else if ($method == 'argon2i' && defined('PASSWORD_ARGON2I')) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the user specifies "argon2i" but |
||
| return password_hash($password, PASSWORD_ARGON2I); | ||
| } else if ($method == 'argon2id' && defined('PASSWORD_ARGON2ID')) { | ||
| return password_hash($password, PASSWORD_ARGON2ID); | ||
| } | ||
|
|
||
| return GalleryUtilities::md5Salt($password); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to above, would be nice to check that
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would make more sense to add this somewhere where the config file is loaded and validated then. it can check for a typo and error, and validate if argon2 is selected that they do exist. Otherwise the admin would never know about it until a password was changed. |
||
| } | ||
|
|
||
| /** | ||
| * Verify that the API provided is compatible with the API that we require. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(thanks for the documentation here!)
This is...a lot of options to offer, and I doubt most people (myself included!) are going to have a good idea of the tradeoffs between the choices. Obviously we need to keep "salted md5" for compatibility, but could we just pick one or two of the most secure other options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, we could always require users to only use what we allow them to use. but I do not know their systems, and what they need to use, why does gallery2 support phpass? why shouldn't bcrypt be supported, most people believe this is secure, why use or not use argon2*, it is believed to be more secure than bcrypt, but bcrypt and argon2 are not fips compliant. I have no idea what other software people would use with this, and what password hashing method they would use. I would not want to limit their options when it's trivial to implement.