Related
I've been reading a bunch of stuff about security and I'm just now starting to try and play around with the code. I want to use MD5 encryption with a salt. I ran across this nifty PHP script with random salt:
substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',5)),0,10);
It randomly generates some characters as salt, but then I was thinking: How would I go about checking logins? Do I remove the salt, or should I store it in the database?
You shouldn't be using MD5 for password hashing. See How can I store my users' passwords safely?
To answer your original question, the salt is stored alongside the HASHED password in the database. The salt is not meant to be secret if the hashed password is discovered. Its purpose is to prevent attackers from using rainbow tables.
Store it in database. Otherwise you can't compare password provided by user with hashed one.
Some even regenerate hash (with new salt) upon each successful login of given user, although commenters below argue this is not the best idea (see comments)
Okay, so salts are used for both one-way hashes and encryption. They make it harder to reverse the encryption or the hash. I think it's easier to draw the point out with hashes, so I'll write from that point of view, but the principles apply to encryption in general.
Imagine that you're saving passwords. One of your users chooses the word "kiwi" as a password. Because storing passwords in plain-text is stupid, you don't want to do that. You want to hash the password.
But, those pesky hackers out there have compiled huge databases of hash look-up tables. (Check this one out!)
So, how do we foil the hackers? By salting the user's input! The salt is a random string (or set of bits, properly) that is cryptographically combined with the user's input to produce a more secure hash.
For example, if the string to be hashed is still "kiwi" and our salt is "5m3d", a simple salt mechanism might concatenate the two into: "kiwi5m3d". The hackers probably have "kiwi" in their database, but probably don't have "kiwi5m3d". A good salting system will probably perform a much more complicated function than this.
So now the hackers need a new look-up database for each possible salt. Using a random salt means that the hacker will have to do a full-on brute force attack, rather than recycling previous computations or using someone else's look-up table.
You could choose a different salt for everything, or the same salt for all the things on your site. A different salt of each entity necessitates a new brute force attack for each entity, but it can make implementation more difficult because each salt must be saved, rather than having one global salt (which, for data which is already somewhat random, e.g. passwords, should be sufficient).
In the case of encryption, look-up tables are still a possibility, but the data to be encrypted is generally varied enough that they're not feasible. So it becomes a game of playing "guess the password". It's easy to guess "kiwi" and hard to guess "kiwi5m3d".
You will have to save the salt somewhere, because it's the only way to "know" what's been hashed or encrypted. In the case of a hashed, you compare the user's original hash against the salted hash of their input. In the case of encryption, you need the salt to decrypt the data.
Where do you go from here?
First, don't use MD5. I gave you a link to an MD5 look-up database above. The function's increasingly considered to be weak. The sha class of algorithms is a better choice.
Second, make sure you choose a good salt. Longer and randomer is better. Computers are kind of bad at generating random data. This site could be one good choice and has a pretty good break-down of how it generates its random numbers.
Third, consider salt algorithms. Simple concatenation should work, but maybe HMAC (something I don't know much about) would be better.
You would have to store it in the database, otherwise you would not have anything to compare it to. The thing to remember with using a salt, is that the complexity can vary and without knowing what the salt is, the likelihood of it being brute forced hack is dramtically decreased.
Example:
$password = "banana";
$salt = "a12dsfg33B1cD2eF3G"; # Can be any assortment of characters
$password = md5($salt.$password);
Then you would just attach the same salt (would have to match to work) and pass the same function to your login script that combines the salt and the supplied password. You would then check that to the value in your database to authenticate the user.
Do not invent your own password-hashing scheme, however nifty it may look. Having a secure system is hard because you cannot really test for security. What you need is the following:
For each password instance, a random salt of sufficient length is created.
The random salt is stored along the hashed value; you will need it to verify the password afterward.
The password hashing process must be (configurably) slow, with many (many) nested invocation of whatever hash function is internally used.
Preferably, the internal hash function should use operations which are efficient on a PC but slow on a parallel architecture (a GPU).
Such a thing exists, it is called bcrypt and you can get it in PHP with the portable PHP password hashing framework.
I am looking into building a login system and after reading the php manual when you pass a 2 digit salt to the crypt() function it returns a hash string, and the first 2 digits of the string are the salt that you used.
example:
$salt = "kr";
echo crypt("mysecret",$salt); //returns "kreOI.F7eOQMY"
My first thought was, wouldn't this help someone who is trying to reverse your hash?
I looked up salt on wikipedia which said:
For best security, the salt value is kept secret.
So I do not understand why then would the crypt function return all hashes prepended with the salt value used?
Is there a reason for this? Should this be a security concern?
The author of the Wikipedia article is conflating salt with the idea of search space, implying salt is a way to deter brute force attacks. Security is not improved by confusing these ideas; someone who can't recognize and delineate these two issues is not a credible guide.
The purpose of salt is to thwart pre-computed lookup tables (like a Rainbow table). Salt prevents an attacker from trading "space" for "time." Every bit of salt doubles the storage requirements for a table; a two byte salt makes a big (65536 times) difference, but eight bytes would require non-existent "yottabyte" storage devices for lookup tables.
Assuming that the salt cannot be kept secret encourages better key-strengthening and password selection, and this leads to more secure system.
However, recent recommendations from NIST encourage the use of an additional, secret "salt" (I've seen others call this additional secret "pepper"). One additional iteration of the key derivation can be performed using this secret as a salt. Rather than increasing strength against a pre-computed lookup attack, this round protects against live dictionary attacks. In this way, it's more like the large number of iterations in a good key derivation function.
This secret serves no purpose if stored with the hashed password; it must be managed as a secret, and that could be difficult in a large user database.
Brute force attacks are best prevented by key-strengthening (applying the hash function thousands of times), and password selection rules (require longer passwords, reject blacklisted entries, etc.), but a "pepper" provides an additional layer of defense.
I should comment that Crypt is not as bad as Marc B makes it sound, and may in fact be the easiest way to good hashes, as long as you don't rely on its weaker schemes like MD5.
See:
How do you use bcrypt for hashing passwords in PHP?
http://uk.php.net/manual/en/function.crypt.php
http://www.openwall.com/phpass/
Yes, the salt is supposed to be kept secret, but then so is the password hash. It's perfectly acceptable for them to be kept equally secret in the same place. To check a password against the hash, you have to combine the salt with the password and then check it against the hash. So, any user or process with the right to see the password hash should also have the right to see the salt, since the password hash by itself is not useful for checking passwords (unless you're going to brute-force the salt).
The purpose of the salt is so that if two different users have the same password, they'll hash to different things. This also means that dictionary attacks are much more complex because you can't just hash all likely passwords and then check them against a list of user password hashes to find multiple user's passwords. Instead you have to try passwords for an individual salt to find one user's password or try all combinations of likely passwords with multiple salts in order to find hits. But knowledge of the salt, by itself, doesn't mean you can reverse the password hash. It just means that you can do a dictionary attack on the password hash.
If you can find a way to keep the salt more secure than the hash value, it certainly wouldn't be a bad thing, but it's hard to see how this is feasible when any program which needs access to one needs access to both.
The crypt() function is obsolete. It was used to hash passwords for old-style Unix systems, before shadow password support came along. The salt was there to increase the complexity of brute forcing the password. However, since the salt was randomly generated by the password subsystem, it had to be stored in the clear so any future password actions would work. If the salt had been embedded into the password before crypting, there would be no practical way to verify a password - you'd have to try every single possible salt whenever a password check was done - highly impractical. So, the salt was prepended to the crypted password, so you could pull it out again for future use.
crypted password: xxabcdefghijklmn
^^- salt
^^^^^^^^^^^^^^-- crypted pw
if ('xx' + crypt('xx' + password) == 'crypted string') then
password is ok
endif
These days, crypt() is the security equivalent of a cereal box decoder ring. There for historical purposes, and low-security "who cares if it's cracked into" storage. For any modern password usage, you'd be better off with more modern hashes, such as sha1/sha256/md5. And even md5 is considered broken these days, sha1 has cracks around the edges, and (last I checked) sha256 is still secure.
The salt is appended to the has so that you will know which salt to use when you get the password and want to see if it matches the hash. The idea here is to use a different salt for every password so that someone cannot precompute a hash table.
You could also append a second salt to every password (the same for all) and not tell anyone what it is.
PHP crypt inherits this behaviour from the UNIX crypt() function, which was used for generating password hashes in the UNIX passwd file. It's necessary to store the salt somewhere, or you can't verify later that the password is correct. For the passwd file, the simple behaviour was just to prepend the salt (always two characters) to the start of the crypted password, which makes it simple to store it in a single field.
The statement that the salt value should be kept secret is open to misinterpretation. For best practice you should not publish your salts, in the same way that you should not publish your password hashes. Giving an attacker the hashes and salts makes it easy for them to run a brute-force attack without generating suspicious traffic to your system. However, the system should still be secure even if an attacker can see both salt and hashed password.
In fact, there's nowhere you can store the hash that couldn't, in principle, be compromised by a hacker in exactly the same way as the hashed passwords. If the password-checking code can access it, then you have to assume that someone who's compromised the system could get access to it as well.
I realize that this topic have been brought up sometimes, but I find myself not entirely sure on the topic just yet.
What I am wondering about how do you salt a hash and work with the salted hash? If the password is encrypted with a random generated salt, how can the we verify it when the user tries to authenticate? Do we need to store the generated hash in our database as well?
Is there any specific way the salt preferably should be generated? Which encryption method is favored to be used? From what I hear sha256 is quite alright.
Would it be an idea to have the hash "re-salted" when the user authenticates? And lastly is it any major security boost to rehash it a bunch of times?
Thank you!
The answer is to not do it yourself. The one-liner that will do everything you need in PHP is to use bcrypt.
Read this, it's easy to understand and explains everything you asked: http://codahale.com/how-to-safely-store-a-password/
bcrypt takes into account the hashing by itself, and can be configured to be as "complex" as necessary to maintain the integrity of your users' passwords in the event of being hacked.
Oh, and we don't "encrypt" passwords, we hash them.
You need to store both the hash and the salt that has been used to calculate the hash.
If you then want to check if an input is equivalent to the original input value, you can re-calculate the hash with the same salt and compare the stored hash with the new calculated one. If they are equal both input values are identical (up to some particular probability).
The choice of hashing algorithm is also important. Because there are fast hashing algorithms and rather slow hashing algorithms. And as you want to make is hard to find a collision (at least in brute-force), use a slower hashing algorithm.
What I am wondering about how do you
salt a hash and work with the salted
hash? If the password is encrypted
with a random generated salt, how can
the we verify it when the user tries
to authenticate? Do we need to store
the generated hash in our database as
well?
Yes. First you generate a salt, then generate a hash from the password plus the salt and save both hash and salt together.
Is there any specific way the salt
preferably should be generated?
I doubt that there's consensus on what's preferable. I use /dev/random. e.g.
$salt = '$2a$12$'
. strtr(substr(base64_encode(shell_exec(
'dd if=/dev/random bs=16 count=1 2>/dev/null'
)), 0, 22), '+', '.')
. '$';
$hash = crypt($input, $salt);
Which encryption method is favored to
be used? From what I hear sha256 is
quite alright.
See Computer Guru's answer, i.e. use bcrypt as in the example above. See the PHP manual page on crypt(). If bcrypt isn't on your system, one way to get it is the Suhosin patch.
Would it be an idea to have the hash
"re-salted" when the user
authenticates?
The salt just makes dictionary attacks slower. If you have a decent random salt to start with I wouldn't think changing it frequently would help. You'd probably be better off investing your effort in making users choose good passwords, changing them often enough and keeping your Blowfish cost parameter at a sensible value.
And lastly is it any major security
boost to rehash it a bunch of times?
That question belongs in the world of cryptographic design. I recommend you leave that to the experts. In other words: forget it—just use best common practices.
What generally you do is something like:
salted = HASH(password . key); // DON'T DO IT LIKE THIS
Where key is "the salt" - the secret key stored in configuration files. So in order to crack the password you would need both the secret key and the DB so it is good to store them
in separate places.
Because the schema I had shown is not strong enough, it is better to use HMAC for this purpose rather then hand written salting. Such an operation is as simple as hash and PHP supports this.
salted = hash_hmac('sha1',password,key); // <-- this is ok
See this: http://php.net/manual/en/function.sha1.php
Three simple rules. Okay, five:
Most important thing, if you want to consider your password storage being safe: allow strong passwords only e.g. at least 8 chars with some different case letters and numbers and even punctuation marks
Allow users to use strong passwords only. Make a routine to check length and character range and refuse weak passwords. Even get yourself John the ripper database and check against it.
Torture users wickedly, beat them up, until they choose good long and random enough passwords. Passwords! Not salt, of which everyone is delighted to talk for hours, but password itself should be random enough!
Salt your passwords and store that salt along with user info. you can use user email and username as a perfect salt, no need to invent something extraordinary random.
Certain algorithm is not that important, you can use MD5 as well. In real world there are very few people who would bother themselves with cracking user database of your famous Fishing And Grocery Fans Society site forums.
I was reading this tutorial for a simple PHP login system.
In the end it recommends that you should encrypt your password using md5().
Though I know this is a beginners' tutorial, and you shouldn't put bank statements behind this login system, this got me thinking about encryption.
So I went ahead and went to (one of the most useful questions this site has for newbies): What should a developer know before building a public web site?
There it says (under security) you should:
Encrypt Hash and salt passwords rather
than storing them plain-text.
It doesn't say much more about it, no references.
So I went ahead and tried it myself:
$pass = "Trufa";
$enc = md5($pass);
echo $enc; #will echo 06cb51ce0a9893ec1d2dce07ba5ba710
And this is what got me thinking, that although I know md5() might not the strongest way to encrypt, anything that always produces the same result can be reverse engineered.
So what is the sense of encrypting something with md5() or any other method?
If a hacker gets to a password encrypted with md5(), he would just use this page!.
So now the actual questions:
How does password encryption work?
I know I have not discovered a huge web vulnerability here! :) I just want to understand the logic behind password encryption.
I'm sure I'm understanding something wrong, and would appreciate if you could help me set my though and other's (I hope) straight.
How would you have to apply password encryption so that it is actually useful?
What about this idea?
As I said, I may/am getting the whole idea wrong, but, would this method add any security in security to a real environment?
$reenc = array(
"h38an",
"n28nu",
"fw08d"
);
$pass = "Trufa";
$enc = chunk_split(md5($pass),5,$reenc[mt_rand(0,count($reenc)-1)]);
echo $enc;
As you see, I randomly added arbitrary strings ($reenc = array()) to my md5() password "making it unique". This of course is just a silly example.
I may be wrong but unless you "seed the encryption yourself" it will always be easily reversible.
The above would be my idea of "password protecting" and encrypted password, If a hacker gets to it he wont be able to decrypt it unless he gets access to the raw .php
I know this might not even make sense, but I can't figure out why this is a bad idea!
I hope I've made myself clear enough, but this is a very long question so, please ask for any clarification needed!
Thanks in advance!!
You should have an encryption like md5 or sha512. You should also have two different salts, a static salt (written by you) and then also a unique salt for that specific password.
Some sample code (e.g. registration.php):
$unique_salt = hash('md5', microtime());
$password = hash('md5', $_POST['password'].'raNdoMStAticSaltHere'.$unique_salt);
Now you have a static salt, which is valid for all your passwords, that is stored in the .php file. Then, at registration execution, you generate a unique hash for that specific password.
This all ends up with: two passwords that are spelled exactly the same, will have two different hashes. The unique hash is stored in the database along with the current id. If someone grab the database, they will have every single unique salt for every specific password. But what they don't have is your static salt, which make things a lot harder for every "hacker" out there.
This is how you check the validity of your password on login.php for example:
$user = //random username;
$querysalt = mysql_query("SELECT salt FROM password WHERE username='$user'");
while($salt = mysql_fetch_array($querysalt)) {
$password = hash('md5',
$_POST['userpassword'].'raNdoMStAticSaltHere'.$salt[salt]);
}
This is what I've used in the past. It's very powerful and secure. Myself prefer the sha512 encryption. It's actually just to put that inside the hash function instead of md5 in my example.
If you wanna be even more secure, you can store the unique salt in a completely different database.
Firstly, "hashing" (using a cryptographic one way function) is not "encrypting". In encryption, you can reverse the process (decryption). In hashing, there is (theoretically) no feasible way of reversing the process.
A hash is some function f such that v cannot be determined from f(v) easily.
The point of using hashing for authentication is that you (or someone seeing the hash value) do not have any feasible way (again, theoretically) of knowing the password. However, you can still verify that the user knows his password. (Basically, the user proves that he knows v such that f(v) is the stored hash).
The weakness of simply hashing (aside from weak hash functions) is that people can compile tables of passwords and their corresponding hash and use them to (effectively) get the inverse of the hash function. Salting prevents this because then a part of the input value to the hash is controlled and so tables have to be compiled for that particular salt.
So practically, you store a salt and a hash value, and authenticate by hashing a combination of the salt and the password and comparing that with your hash value.
MD5 is a one way hashing function which will guard your original password more or less safely.
So, let's say your password is "Trufa", and its hashed version is 06cb51ce0a9893ec1d2dce07ba5ba710.
For example, when you sign in to a new webpage, they ask you for your username and password. When you write "Trufa" as your password, the value 06cb51ce0a9893ec1d2dce07ba5ba710 is stored in the database because it is hashed.
The next time you log in, and you write "Trufa", the hashed value will be compared to the one in the database. If they are the same, you are authenticated! Providing you entered the right username, of course.
If your password wasn't stored in its hashed form in database, some malicious person might run a query somehow on that database and see all real passwords. And that would be compromising.
Also, since MD5 is a 128 bit cryptographic function, there are 2^128-1 = 340282366920938463463374607431768211455 possible combinations.
Since there are more possible strings than this, it is possible that 2 strings will generate the same hash value. This is called a collision. And it makes sure that a hashed password cannot be uniquely reverse engineered.
The only vulnerability with salting is that you need to know what the salt is in order to reconstruct the hash for testing the password. This is gotten around by storing the entry in the authdb in the form <algorithm>$<salt>$<hash>. This way the authdb entry can be used by any code that has access to it.
You're missing the important step - the salt. This is a unique (per user, ideally) bit of extra data that you add to the password before hashing it.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
Your idea (salting) is well known and is actually well-implemented in the PHP language. If you use the crypt() function it allows you to specify a string to hash, a method to encrypt (in some cases), and a salt. For example,
$x = crypt('insecure_password', $salt);
Returns a hashed and salted password ready for storage. Passwords get cracked the same way that we check if they're right: we check the hash of what the user inputs against the hash of their password in the database. If they match, they're authenticated (AFAIK this is the most common way to do this, if not the only). Insecure passwords (like password) that use dictionary words can be cracked by comparing their hash to hashes of common passwords. Secure passwords cannot be cracked this way, but can still be cracked. Adding a salt to the password makes it much more difficult to crack: since the hacker most likely doesn't know what the salt is, his dictionary attack won't work.
For a decent hash the attacker won't be reversing the hash, they'll be using a rainbow table, which is essentially a brute-force method made useful if everyone uses the same hash function.
The idea of a rainbow table is that since hashing is fast I can hash every possible value you could use as a password, store the result, and have a map of which hash connects to which password. If everyone just takes their passwords and hashes them with MD5 then my hash table is good for any set of password hashes I can get my hands on!
This is where salting comes in. If I take the password the user enters and add some data which is different for every user, then that list of pre-determined hashes is useless since the hash is of both the password and some random data. The data for the salt could be stored right beside the password and even if I get both it doesn't help me get the password back since I still have to essentially brute force the hash separately for every single user - I can't form a single rainbow table to attack all the hashes at once.
Of course, ideally an attacker won't get the list of hashed passwords in the first place, but some employees will have access so it's not possible to secure the password database entirely.
In addition to providing salt (or seed), the md5 is a complex hashing algorithm which uses mathematical rules to produce a result that is specifically not reversable because of the mathematical changes and dataloss in throughput.
http://en.wikipedia.org/wiki/Cryptographic_hash_function
md5 (or better put: hash algorithms in general) are used to safely store passwords in database. The most important thing to know about hashes is: Hashes are not encryptions per se. (they are one-way-encryptions at most). If you encrypt something, you can get the data back with the key you used. A hash generates a fixed-length value from an arbitrary input (like a string), which can be used to see if the same input was used.
Hashes are used to store sensitive, repeatly entered data in a storage device. Doing this, nobody can recreate the original input from the hash data, but you can hash an incoming password and compare it to the value in the database, and see if both are the same, if so, the password was correct.
You already pointed out, that there possibilites to break the algorithm, either by using a database of value/hash pairs or producing collisions (different values resulting in the hash value). You can obscure this a bit by using a salt, thus modifying the algorithm. But if the salt is known, it can be used to break the algorithm again.
I like this question. But I think you've really answered yourself.
The site you referenced uses dictionary lookups of known, unsalted, md5's - it doesn't "crack" anything.
Your example is almost good, except your application needs to be able to regenerate the md5 using the same salt every time.
Your example appears to use one of the random salts, which will fail 2 of 3 times if you try to compare a users password hash to something input.
People will tell you to also use SHA1 or SHA256 to be have a 'stronger' hash - but people will also argue that they're all 'broken.'
That documentation is misleading -- it teaches a "vulnerable" concept and presents it as somehow being "secure" because it (the saved password) looks like gibberish. Just internet junk that won't die. The following link should clear things up (you have already found a good bit of it though, it seems. Good work.)
Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes talks about MD5 (and why it should not be used) along with salt (e.g. how to thwart rainbow attacks) as well as provides useful insights (such as "Use someone else’s password system. Don’t build your own"). It is a fairly good overview.
This is my question about the aspects of md5 collision, slightly related to your question:
Is there any difference between md5 and sha1 in this situation?
The important part is in the first 3 rows, that is: you must put your salt before the password, if you want to achieve stronger protection, not after.
To simply answer the title of your question, md5's only real use nowadays is for hashing large strings (such as files) to produce checksums. These are typically used to see if both strings are identical (in terms of files, checksums are frequently used for security purposes to ensure a file being distributed hasn't been tampered with, for example).
To address each of your inline questions:
How does password encryption work?
How would you have to apply password encryption so that it is actually useful?
Secure password hashing works by taking the password in plain text form, and then applying a costly hashing function to it, salted with a cryptographically secure random salt to it. See the Secure hash and salt for PHP passwords question for more detail on this.
What about this idea?
Password hashing does not need to be complicated like that, and nor should it be. Avoid thinking up your own algorithms and stick with the tried and tested hashing algorithms already out there. As the question linked above mentions, md5() for password hashing has been obsolete for many years now, and so it should be avoided.
Your method of generating a "random" salt from an array of three different salts is not the randomness you're looking for. You need unique randomness that is suitable for cryptographically secure (i.e. using a cryptically secure pseudo-random number generator (CSPRNG)). If you're using PHP 7 and above, then the random_bytes function can be used to generate a cryptographically secure salt (for PHP 5 users, the random_compat library can be used).
So I've been reading a lot about encryption in PHP. So much that I am not sure exactly what's a really good method to securely store login information.
However, the following function is what I came up with:
function loginHash($username, $password){
$salt = str_split($password,(strlen($password)/2)+1);
$hash = hash('whirlpool', $username.$salt[0].'centerSalt'.$salt[1]);
return $hash;
}
Am I doing it the right way? It's used for authenticating a password combined with a username, and the ability to compare the generated hash with the one stored in a database to verify a login.
Encrypting != Hashing. They both are generally accepted to be in the category of Cryptography, but when something can be encrypted, it can be decrypted, which is not the case in Hashing. Hashing is just hashing, and that's it.
The salt is indeed not properly constructed. It should be x-bytes read from /dev/urandom with a fopen() call. For example, 16 bytes of salt is what I personally use. This prevents rainbow table attacks effectively.
To make things more secure, use a secret key, too. For example:
$hashedPassword = hash_hmac('whirlpool',$password.$salt,$key);
The $key is simply random data. You could generate a 64 kB file, for instance, that is called "key.bin" in a hidden folder above the document root and use file_get_contents() before the hash process.
Why to use secret keys? If you store the hashes and salts in a database and the key in the filesystem, then this prevents anyone from cracking your hash if they get their hands on your stored hashes and salts. So, an attacker would need to crack into both the database and the filesystem to crack your hashes, but notice that it's pointless for anyone to crack your hashes anymore if they have already cracked your whole application, which implies that your hashing scheme is good.
My advise is to never, never, never write your own encryption and hash functions. Even experts do it wrong all the time, so dont try it yourself.
Ive heared that phpass (Openwall) is a nice hashing framework, i'd suggest you use that.
They use salts in their hashes and have quite some parameters to tweak the hash.
You're not actually using a salt.
Salt is a randomly generated string that is included in the input for your hash function. As such, it will be different every time.
The idea is that you generate a salt when a user stores a password, and that this salt is included in your data storage. When authenticating, you retrieve the salt and the stored hash, you prefix the given password with the stored salt, and hash the two together. Then compare the result with the stored hash.
I think the above code checks the two boxes.
Avoiding rainbow table attacks (via Salts)
Secure Login
using salt solves two problems:
rainbow tables: rainbow tables are just precalculated hashes, stored with the source value. by comparing the hashes, you get the unhashed value (password). by adding salt you got another layer of complexity - the attacker must know the salt for generating a custom hashing table.
difference of hashed values: without salt, the same 2 passwords generate the same 2 hashes. now it's easy to see if two users use the same password (the weak point here is about the same as with the rainbow tables, but still). that may not amount to much, but is still a point of concern.
additionally, you shouldn't use fast algorithms for password hashing. md5 is fast, sha is fast. the slower, the better.
the matsano chargen blog is a good (and funny) resource for hints and pointers regarding security.