Crypt returning same hash for two different (similar) passwords
Asked Answered
A

1

5

I have an issue using crypt() where if a user has a password (password1 in this example), and they change it to password2, the hashing returns the same result. You can test that here: OLD LINK Type password1 as current password, and password2 as new password and confirm password, you will see the results. If a completely non similar password is entered there is no problem. I understand there are other ways to go about hashing passwords etc. I'm more curious than anything. My code is below:

<?php

$oldpassword="password1";

echo "<form method=\"post\">
<p>Enter Current Password: <input type=\"password\" name=\"currentpassword\" /></p>
<p>Enter New Password: <input type=\"password\" name=\"password\" /></p>
<p>Confirm New Password: <input type=\"password\" name=\"confirmpassword\" /></p>
<p><input type=\"submit\" value=\"Change Password\"></p>
</form>";

$user_id = $_SESSION['user_id'];
$pass=$_POST['password'];
$salt = 'xxxxx';
$currentpassword = crypt($_POST['currentpassword'], $salt);
$oldpassword = crypt($oldpassword, $salt);
if(isset($_POST['password'])) {
    if ($currentpassword !== $oldpassword) {
        echo "The password you entered for current password does not match our records.";
    }
    else {
        if ($_POST['password'] && $_POST['confirmpassword']) {
            if ($_POST['password'] == $_POST['confirmpassword']) {
            $hash = crypt($pass, $salt);
                if ($hash == $currentpassword) {
                    echo "Current Password:&nbsp;";
                    var_dump($_POST['currentpassword']);
                    echo "<br/>";
                    echo "New Password:&nbsp;";
                    var_dump($_POST['password']);
                    echo "<br/>";
                    echo "New Hash:&nbsp";
                    var_dump($hash);
                    echo "<br/>";
                    echo "Current Password Hash:&nbsp";
                    var_dump($currentpassword);
                    echo "<br/>";
                    echo "<hr/>";
                    echo "Your new password cannot be the same as your current password.";
                }
                else {
                    echo "Your password has been changed successfully<br/>";
                }
            } else {
                echo "Your passwords do not match. Please try again.";
            }
        }
    }
}

?>
Amphitheater answered 22/2, 2013 at 22:40 Comment(12)
If you're using bcrypt, keep in mind the maximum password length is 55 characters. Are the passwords you're trying longer than this?Countermeasure
Which crypt() algorithm are you using?Grussing
@TML, Something that seems to limit the string length to 7 characters. And Kevin, you shouldn't try to write your own code for this. Use password_hash or the Github compatibility package (in the comments) which is forward-compatible with it for PHP < 5.5Countermeasure
@Countermeasure Unfortunately my server is only at PHP 5.4. I really like the looks of password_hash. I've since developed something a little bit different using the following: $salt = $username.$email_address; $hash = sha1($pass.$salt); Is this somewhat sufficient?Amphitheater
Yes, password_hash() was what I was going to suggest as well; my bet is that DES is being used.Grussing
I just tested this code on my server and it looks like you are literally using xxxxx as the salt. That is the problem.Woolridge
@KevinO'Brien that's why I mentioned the Github link in the comments. It's compatible with PHP >= 5.3.7Countermeasure
There's a github project that will provide password_hash() as a userland package at php.net/password_hash in the commentsGrussing
I used a different string on the actual page I used this on, just replaced it with xxxxx for the example.Amphitheater
@KevinO'Brien no, that is not a good salt. Salts should be randomly generated and unique for each hash. Which is another reason I said you shouldn't try to write your own code for this when it's already available in a much more secure form.Countermeasure
I will follow your advice for using password_hash(). Could you explain how generating a random salt where it would still return the same salt every time it is encrypted / hashed?Amphitheater
@KevinO'Brien, I'm not sure what you mean. If it's random, the salt won't be the same when you re-encrypt. You want it to be different every time. When using bcrypt, the salt is stored right in the hash, so you don't need to regenerate it to validate a password.Countermeasure
C
13

To use crypt you have to provide proper salt. Every algorithm has its own salt format. My guess is that you are using few random chars as salt, this does no match any advanced algo, so php cuts down your salt to first 2 character and fallbacks to basic DES algorithm. DES algorithm hashes up to 8 characters and both password1 and password2 are 9 character long, so only password is used from both, hence same hash.

Solution: use proper salt format for strongest available algorithm, generate random salt for each password

Recommended solution: https://github.com/ircmaxell/password_compat (for php 5.3.7 - 5.4.x) and after switching to php 5.5: http://php.net/password_hash

Conceptionconceptual answered 22/2, 2013 at 23:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.