0

Cryptography

Recently I have been doing a lot of research into cryptography. It led me to discovering that, not only do we have salt, we also have pepper (yes I really only just found out about pepper).

Hashing passwords

This all started when I inherited a project in which passwords were not hashed. Even as a n00b I know that this is just silly.
I have a basic understanding of hashing, but what I knew was apparently outdated.

Original solution

My original hashes and salts were achieved by:

  1. Getting the user's password
  2. Combining it with a salt
  3. Hashing it using MD5
  4. Storing both, the salt and the hash in a table

This worked well, but I am leaning towards using a better technique

New technique

The new way I wish to try is by using PHP's password_hash and password_verify.

Having created a quick test, I can see that I can return a true value with password_verify on a given hash. The one thing that is puzzling me is where the salt comes in?
On the documentation I can see that there was an option to specify a salt in the options array but that is deprecated as of PHP 7.0.

My attempt

I have created some code (untested) just to demonstrate. See below code.

<?php
$pepper = "myPepper";

function register($username, $password)
{
    // add the pepper
    $password .= $pepper;
    // hash the password
    $hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 10]);

    // insert into table
    $query = $mysqli->prepare("INSERT INTO users(username, password) VALUES(?, ?)");
    $query->bind_param("ss", $username, $hash);

    // check the success
    if ($query->execute())
        return true;
    else
        return false;
}

function login($username, $password)
{
    // create the query
    $query = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
    $query->bind_param("s", $username);

    // check if successful
    if ($query->execute())
    {
        // get password from the database
        $query->store_result();
        $query->bind_result($hash);
        $query->fetch();

        // verify the passwords are the same
        if (password_verify($password . $pepper, $hash))
            return true;
        else
            return false;
    }
}
?>

register function

Both these functions are very basic as I just wanted to show a point.

This function takes some parameters (in this case username and password and adds them to the database.
Now, I know how to add my pepper to the password as that is a simple concatenation, but the salt is randomly generated but never returned meaning I have no idea what it is.

login function

Again, very basic in what it does.

Since I have not used password_verify before I am not entirely sure I know the best approach to use to attain the user's password.

With my old login scripts they looked something like this:

function login($username, $password)
{
    // create the query
    $query = $mysqli->prepare("SELECT salt FROM users WHERE username = ? AND password = ?");
    $pass = md5($password);
    $query->bind_param("ss", $username, $password);

    // check if successful
    if ($query->execute())
    {
        $query->store_result(); // store result to gain access to num_rows

        // verify if password and usernames match
        if ($query->num_rows == 1)
            return true;
        else
            return false;
    }
}

Where I would just hash the password and pass it as a parameter into the SQL query.
With bcrypt I have to withdraw the password from table and then use it in another query. (At least that is what I believe I have to do currently).

Finally, the question part

Disclaimer

I apologise if I offended anyone with my lack of knowledge and / or my poor explanation of my knowledge.

Your help

I crave knowledge. So what I don't know, I want to know. (Obviously to an extent, I like to learn about computers and systems and programming etc).

Password hashing is essential these days and getting it right is very important and that is why I am writing this essay question.

Question(s)

  1. Is my understanding of bcrypt correct?
  2. Does it really not store a salt?
  3. In my basic example of login and register, have I implemented password_hash and password_verify?

Update 1

Following all the comments, I would just like to post this update.

As stated above I like to learn, so when I came across this function it started confusing me because I didn't know what was happening.

I am going to post some examples to try and effectively get my confusion across to everyone.

Let's take this script for example:

<?php
// everything below is hard coded for simplicity (would actually be extracted from a database)
$password = "myPassword"; // the password from the database
$salt = "mySalt"; // I have hard coded this for simplicity
$hash = md5($salt . $password);

// check login status
if (md5($salt . $_POST["password"]) == $hash)
    return true;
else
    return false;
?>

In this example I understand how the hashing works.

I am storing the password with a salt and hashing it. Then I am checking the posted password with the salt and hashing that. If the two match then I succeed with the login, otherwise the login has failed.

Now, let's take the following example.

<?php
// everything below is hard coded for simplicity (would actually be extracted from a database)
$password = "myPassword"; // the password from the database
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost" => 10]); // salt is taken care of

// check login status
// again I am keeping this so simple (it might not work per se but I just want to learn about the functions)
if (password_verify($_POST["password"], $hash))
    return true;
else
    return false;
?>

Confusion

I start getting confused when I am running password_verify.

I understand that the salt is taken care of by default in password_hash, but in the first example I know the salt and so I can perform a hash with the posted password to check if they match.

Why, then, does password_verify succeed in verifying the posted password without me having given it the salt?
Surely a salt is designed to make each password unique but somehow password_verify will succeed. I have used var_dump to dump the hash made from password_hash and it changes upon refresh. This really is where the confusion comes from. If the hash of "test" can change to a different hash each refresh, then how does password_verify know the posted password is correct?

I know that I can write a function to verify the user's password. What I really want to know is how can how PHP's password_verify manage to validate to true every time, despite the fact that my hash will change with each refresh.

Note: I understand that I will be storing the password in a database so the refreshing won't be a problem, but I was doing so to try and understand the function.

Comments

@RiggsFolly I know that the salt is done for me. The question is "How does the verify function know the random salt created in the hash function in order to validate to true?"

@RiggsFolly I understand the salt option was deprecated. Had it not been (and I was able to pass it a salt), I think I would understand this function a lot more. The whole idea of the verify function successfully validating a password against a hash without knowing the salt is actually blowing my mind.
Perhaps I am just being stupid.

@Alex Howansky How is the salt returned? A string such as $hash = $2y$10$Vaj4ZonpRJjE6kmfQffvOOeIVW3ZV31JJYVY79GtZ3GtioZKtDwku means nothing, yet somehow password_verify("test", $hash") returns true.

@Machavity Having read the link, I can see that the salt is at the start of the hash, but how can the salt be in the final hash? I apologise for my confusion, and apparent stupidness, but I simply wish to understand password hashing so that I am better prepared for future uses.

@Fred -ii- Those custom function were just simple for the example (I didn't want to link an entire page of code). That being said, my current usage is in a self defined Class called User, where I have a private variable called $conn which stores the mysqli connection. Then from that I use $this->conn->prepare("SELECT * FROM ...") to access the database.
Is that bad for scoping? What is the preferred way to store the connection within a self defined Class?

Community
  • 1
  • 1
JustCarty
  • 3,839
  • 5
  • 31
  • 51
  • 3
    Forget the PEPPER completely and the SALT. Its all done for you in `password_hash()` – RiggsFolly Mar 23 '17 at 20:10
  • [The manual](http://php.net/manual/en/function.password-hash.php) Specifically _The salt option has been deprecated as of PHP 7.0.0. It is now preferred to simply use the salt that is generated by default._ – RiggsFolly Mar 23 '17 at 20:13
  • Also note: _The used algorithm, cost and salt are returned as part of the hash. Therefore, all information that's needed to verify the hash is included in it._ – Alex Howansky Mar 23 '17 at 20:14
  • 1
    Take some time to read [PHP's password hashing guide](http://php.net/manual/en/faq.passwords.php). it answers a lot of your questions, most notably about the salt and where it's stored – Machavity Mar 23 '17 at 20:16
  • 1
    Sidenote about your custom functions: You've [variable scoping](http://stackoverflow.com/q/16959576/1415724) happening in there. Either you pass db connection to them or make it global. The latter is frowned upon. – Funk Forty Niner Mar 23 '17 at 20:41
  • 1
    The `password_hash()` function will generate a random salt, and includes it in the resulting hash-string, the format looks like [this](http://stackoverflow.com/a/20399775/575765). The `password_verify()` can then extract that salt from the stored hash-string, and use it to calculate the new hash. Because both hashes are based on the same salt, they are comparable. If you are interested in more information, you could have a look at my [tutorial](http://www.martinstoeckli.ch/hash/en/index.php) about safely storing password. – martinstoeckli Mar 29 '17 at 19:21
  • @martinstoeckli This is exactly the answer I was looking for :) thank you! – JustCarty Mar 31 '17 at 00:08

0 Answers0