store hashed passwords to Mysql - php

I was researching about hashing and storing passwords to database on PHP.NET.
This site said:
If you are for example storing the data in a MySQL database remember that varchar fields automatically have trailing spaces removed during insertion. As encrypted data can end in a space (ASCII 32), the data will be damaged by this removal. Store data in a tinyblob/tinytext (or larger) field instead.
which of this suggests are better? or may be I have to ask: Is one of them better? and if the answer is yes, which?
and finally how should I store passwords to db using PDO. I thought I can write information to a blob row just like files, but if I get the values from input, which method or function have to used?
Would you explain about please?

When storing hashed passwords, then whitespace removal is a non-issue:
You never store the passwords themselves, but the output of a hash function instead.
This hash function produces fixed-size output (or you are likely using a reversible encryption algorithm).
The output of most hash functions is already fixed-sized plaintext[1] that doesn't include any spaces. Otherwise, you are probably using a hash function not intended for password hashing.
The fixed-sized salt is stored along with the hash output (Password hashing functions which are aware of salting usually output the salt with the hashed password).
If you want to be flexible and be able to upgrade to a better hash function in the future, you also have to remember which hash function was used. It is recommendable to use plaintext[1] for this information, which makes the complete record variable-length. RFC 2307 describes such a possible plaintext[1] storage scheme.
Passwords should be hashed with a modern and proven key-stretching algorithm, but not with cryptographic hash functions like SHA-256 or MD5. Suitable algorithms include PBKDF2, bcrypt, or scrypt.
For example, hashing the string "pass phrase" with bcrypt and a new salt may produce
$2a$12$PuYHvYwgKeD.hQ1Dv6nLQuxUkv5zP3lYLPHqdMOzgwPVaGGSAs07u
`-----'`-----------······· ·········-------'
algorithm random salt password hash
parameters
The whole string can be used as salt, as the actual password hash will be cut off and not be used as salt.
Recommended workflow for validating a login attempt:
The user provides an username and password. Be careful to handle Unicode normalization and encodings.
The hashed password is fetched from the DB based on the username.
The hashed password is parsed to determine the algorithm used.
The correct algorithm is invoked with the user password as input with the hashed password as salt.
If the two hashes match, then a correct password was provided by the user.
Recommended workflow for setting a new password:
If the user already exists, authenticate him.
Obtain a new password from the user. Take care to handle Unicode normalization and encodings. Give the user feedback on the strength of his password (but do not frustrate the user with silly requirements like forbidden characters or restrictive maximal lengths).
Create a new salt, which must not depend on user input like the password or user names.
Pick a strong password hashing function and hash the password with the new salt.
Update the DB to store the new password along with an identifier for the hash function.
Further comments:
Encrypted data is binary data, and should not be stored as text (use a blob instead).
Hashes are usually often represented as plaintext and not as binary data because text is easier to store.
In many scenarios you can use OpenID instead of implementing your own authentication. E.g. Stack Exchange offers login with OpenID. Because I use this option, I never had to disclose a password to SE.
I have no cryptographic background. Information Security is frequented
by people who understand more of the matter.
[1] Here, “plaintext” means printable ASCII characters. It does not refer to the clear text of a password.

Related

PHP MySQL User Password Encryption

I am using following way to encrypt user's passwords which is AES Encryption. I just want to know is this a good practice or is there any other method should I follow. Because someone made me confused saying "Why don't you use "SALT". Can I use SALT AES Encryption? with Bellow is a sample query I am using.
INSERT INTO user(id,passowrd) VALUES (1,AES_ENCRYPT('mypassword','key'));
I hope your database column isn't named "passowrd".
That aside..
Salt isn't an encryption method, it's a random bit you need to add to each password before hashing to protect against dictionary attacks.
You should not be storing user passwords using AES encryption, which is reversible. You don't care what the user's password is, only that they know it: so don't store the password in a reversible form.
Instead, you use a secure one-way hash, such as SHA256 or even bcrypt, of the password plus some random data. This random junk, the "salt", is generated for each user and appended to the password before hashing. It is then stored in the database along with the hashed data to enable you to compare the passwords later.
This way, an attacker with what's called a rainbow table (a big dictionary of hash-to-plaintext mappings) can't come along and see "oh look, Joe User decided to make his password 'password'!". This also protects against someone brute-forcing all the passwords in your database, since if each account has its own independent salt, each password must be independently attacked.
You wouldn't use "SALT" with AES, typically it's used with SHA.
Great details and explanation can be found at:
https://stackoverflow.com/a/4351749/1232478
A salt is a sequence of characters added to a string about to being hashed, so it's harder for an attacker to obtain the original string.
However, for a cipher algorithm that is not based on hash, a salt isn't necessary, because the attackers will obtain anyway the original string with the salt, and it's just needed logic to remove it.
With AES_ENCRYPT the key you're using IS the salt. I prefer one-way hashes like MD5 or SHA, but many like decryptable passwords like you're storing.

Should I store my salt along with my hashed password in the database?

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.

Why does PHP crypt() prepend the salt to the hash?

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.

Using crypt(), how does my app validate passwords that have randomly generated salts?

I've been looking at PHP's crypt function and a few questions on Stackoverflow, and I'm trying to figure out salted and hashed passwords.
I found this on the PHP community page:
<?php
function md5crypt($password){
// create a salt that ensures crypt creates an md5 hash
$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
.'abcdefghijklmnopqrstuvwxyz0123456789+/';
$salt='$1$';
for($i=0; $i<9; $i++){
$salt.=$base64_alphabet[rand(0,63)];
}
// return the crypt md5 password
return crypt($password,$salt.'$');
}
?>
How does something like that compare to:
<?php
// Slightly modified example from PHP community page
$password = trim(mysql_prep($_POST['password']));
// Get the hash, letting the salt be automatically generated
$hashed_password = crypt($password);
?>
Here's an excerpt from another question:
However, the PHP crypt() function can
use a variety of different hashes to
compute the hash. When you prefix your
salt with "$1$" you get a hash with an
MD5. When you prefix with $2$ you get
a crypt with blowfish, which is more
secure.
The "$1$" is prefixed to the output so
that the hash can be verified. If it
wasn't included, there would be no way
to know from the stored hash which
algorithm should be used! This
information would have to be stored
elsewhere. To save you this trouble
PHP includes the algorithm in the hash
output.
My head is spinning a bit concerning hashes, encryption and salts... but the part that really stumps me, is how do I compare a user-entered password against a salted hashed password, if the salt is randomly generated upon user creation... and not stored--and on top of that, what's the point of using crypt() with an automated salt, if you HAVE to specify the correct prefix to be able to validate the password again upon user return?
You need to store the salt with the user.
The purpose of the salt is to ensure that two users with the same password get different hashes.
This prevents rainbow table attacks.
EDIT: Your salt should contain (cryptographically-secure-)random bytes.
Right now, you're restricting it to only contain letters and numbers
The idea is to have a random salt for every user/password.
Adding a salt will just make more difficult to guess your password, but using a random salt for every account will increase the security as it'll reduce the way for an attacker to guess any other passwords, as given some current and unsecure password and/or username, the reverse engineering to guess password would be easy.
It has a big impact on cross-system security as people tends to use the name username/password on most sites.
Using a random salt makes an attack almost impossible with a dictionary as you'll need to compute every salt possible to guess any password.
If you look closely at the format of /etc/shadow, you'll see the nomenclature in the second field (with : delimiting fields):
username:${enctype}${salt}$HoPeFuLlYVerYloNGpassWOrDhAsh: ... ... ...
The salt is actually stored with the password. {enctype} is the type of encryption being employed, {salt} is the salt. Since you know the encryption type and salt, you can naturally reproduce the hash with the password they provide (thus authenticating the user).
A handy table of {enctype} values for crypt (for informational purposes):
ID | Method
─────────────────────────────────────────────────────────
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
And finally, how PHP lets you use them.
So, if you see a string like:
root:$6$foobar$JKLsdiuoilI/KSJHDKUyjh/SHDKJyUYW(....)
You know that you're dealing with SHA-512 and the salt is 'foobar' (and likely, the account is foobar too!).
It is (one) example of how salts are stored and associated with hashes. As SLaks said, don't restrict the salt to just ASCII. At the minimum you should be obtaining bytes from a PRNG or HRNG, falling back to time() only when no RNG is available.
No, You are doing it wrong. Use solardesigner's PHPASS in order to do the hashing and validation. Finally, never EVER use your own ad-hoc scheme, doing that is asking for trouble.

What is md5() for?

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).

Categories