Search code examples
phphashsalt-cryptographycrypt

Crypt returning same hash for two different (similar) passwords


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.";
            }
        }
    }
}

?>

Solution

  • 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