PHP: Easy to use and secure PHP hashing Class

Why

I created this class because there are too many people still saving simple md5 instead of more secure hashes.
The class should be fully PHP4 and PHP5 compatible and very easy to use. But also extended usage on its complex methods is possible.

Example

The usage of the class should be straight forward.
If you just want to use it, use the methods hash() and check().
EXAMPLE:

$secure_hash = new secure_hash;
$hash = $secure_hash->hash('pass');
if($secure_hash->check($hash, 'pass'))
  echo "Password fits to hash.";
else
  echo "Password does NOT fit to hash.";

That is all you need to know for just using it, but i have to tell, you will miss something important if you stop reading here.

Problem with hashes

There are several other things included for making hashes from this class even more secure.
First to know is the principle behind the class. A normal md5() is just one operation. Today's computer can calculate millions of them in a second (!).
So what to do?
You can use sha1() but this is still the same problem.
So we need a technique to slow the hashing process down to a time frame a brute force attack would be much too ineffective.

We generated our example hash:

$sha1$~=<=/<_%=|$71$bdf6a4a8bb2914f6152f31eabf34fd4b8b7f4a74$

The format of the hash simply is:

delimiter = $
$ hashing-mehtod $ salt $ interations $ hash $

random Salts

First step for solving this problem is: using salts
A salt is some random string that is appended to the password to make it more complex. This class generates random salts so rainbowtables will be useless.
In the formated hash the salt is ~=<=/<_%=|.
You can configure length of the salt with:

var $salt_len = 4;

Hint: A much longer salt does NOT result a more secure hash.
The salt needs to be stored too so better leave it at 4.

random Iterations

Second step is: random iterations
Each hash gets rehashed n times. This makes cracking the hash very difficult because you need specialized software for hashes from this class. Also doing more iterations will take longer, too long for current hardware.
In the formated hash the number of iterations is 71 ($71$).
You can configure this with:

var $iter_min = 10;
var $iter_max = 99;

unusual hashing methods

Third step: Using unusual hashing methods
Our example hash is done with sha1($sha1$), but it is also possible to write
own hashing methods an attacker needs to know first.
Check out "secure_hash_example" for an example.
You can change hash method with:

var $hashing_method = 'sha1';

global Salt

Forth step is: A global salt
Each password gets its own salt, that is great. But we have to save the salt inside our formated hash. That is baaad because the attacker will get it too. So lets define something the attacker can NOT get with a SQL-Injection.
We define a global salt. This has to be done BEFORE the hashes get created.
This values should NOT CHANGE, or your hashes get incorrect.
So if you want to use a global salt, define it BEFORE FIRST USE and let it stay!

var $salt_global = '';

Permutations

Fifth step: using permutations
A permutation is something like this:
The rules this class uses look like "abc|cab". This means, the "a" will become "c", "b"->"a" and "c"->"b".
The principle is something like shuffling the string with a defined rule. This is another thing the attacker needs to know if he wants to crack our hashes.
This feature has to be defined BEFORE FIRST USE! and then let it stay! Otherwise your hashes will become incorrect.
You can define your own permutations at:

var $permutate = true;
var $permutations = array(.....);

There is also a method for creating permutations:

function _new_permutation();

If you use all these steps you will have a fine solution for the problem with common unsecured hashes. Storing a hash created by this class with all its features enabled should be safe way to store your users passwords.

Download

secure_hash.zip
Source
Documentation

Hope you enjoy my work.
Get in touch if you have questions or hints.

Related posts:


 
 
 

13 Kommentare zu “PHP: Easy to use and secure PHP hashing Class”

  1. julianor 1. Oktober 2009 um 22:32

    The global salt idea is broken. Salts are to avoid the same password resulting in the same hash. To do what you are trying to do you could encrypt every password with a real block cipher and a secret key before hashing. But if the attacker can retrieve all the hashes and he can change any password, your secret key starts to be useless too :)

  2. Julius 2. Oktober 2009 um 09:45

    The global Salt is only a method for advanced use of the class to make hashes fetched with SQL-Injection useless. So the idea is not broken by default.
    Adding a encryption with a secret key is not different to the use of a global salt when using only hashing functions.

  3. Dustin 3. Oktober 2009 um 19:59

    Hey Julius,

    I like the idea of a combination of global salting and per unit salting, as I can see it's obvious benefits. The argument for storing a users salt with the salted hashes can still be considered a viable measure, since a hacker would still need to know the insert method the code uses to salt (i.e. is it inserted by str_split, is it before the pass, after? etc...) as always security does also rely on the length of the values being passed to be hashed. The only problem I can forsee with a global hash however is, if it is lost, the scheme is broken, so precautions would need to be implemented to keep that from happening.

    Great class, and I do like that it slows down the hashing routine.

    -Dustin

  4. bucabay 21. Oktober 2009 um 01:02

    I think you hit the nail on the head with this one. There is a lot of bad advice that is just followed blindly regarding hashing of passwords. Especially the common advice that double hashing is bad, when it is used in my applications: http://en.wikipedia.org/wiki/Key_strengthening

    I like the global hash and custom hash function. You could however consider the global salt, and custom hashing function.

    Great work!

  5. Tazek 31. Juli 2011 um 17:54

    Hi,

    Your class seems to be really useful.
    Is it the latest version? How can I get further updates?

    Thank you!

    Best,
    Tazek

  6. Julius 1. August 2011 um 11:57

    Hi Tazek,
    i think i should do da rewrite of that code and publish it on github.
    But that has to wait for after exams.
    Regards, Julius

  7. Tazek 1. August 2011 um 20:29

    Hi Julius,

    I have a question: I'm using your class on my login system. This login system has a "reset password" page, which sends the password by e-mail. I'd like to find someway to "generate" the password from the hash.

    What's the easy way to do it?

    Thanks!

  8. Julius 1. August 2011 um 21:46

    There is no way to get the password from a hash.
    Hashes just work the way Input (like a password) -hashing-> Hash. Not the other way round.
    Encryption can do Input -encrypting-> Encrypted Input -decrypting-> Input but that aint practical.

    Sending plain passwords via Email is also a security risk. I would avoid that.
    Best way for you should be sending a unique link that can only be used once for resetting a password on your website.

    Regards, Julius

  9. Macs 15. Februar 2012 um 11:19

    Hi Julius

    Please forgive my ignorance, however, the code and example that you give generates a unique hash on each occasion that it is executed for the same password.

    Is this intended and a I missing something.

    Regards
    Macs

  10. Julius 15. Februar 2012 um 11:36

    It seems as if you missed the part, that for each hash a random salt is used, that is stored inside the returned hash. This is a security measurment to avoid hashes beeing cracked too fast.
    More info can be found here: http://en.wikipedia.org/wiki/Salting_%28cryptography%29

  11. Macs 15. Februar 2012 um 11:44

    Hi Julius

    Please ignore my last comment. I understand now

    Great stuff, thank-you

    Regards
    Macs

  12. Alejandro 26. August 2012 um 14:45

    Hi Julius, i need to tell you that this scheme isn't secure, i know it is hard to get, but the only functions that actually increase the security of your scheme are the random salt and the multiple hashing, and the multiple hashing can be easily broke with an FPGA in no time, because you are using sha-1.
    Your commentary about the 4 bytes salt is simply wrong, even the PBKDF uses a salt of 8 bytes (new schemes use nonces with at least 32 bytes), the size of the salt matters.
    The global salt + the permutation = bad cipher
    if you want to do this, it's a better idea using a block cipher like AES
    key + AES
    The AES-key is a global salt, and AES is a permutation (by definition), the diference between your salt+permutation and key+AES is: your permutation is linear, then, it is easy to compute.

  13. Julius 23. September 2012 um 13:34

    Thanks Alejandro for your comment.

    From your point of view, my scheme might be too simple to be called secure. But when working with php, you are quite limited what kind of solution can be done with common effort. Why i used sha1 and md5 is, because PHP offers them in nearly every version today. Other functions need specific modules that are not always installed.

    The point with the FPGA is correct, its the way it goes with more powerfull hardware over time.

    The comment about salt length is truly incorrect. A longer salt will result a in a "more secure" hash because the number of possibilites for a attack that does not have the salt will increase. But if the attacker already got the salt, i think it does not make a difference, if its 4 or 8 chars long.

    Thanks for your AES comment, that is something i did not know yet.

    As you can see, the solution is not perfect ;)
    But i always hoped to inspire and teach people, to have an eye on that topic because it is fundamental knowledge of hashing.