1

I am storing a username and an encrypted password in a mysql database. For testing only, I am also storing the password in an unencrypted form in the database as well.

In the following code, I get the hashed password and the unencrypted password from the database. I then encrypt the unencrypted password.

The given password does not pass the password verification test for the stored hash or the new hash.

The stored password does pass the password verification test for both the stored hash and the new hash.

The call to strcmp says that the stored password and the given password are equal.

How could this be?

[edit] : I am passing in $password from user input on the web page.

// get hashed password from database
$sql = "SELECT member_password FROM member WHERE member_username=:username;";
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username);
$stmt->execute();
$hash = $stmt->fetch(PDO::FETCH_ASSOC);
$hash = $hash["member_password"];

// get unencrypated password from database
$sql = "SELECT member_unencrypted FROM member WHERE member_username=:username;";
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam("username", $username);
$stmt->execute();
$unencrypted = $stmt->fetch(PDO::FETCH_ASSOC);
$unencrypted = $unencrypted["member_unencrypted"];

// encrypt the unencrypted password that was retrieved from the database
$encrypted = password_hash($unencrypted, PASSWORD_DEFAULT);

// given password does not pass the new hash per this test
if(password_verify($password, $encrypted))
  echo '<br>given password passed new hash';
else 
  echo '<br>given password did not pass new hash';

// stored password does pass the new hash per this test
if(password_verify($unencrypted, $encrypted))
  echo '<br>stored password passed new hash';
else
  echo '<br>stored password did not pass new hash';

// given password does not pass the stored hash per this test.
if(password_verify($password, $hash)){
  echo '<br>given password passed stored hash';
else
  echo '<br>given password did not pass stored hash';

// stored password does pass the stored hash per this test.
if(password_verify($unencrypted, $hash))
  echo '<br>stored password passed stored hash';
else
  echo '<br>stored password did not pass stored hash';

// stored and given passwords are equal per this test.
if(strcmp($unencrypted, $password)) 
  echo '<br>stored and given passwords are equal';
else
  echo '<br>stored and given passwords are not equal';

Output:

given password did not pass new hash
stored password passed new hash
given password did not pass stored hash
stored password passed stored hash
stored and given passwords are equal
  • 1
    What is the structure of the column used to store the hashes? – Mike Sep 25 '14 at 04:16
  • 1
    Also, I'm not sure if you're doing it simply because of testing but you can easily combine the two queries. And when selecting a single value you should use `fetchColumn()` instead of things like `$hash = $stmt->fetch(PDO::FETCH_ASSOC); $hash = $hash["member_password"];` – Mike Sep 25 '14 at 04:19
  • Thanks for the tips Mike! It has been a while since I have done much sql, and that is useful. The hashes are stored in a VARCHAR(255). – brucebolick Sep 26 '14 at 03:36
  • 1
    Hmm then I guess that rules out the hash being truncated – Mike Sep 26 '14 at 18:19

1 Answers1

2

It is not clear from your question where the variable $password is coming from, and if it contains the same text as the one stored in the database.

If you make such tests you must be aware that the function password_hash() will generate a unique salt and includes it in the resulting hash. For verification you need this salt (and other parameters) to get a comparable hash-value. That means the hash will be different each time and if you call password_hash() twice, you end up with different salts and non-compareable hashes.

I tried to explain the hash format in another answer.

[edit from Bruce: see comments for the answer]

Community
  • 1
  • 1
martinstoeckli
  • 23,430
  • 6
  • 56
  • 87
  • Thanks for the response! I am getting $password from $_GET. What confuses me is that the stored, unencrypted password works with the stored hash and a brand new hash. The password that I pass in fails against each of the hashes. Then, when I compare the stored password and the one that I pass in, it says that they are equal. – brucebolick Sep 25 '14 at 22:18
  • 1
    @brucebolick - Do you have a special encoding on your HTML page, is it UTF-8? And what's the charset of your database? If you are unsure about the encoding you may have a look at this small [article](http://www.martinstoeckli.ch/php/php.html#utf8). Also check for leading/trailing whitespaces. – martinstoeckli Sep 26 '14 at 08:41
  • 1
    @brucebolick - What happens when you set the variable `$password = 'yourpassword';` hardcoded? – martinstoeckli Sep 26 '14 at 09:13
  • Hi @martinstoeckli - latin1_swedish_ci is my database's collation. Is it also the charset? (Sorry, I'm really a rookie.) It turns out that if I set $password = 'asdf' (which is my test password), it works! It also works when I set $password = $unencrypted (which is no surprise). I don't think I have special encoding in my html page. I am passing the password through the query string: Request URL:http://localhost/project_001/oauth2-server/authorize.php?username=asdf&password=%20asdf . – brucebolick Sep 27 '14 at 03:50
  • I clicked on the link that I sent to you and took a closer look at it. I noticed that there was an encoded space character '%20' in front of my password. Somehow, this messed up the hash but still passed the strcmp test. I found the place in my code where I was hard-coding a space into the query string, and removed it. This fixed my problem. Thanks a bunch for talking me through it, Martin! – brucebolick Sep 27 '14 at 04:04