Understanding Hash Functions and Keeping Passwords Safe

Understanding Hash Functions and Keeping Passwords Safe

Tutorial Details
  • Language: PHP
  • Difficulty: Intermediate
  • Estimated Completion Time: 30min

From time to time, servers and databases are stolen or compromised. With this in mind, it is important to ensure that some crucial user data, such as passwords, can not be recovered. Today, we are going to learn the basics behind hashing and what it takes to protect passwords in your web applications.

Republished Tutorial

Every few weeks, we revisit some of our reader's favorite posts from throughout the history of the site. This tutorial was first published in January of 2011.


1. Disclaimer

Cryptology is a sufficiently complicated subject, and I am by no means an expert. There is constant research happening in this area, in many universities and security agencies.

In this article, I will try to keep things as simple as possible, while presenting to you a reasonably secure method of storing passwords in a web application.


2. What Does “Hashing” Do?

Hashing converts a piece of data (either small or large), into a relatively short piece of data such as a string or an integer.

This is accomplished by using a one-way hash function. “One-way” means that it is very difficult (or practically impossible) to reverse it.

A common example of a hash function is md5(), which is quite popular in many different languages and systems.

$data = "Hello World";
$hash = md5($data);
echo $hash; // b10a8db164e0754105b7a99be72e3fe5

With md5(), the result will always be a 32 character long string. But, it contains only hexadecimal characters; technically it can also be represented as a 128-bit (16 byte) integer. You may md5() much longer strings and data, and you will still end up with a hash of this length. This fact alone might give you a hint as to why this is considered a “one-way” function.


3. Using a Hash Function for Storing Passwords

The usual process during a user registration:

  • User fills out registration form, including the password field.
  • The web script stores all of the information into a database.
  • However, the password is run through a hash function, before being stored.
  • The original version of the password has not been stored anywhere, so it is technically discarded.

And the login process:

  • User enters username (or e-mail) and password.
  • The script runs the password through the same hashing function.
  • The script finds the user record from the database, and reads the stored hashed password.
  • Both of these values are compared, and the access is granted if they match.

Once we decide on a decent method for hashing the password, we are going to implement this process later in this article.

Note that the original password has never been stored anywhere. If the database is stolen, the user logins can not be compromised, right? Well, the answer is “it depends.” Let’s look at some potential problems.


4. Problem #1: Hash Collision

A hash “collision” occurs when two different data inputs generate the same resulting hash. The likelihood of this happening depends on which function you use.

How can this be exploited?

As an example, I have seen some older scripts which used crc32() to hash passwords. This function generates a 32-bit integer as the result. This means there are only 2^32 (i.e. 4,294,967,296) possible outcomes.

Let’s hash a password:

echo crc32('supersecretpassword');
// outputs: 323322056

Now, let’s assume the role of a person who has stolen a database, and has the hash value. We may not be able to convert 323322056 into ‘supersecretpassword’, however, we can figure out another password that will convert to the same hash value, with a simple script:

set_time_limit(0);
$i = 0;
while (true) {

	if (crc32(base64_encode($i)) == 323322056) {
		echo base64_encode($i);
		exit;
	}

	$i++;
}

This may run for a while, though, eventually, it should return a string. We can use this returned string — instead of ‘supersecretpassword’ — and it will allow us to successfully login into that person’s account.

For example, after running this exact script for a few moments on my computer, I was given ‘MTIxMjY5MTAwNg==‘. Let’s test it out:

echo crc32('supersecretpassword');
// outputs: 323322056

echo crc32('MTIxMjY5MTAwNg==');
// outputs: 323322056

How can this be prevented?

Nowadays, a powerful home PC can be used to run a hash function almost a billion times per second. So we need a hash function that has a very big range.

For example, md5() might be suitable, as it generates 128-bit hashes. This translates into 340,282,366,920,938,463,463,374,607,431,768,211,456 possible outcomes. It is impossible to run through so many iterations to find collisions. However some people have still found ways to do this (see here).

Sha1

Sha1() is a better alternative, and it generates an even longer 160-bit hash value.


5. Problem #2: Rainbow Tables

Even if we fix the collision issue, we’re still not safe yet.

A rainbow table is built by calculating the hash values of commonly used words and their combinations.

These tables can have as many as millions or even billions of rows.

For example, you can go through a dictionary, and generate hash values for every word. You can also start combining words together, and generate hashes for those too. That is not all; you can even start adding digits before/after/between words, and store them in the table as well.

Considering how cheap storage is nowadays, gigantic Rainbow Tables can be produced and used.

How can this be exploited?

Let’s imagine that a large database is stolen, along with 10 million password hashes. It is fairly easy to search the rainbow table for each of them. Not all of them will be found, certainly, but, nonetheless…some of them will!

How can this be prevented?

We can try adding a “salt”. Here is an example:

$password = "easypassword";

// this may be found in a rainbow table
// because the password contains 2 common words
echo sha1($password); // 6c94d3b42518febd4ad747801d50a8972022f956

// use bunch of random characters, and it can be longer than this
$salt = "f#@V)Hu^%Hgfds";

// this will NOT be found in any pre-built rainbow table
echo sha1($salt . $password); // cd56a16759623378628c0d9336af69b74d9d71a5

What we basically do is concatenate the “salt” string with the passwords before hashing them. The resulting string obviously will not be on any pre-built rainbow table. But, we’re still not safe just yet!


6. Problem #3: Rainbow Tables (again)

Remember that a Rainbow Table may be created from scratch, after the database has been stolen.

How can this be exploited?

Even if a salt was used, this may have been stolen along with the database. All they have to do is generate a new Rainbow Table from scratch, but this time they concatenate the salt to every word that they are putting in the table.

For example, in a generic Rainbow Table, “easypassword” may exist. But in this new Rainbow Table, they have “f#@V)Hu^%Hgfdseasypassword” as well. When they run all of the 10 million stolen salted hashes against this table, they will again be able to find some matches.

How can this be prevented?

We can use a “unique salt” instead, which changes for each user.

A candidate for this kind of salt is the user’s id value from the database:

$hash = sha1($user_id . $password);

This is assuming that a user’s id number never changes, which is typically the case.

We may also generate a random string for each user and use that as the unique salt. But we would need to ensure that we store that in the user record somewhere.

// generates a 22 character long random string
function unique_salt() {

	return substr(sha1(mt_rand()),0,22);
}

$unique_salt = unique_salt();

$hash = sha1($unique_salt . $password);

// and save the $unique_salt with the user record
// ...

This method protects us against Rainbow Tables, because now every single password has been salted with a different value. The attacker would have to generate 10 million separate Rainbow Tables, which would be completely impractical.


7. Problem #4: Hash Speed

Most hashing functions have been designed with speed in mind, because they are often used to calculate checksum values for large data sets and files, to check for data integrity.

How can this be exploited?

As I mentioned before, a modern PC with powerful GPU’s (yes, video cards) can be programmed to calculate roughly a billion hashes per second. This way, they can use a brute force attack to try every single possible password.

You may think that requiring a minimum 8 character long password might keep it safe from a brute force attack, but let’s determine if that is, indeed, the case:

  • If the password can contain lowercase, uppercase letters and number, that is 62 (26+26+10) possible characters.
  • An 8 character long string has 62^8 possible versions. That is a little over 218 trillion.
  • At a rate of 1 billion hashes per second, that can be solved in about 60 hours.

And for 6 character long passwords, which is also quite common, it would take under 1 minute.

Feel free to require 9 or 10 character long passwords, however you might start annoying some of your users.

How can this be prevented?

Use a slower hash function.

Imagine that you use a hash function that can only run 1 million times per second on the same hardware, instead of 1 billion times per second. It would then take the attacker 1000 times longer to brute force a hash. 60 hours would turn into nearly 7 years!

One way to do that would be to implement it yourself:

function myhash($password, $unique_salt) {

	$salt = "f#@V)Hu^%Hgfds";
	$hash = sha1($unique_salt . $password);

	// make it take 1000 times longer
	for ($i = 0; $i < 1000; $i++) {
		$hash = sha1($hash);
	}

	return $hash;
}

Or you may use an algorithm that supports a "cost parameter," such as BLOWFISH. In PHP, this can be done using the crypt() function.

function myhash($password, $unique_salt) {

	// the salt for blowfish should be 22 characters long

	return crypt($password, '$2a$10$'.$unique_salt);

}

The second parameter to the crypt() function contains some values separated by the dollar sign ($).

The first value is '$2a', which indicates that we will be using the BLOWFISH algorithm.

The second value, '$10' in this case, is the "cost parameter". This is the base-2 logarithm of how many iterations it will run (10 => 2^10 = 1024 iterations.) This number can range between 04 and 31.

Let's run an example:

function myhash($password, $unique_salt) {
	return crypt($password, '$2a$10$'.$unique_salt);

}
function unique_salt() {
	return substr(sha1(mt_rand()),0,22);
}
$password = "verysecret";

echo myhash($password, unique_salt());
// result: $2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC

The resulting hash contains the algorithm ($2a), the cost parameter ($10), and the 22 character salt that was used. The rest of it is the calculated hash. Let's run a test:

// assume this was pulled from the database
$hash = '$2a$10$dfda807d832b094184faeu1elwhtR2Xhtuvs3R9J1nfRGBCudCCzC';

// assume this is the password the user entered to log back in
$password = "verysecret";

if (check_password($hash, $password)) {
	echo "Access Granted!";
} else {
	echo "Access Denied!";
}
function check_password($hash, $password) {

	// first 29 characters include algorithm, cost and salt
	// let's call it $full_salt
	$full_salt = substr($hash, 0, 29);

	// run the hash function on $password
	$new_hash = crypt($password, $full_salt);

	// returns true or false
	return ($hash == $new_hash);
}

When we run this, we see "Access Granted!"


8. Putting it Together

With all of the above in mind, let's write a utility class based on what we learned so far:

class PassHash {

	// blowfish
	private static $algo = '$2a';

	// cost parameter
	private static $cost = '$10';
	// mainly for internal use
	public static function unique_salt() {
		return substr(sha1(mt_rand()),0,22);
	}

	// this will be used to generate a hash
	public static function hash($password) {

		return crypt($password,
					self::$algo .
					self::$cost .
					'$' . self::unique_salt());

	}
	// this will be used to compare a password against a hash
	public static function check_password($hash, $password) {

		$full_salt = substr($hash, 0, 29);

		$new_hash = crypt($password, $full_salt);

		return ($hash == $new_hash);

	}

}

Here is the usage during user registration:

// include the class
require ("PassHash.php");

// read all form input from $_POST
// ...

// do your regular form validation stuff
// ...

// hash the password
$pass_hash = PassHash::hash($_POST['password']);

// store all user info in the DB, excluding $_POST['password']
// store $pass_hash instead
// ...

And here is the usage during a user login process:

// include the class
require ("PassHash.php");

// read all form input from $_POST
// ...

// fetch the user record based on $_POST['username']  or similar
// ...

// check the password the user tried to login with
if (PassHash::check_password($user['pass_hash'], $_POST['password']) {
	// grant access
	// ...
} else {
	// deny access
	// ...
}


9. A Note on Blowfish Availability

The Blowfish algorithm may not be implemented in all systems, even though it is quite popular by now. You may check your system with this code:

if (CRYPT_BLOWFISH == 1) {
	echo "Yes";
} else {
	echo "No";
}

However, as of PHP 5.3, you do not need to worry; PHP ships with this implementation built in.


Conclusion

This method of hashing passwords should be solid enough for most web applications. That said, don't forget: you can also require that your members use stronger passwords, by enforcing minimum lengths, mixed characters, digits & special characters.

A question to you, reader: how do you hash your passwords? Can you recommend any improvements over this implementation?

Tags: security
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Matthew

    Guess Tuts+ didn’t read their own tutorial.

  • http://gnarmedia.com adam murphy

    your security staff needs to write this article over 100 times on the chalkboard so they never make a mistake so boneheaded as the one that lead to today’s fiasco.

  • Murphy

    How ironic :D

  • Eox

    And how good is it to use hash_hmac?

    I use it like this:

    $password = //The password of the user (plain text)
    $salt = //A random string only for this user
    $secret_key = //A Sting which is only in the createHash function. So the hacker has never this string when he only hack the database.

    $hash = hash_hmac(‘sha512′, $password.$salt, $secret_key);

  • http://may2012 Dale Hurley

    Why didn’t you read your own article????

    “Today we learned that our server was compromised, and sensitive data including email addresses and passwords were accessed before we were able to detect and stop the unauthorized intrusion. We have taken immediate measures to take Tuts+ Premium offline and to secure the servers and systems.”

    • Edwin

      Is account in Codecanyon affected?

      • http://www.jeffrey-way.com Jeffrey Way

        No — only if the passwords are identical.

  • http://brianswebdesign.com Brian Temecula

    How did you know this is what I was working on today? I was working on Community Auth and implemented bcrypt, and then came here to see this! Too funny!

  • Ali

    Hi Jeff,
    You didn’t take character encoding(utf-8, ISO, etc) into account when calculating the number of possible brute forces. well if someone use chinese, persian, etc in his password it will stronger, but not alone. We need to have long passwords and with different unicodes. That would be much more difficult to compromise.

  • Jacky

    Just how does an attacker know which algorithm was used to hash the password?

  • Cam Carnell

    A good read, thanks for reposting!

  • http://www.fabirco.org/ beton

    Thanks, that was what i had problem in.

  • Anele

    I have a question about this topic, if I have a
    $password_hashed = ‘$P$B55D6LjfHDkINU5wF.v2BuuzO0/XPk/’;

    1. How can I tell what hash functions has been used
    2. How can I retrieve the original password

    Second Question. Does the example in this tutorial proposing that if I should register with the same password twice, will the hashed values be different? If so note that there is a security breach.
    Please see the url bellow:

    http://www.codinghorror.com/blog/2005/10/why-do-login-dialogs-have-a-user-field.html

    “No two users could have the same password” so If so then I can not tell someone that : “that password has been registered”

    • David

      I’m no expert so if someone thinks I’m wrong please point it out.

      1.I think you can’t know for sure what hash function was used. You can guess by the number of characters in the hashed string. For example if the hashed string is 40 bytes long you can guess sha1 was used.

      2. I think you can’t retrieve the original password when you use an algorithm like sha1 or md5, and that’s the point of the algorithms, they work one way only. It depends on the type of algorithm though because the programmer could be using something like AES_ENCRYPT that uses a KEY to encrypt the data and then retrieve the original value with AES_DECRYPT and the same KEY it was used to encrypt it.

      As for the question about users with the same password… read the comments on the link you provided. It’s wise to use the combination of username and password even if the username is public. That way passwords can be repeated safely.

      • http://beardedocto.tumblr.com Michael Grech

        @1 If your server has been hacked your source code has been compromised. If the hacker can read your source code they can figure out what hash function was used.

        @2 Are you kidding me? This article literally explained how to determine passwords hashed w/ md5?!

      • Rick

        Do what I do – ioncube encode the files that handle passwords and encryption keys – it’ll stop them being able to know your hard-coded key, or what kind of method is used for hashing and such.

        This way if they gain access to your server, they can only grab the hashes from the DB – they wont be able to find out how its hashed and how many times.

  • http://jaceksmolak.pl Jacek

    Hi!

    I’m using hash(‘sha512′, $password.$userUniqueSalt.$globalSalt);

    Also:
    – $userUniqueSalt is stored in DB only (when someone gets it’s hands on this data, users unique salt will not be enough), and I change it each time user changes his/hers password – this way stolen DB will be useless after passwords are changed,
    – $globalSalt is hardcoded in application,
    – and sha512 gives me 128-character long hash, way, way much better than sha-1

    Each salts are at least 30-characters long, randomly generated with special characters.

    :)

    • Tom

      Well, ovarall that seems like a clever approach. I am doing something similar.

      I do however not see the point in changing the user unique salt when the user chages the password. If the user changes password after your DB gets hacked, the new password is safe anyway since it is new. If the hacker want to get in after the password has changed, he would have to hack the DB again or guess the password. An updated user unique salt does not affect the difficulty of either of those tasks.

      • http://jaceksmolak.pl Jacek

        Not quite. If users unique salt is unchanged, attacker is one step closer to decrypting users password.

      • http://jaceksmolak.pl Jacek

        Provided that vulnerability still exists and attacker can get his/hers hands on DB again. If not – true, new users salt is useless, but there is (are) scenarios when this is helpfull.

        Sorry for doubleposting.

      • Tom

        Thanks for your reply, Jacek! This truely interests me.

        Well, I am afraid that I do not quite understand you.

        If the vulnerability still exists and attacker can get his hands on DB again, would he not also get hold of the user unique salt (updated or not) again?

    • Whitey

      If you’re handling passwords like this then you’re doing it wrong. Plain and simple. There’s a reason that security experts say SHA (yes, even SHA512) are insecure for passwords or any sensitive data. You do not know better than them and you will not be secure by using this method. Follow what they recommend and use a slow, costly hashing algorithm like bcrypt. I’m sick of people thinking they’re smarter than the experts.

  • http://www.uxzeal.com uxzeal

    Nice Article. Keep Posting.

  • Matt

    I use the following and haven’t had any problems… yet….

    1 function to generate hash

    function genRandomString($Len,$Simple = True) {
    if($Simple === False) {
    $chars = “0123456789abcdefghijklmnopqrstuvwxyz”;
    $charLen = 35;
    } else {
    $chars = “0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()”;
    $charLen = 71;
    }

    for ($p = 0; $p genRandomString(LeftPad);
    $RSalt = $this->genRandomString(RightPad);
    $FullHash = $LSalt . $Salt . $RSalt;

    return $FullSalt;
    }

    function encrypt($Pass, $Salt) {
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $Salt, $Pass, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
    }

    $salt = generateSalt(genRandomString(32)); // Add this to database as the salt

    $pass = encrypt($_POST['pass'], $salt);

    • Matt

      First function should be

      function genRandomString($Len,$Simple = false) {
      if($Simple == true) {
      $chars = “0123456789abcdefghijklmnopqrstuvwxyz”;
      $charLen = 35;
      } else {
      $chars = “0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()”;
      $charLen = 71;
      }

  • Artur

    King of Irony ;)

  • Aäron

    Here is my small class that can be used to hash password. You could also make it static (all the functions) if you want. But is preffer the way it is builded right now.

    Good luck with it!

    a dynamic value that you need to set manually,
    * @param string $pepper -> a static value that is always the same,
    */
    private
    $password = ”,
    $salt = ”,
    $pepper = ’84ce3dc600′;

    /* The constructor. The pepper need to be set above
    * or with the set function.
    * @param string $password,
    * @param string $salt
    */
    public function __construct($password, $salt = ”) {
    $this->password = $password;
    $this->salt = $salt;
    }

    /* Check if a password is valid, this mean one number, one
    * lower case charachter and one uppercase character and a length
    * of 6 charachters.
    * @param string $password
    */
    public static function validatePassword($password) {

    /* Check if the password has at least one lowercase,
    * one uppercase charachter and check if there is
    * one number:
    */
    if((strlen(preg_replace(‘/([^a-z]*)/’, ”, $password)) == 0) || (strlen(preg_replace(‘/([^A-Z]*)/’, ”, $password)) == 0) || (strlen(preg_replace(‘/([^0-9]*)/’, ”, $password)) == 0) || (strlen($password) pepper = $pepper;
    }

    /* If you want to use a random salt, you can ask here and. It
    * wil return a small string of 5 charachters:
    */
    public static function getRandomSalt() {
    return substr(md5(rand(1000000,9999999).str_shuffle(‘ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz’).rand(1000000,9999999)), 0, 5);
    }

    /* Return the salt that has been used by the script if the user
    * activate this function:
    */
    public function getSalt() {
    return $this->salt;
    }

    /* This function will return the hashed password. For the
    * vars that will be used look above:
    */
    public function getHashedPassword() {
    return hash(‘sha512′, substr($this->password, 0, strlen($this->password) / 2).$this->salt.substr($this->password, strlen($this->password) / 2).$this->pepper);
    }

    }

    # Example:
    $hasher = new Security(‘HereSomePassword’, ‘ASaltIfRequiredOrUseGetRandomSaltAndGetSalt’);
    $password = $hasher->getHashedPassword();
    $salt = $hasher->getSalt();

    # You can also use Security::validatePassword($password) to validate a password or
    # Security::getRandomSalt() to get a random salt.

    ?>

  • begs

    Nice and interesting reading.
    But i got one question:
    Where is the difference between having only one salt hardcoded in a e.g. PHP file – and generating a unique salt per user and store this unique salt in the user record?
    If code and database are stolen, you have the salt (one in code, one from the db user record) anyhow.

    Maybe i am missing something…?

  • George

    scrypt or bcrypt is the way to go!

  • Jose Flores

    Excellent!
    Great tutorial.

  • http://less4us.blogspot.com Lani

    Amaizing tips.. :)
    Best hashing teqnique is hashing it multiple times and with umique phrases, only thing to note then is and source view by attacker

  • Rick

    Recommending sha1 or md5 in any shape or form (even if salted) is a big no-no. Never, ever use these. They are out of date and there are databases with BILLIONS of records of passwords using them.

    Stick with a much stronger method. For example use sha256 on the password, then a salt generated by a 32 character string, which in turn is run through sha256. Then put the two together and sha256 them again.

    This will give you a HUGELY secure password when compared to the crappy md5 and sha1 options.

    • Rick

      Oh and I forgot to mention – where possible, use an encryption key, hard coded. This means someone will need not only your salt, but also the hard-coded key before they can even think of attempting to reverse the password (not that they would be able to with sha256 however).

    • Whitey

      I know you’re trying to help, but please don’t give out advice when you no nothing about the topic. SHA has been considered insecure for a long, long time and should not be used for passwords ever. You need a slow and costly algorithm, not a fast and cheap one like SHA.

      • rmwebs2

        you can’t crack it, dipshit

  • http://www.csshtml.co Gautam Lakum

    Ahh! Great post! It can be useful when developing login/register functionality and can help to increase security of password.
    Thanks a ton!

  • Andrii

    Thanks, to remind some obviouse staff we can simply forget or don’t pay attention. Nettuts is always a place to read usefull articles.

  • Leon

    Wow, I’m glad I found this tutorial.

  • http://www.burningsoul.in aaryadev

    nice one
    thanks for posting

  • http://geeksarsenal.comli.com Jahanzeb Khan

    But md5 and sha1 or any sha are old and weak now, they’ve been broken and you can hack through them with even a normal PC.

    I would highly recommend you teach a bit of PHPass, since it hasn’t been broken yet, it’s a simple easy to use light-wieght library that makes life easier. Even WordPress uses it!

  • Luis

    bCrypt is VERY awesome and works on PHP and python I think maybe ruby it’s slow so it takes years to break it.

  • Travis

    Hi there! I’m Travis, now I own a website and when users register we hash the passwords (Every website should) But when I read this they talked about MD5 and SHA1, which are outdated especially MD5 so ovoid using them and go for something very hard to decrypt called SHA512 and try encrypting it with another hash and adding a SALT. That should keep personal data safe and stop passwords being decrypted if you was hacked. I hope this helped some people! -Travis

  • SABARISHKUMAR

    Thank U for your information and i want to know what type of database technology that currently used in facebook to store huge amount of data and manipulation of data???

  • http://www.leo-letaro.fr Léo

    To protect yourself against bruteforce attack, just use a slower hash function, but *do not combine* hashing function since it will only increase the risk of getting a collision.

    In other words: NO 1,000x sha1().

  • http://N/A Drew.R

    Awesome post, I use a bit of an odd method for hashing passwords, for simplicity sake.

    < ?PHP

    $ui_password = trim($_POST['register_password']);

    $s1 = rand(0,11);

    $first_pass = md5($s1 . $ui_password);

    $s2 = rand(10,21);

    $second_pass = md5($s2. $first_pass . $s1);

    $final_gen = ((rand(0,50) /2) * $s1) + ($s2*5);
    $password = md5($final_gen . $second_pass);

    ? >

  • http://www.admecindia.co.in Ravi Bhadauria

    Nice tutorials as always.

    I am using md5() with some own invented techniques.
    I would like to use sha1() too now.

    Thanks

  • http://n/a Diego

    Could it be better to store two different hashes?
    e.g: md5($salted_input) in password1 and sha1($salted_input) in password 2

    I think it would narrow down the posibility of finding other string that simultaniusly matches both columns in a table.

  • a

    Great Read! Thanks for writing!

  • http://www.facebook.com/profile.php?id=1247010790 Matt Williams

    bcrypt ftw

  • Guven

    Nice tutorial, thanks

    Guven

  • arnaud

    Hi, many thanks for the tutorial and code!

    One correction to make: in the code for the login process, row 8 miss a closing bracket for the “if”. It should read “if (PassHash::check_password($user['pass_hash'], $_POST['password'])) {“

  • http://twitter.com/gabbsmo Gabriel Smoljár

    I felt the example code could be more simple so I cleaned it up a bit https://gist.github.com/gabbsmo/5227002

  • http://www.facebook.com/dimitris.papageorgiou1 Dimitris Papageorgiou

    In this code here:…if (PassHash::check_password($user['pass_hash'], $_POST['password'])

    the $user['pass_hash'] is the password that is retrieved from the db? It is not clear to me.

  • gamaya

    Thank you

  • Saumya Majumder

    Hey guys, I’m in a big trouble. I’m using the hash function posted in the above tutorial into my new project. But what I found, rather faced is: It is successfully encrypting passwords, but when I do check the db password with user given password, it always return false, beside giving everything correctly.
    Please help guys. Its urgent. Plz