Skip to content

A Better PHP Hashing Function

by Chris Wiegman on March 10th, 2009

Anyone who has done much with PHP knows that from time to time there is data we must store securely without the risk of letting the wrong people get to it. For the bulk of smaller projects this data falls into two categories: passwords and cookies. For obvious reasons storing plain-text or unencrypted passwords isn’t very secure as anyone with access to your database can easily retrieve those passwords and gain access to your system. In the case of cookies we need a way to keep people from easily manipulating them and spoofing them in an attempt to gain access to your application.

PHP contains a number of functions to help you get started in this with the most popular being md5 and sha1. These two functions use the encryption algorithm referred to by their name to give you a more-secure version of the data which then could be stored in a database. For example, using the md5 algorithm we could hash the word password with the following code:

md5(“password”);

Using this function would change the easily identified word password into: 5f4dcc3b5aa765d61d8327deb882cf99

This 32-bit hex number will keep the average person from getting the original password. However, both the md5 and the sha1 functions will always produce the same result for a given input. Knowing this many of the more sophisticated attackers have started using what are called Rainbow Tables. These are essentially lists of all the words in the dictionary (and other common phrases, etc) and their associated encrypted value. Over time these types of table can allow an attacker who can see your table to reverse engineer your passwords or other data and once again gain access to your application.

So how do we stop this? We use a technique called salting or seeding to apply extra characters to the plain-text before it is encrypted. Think of it as a password for the text to be encrypted. For example in the following example we use the seed seed in our password to change the result of our function.

md5(“seedpassword”);

With the above code our output would now be 3e0a3520002da052984dd095bba19550 which is a completely different result than just encrypting the password like we did above. Now our attacker would need to know both are seed AND our password to be able to reverse engineer what they might find in our database. This can be an unlikely, but possible scenario. So what do we do to strengthen it even more? First we need to pick a random seed using something other than a normal word we could find in a dictionary. Click Here to use my seed generator which gives you a 60 character random seed. Now take a look at the following code to see how we’ll use the seed:

define(‘ENCRYPT_SEED’,’ ^kxmMMJ3*zVNcKQ.@2*HjIW#PTbGh!B_*6dk.tVMy7p/#Q%j/WLb,3,GK:4′);

First we need to take the seed and store it somewhere where our application can get to it, but preferably where no one else can

define(‘ENCRYPT_COUNT’,’4′);

The encrypt count will be used to embed the characters from the original password into the seed. I would recommend using a random variable between 3 and 10 and then storing this integer in the database as a separate field or tack it on as the first or last 2 characters of your encrypted password.

function cwCrypt($plainText) {
$salt = ENCRYPT_SEED;
$textLength = strlen($plainText);
$saltLength = strlen($salt);
$saltPos = 0;
for ($textPos = 0; $textPos <= $textLength; $textPos++) {
$pre = substr($salt, $saltPos, ENCRYPT_COUNT);
$addChar = substr($plainText, $textPos, 1);
$post = $pre.$addChar;
$salt = str_replace($pre,$post,$salt);
if ($saltPos < $saltLength – (ENCRYPT_COUNT-1)) {
$saltPos = $saltPos + ENCRYPT_COUNT;
} else {
$saltPos = 0;
}
}
return md5($salt);
}

Finally the function above will take the text you wish to encrypt and intersperse each character based on the value given by the value stored in ENCRYPT_COUNT. The end result is an encrypted string of characters encrypted with a random seed which would be hard to guess and finally the actual text you need to encrypt is interspersed at a random interval within the text making cracking it even harder.




Related posts

Comments are closed.