user10727666
user10727666

Reputation: 37

Hash function not returning the same output for identical input

I am currently working on implementing a website that allows a user to (fictionally) buy and sell stocks. This is problem set 9 in Harvards' CS50 computer science course. My program compiles, functions and passes all checks. However, the past few days I've been stuck trying to implement a password change option.

On the password change page, I prompt the user to input their old password. Then, the user has to input their desired new password. Finally, the user has to confirm their new password once more.

However, my hashing function seems to output a different hash when a user inputs their old password, than it did when they registered with this password. This causes my comparison check between the hashed password in the database and the user input to always return false.

Below is the python code for the implementation of the password change. Below it is the html code for the actual page on which the user can change their password.

@app.route("/change", methods=["GET", "POST"])
@login_required
# PERSONAL TOUCH: <Allows user to change their password>
def change():
"""Allows user to change their password"""

if request.method == "GET":
    return render_template("change.html")

else:

    # Returns an error if Password is left blank
    if not request.form.get("originalpassword"):
        return apology("User must submit their original Password.", 400)

    elif not request.form.get("newpassword"):
        return apology("User must submit a new Password.", 400)

    elif not request.form.get("newconfirmation"):
        return apology("User must confirm their new Password", 400)

    # Hashes the Password
    Password = request.form.get("originalpassword")
    print("GIVEN PASSWORD: ", Password)
    HashedPassword = generate_password_hash(Password, method='pbkdf2:sha256', salt_length=8)

    # Returns an error if the user typed in a non-valid original password
    OldHashedPassword = db.execute("SELECT hash FROM users WHERE id = :id", id=session["user_id"])
    Old_HPW = OldHashedPassword[0]["hash"]

    print("given hash: ", HashedPassword)
    print("actual hash: ", Old_HPW)

    print("=====\n",OldHashedPassword,"\n=====\n")

    if not Old_HPW == HashedPassword:
        return apology("Submitted password is not valid.")

    # Returns an error if Password and Confirmation are not identical
    if not request.form.get("newpassword") == request.form.get("confirmpassword"):
        return apology("New Password and Confirmation must be identical.", 400)

    # Hashes the new Password
    NewPassword = request.form.get("newpassword")
    NewHashedPassword = generate_password_hash(NewPassword, method='pbkdf2:sha256', salt_length=8)

    # Insert the new Password into the database
    insertPW = db.execute("INSERT INTO users (hash) VALUES(:hash)", hash=NewHashedPassword)

    return redirect("/")

And the HTML code:

HTML Code

I did include a few print statements in order to debug. I registered a new account with username 'q', and password 'q'. Then, I attempted to change the password into 'qq'. During registration, the input 'q' resulted in the following hash:

pbkdf2:sha256:50000$sBxqbmza$e35dd4e61eb186af014e5e1ce3b73450b1361baabdd2f5f4559ad83ef0d5b45b

However, when I input 'q' into the 'original password' form field, the generate_password__hash function returns the hash:

pbkdf2:sha256:50000$iAjKAPM1$f7644f34f21864062efa2f3e3f3ea0a89a8a3391a0223c1a62fa7cbaab012a71

The values printed by the print statements are:

GIVEN PASSWORD: q

given hash:

pbkdf2:sha256:50000$iAjKAPM1$f7644f34f21864062efa2f3e3f3ea0a89a8a3391a0223c1a62fa7cbaab012a71

actual hash:

pbkdf2:sha256:50000$sBxqbmza$e35dd4e61eb186af014e5e1ce3b73450b1361baabdd2f5f4559ad83ef0d5b45b

Apologies for the very long post. Does anyone have an idea what is causing the hash function to output a different hash value for a (seemingly) similar input?

Thanks!

EDIT: this new code seems to have solved the problem:

NEW CODE

Upvotes: 2

Views: 2169

Answers (1)

kelalaka
kelalaka

Reputation: 5636

As pointed in this answer some libraries generate the salt itself, you don't supply one. In this library, you can only supply the salt size. From the doc

werkzeug.security.generate_password_hash(password, method='pbkdf2:sha256', salt_length=8)

Hash a password with the given method and salt with a string of the given length. The format of the string returned includes the method that was used so that check_password_hash() can check the hash.

The format for the hashed string looks like this:

method$salt$hash

If you want to store the salt, parse it from the result. But this library has another function to check/verify the passwords;

werkzeug.security.check_password_hash(pwhash, password)

check a password against a given salted and hashed password value.

So;

In sign-up login, or to change passwords use;

generate_password_hash

To verify the passwords, use;

check_password_hash

Upvotes: 1

Related Questions