We are following a pretty standard user id / password check. We store the hashed password in the db. When the user enters credentials we hash the entered password then compare to what the db has. If they match then user is authenticated.
Now this login process under load test is slowing down considerably so I was asked to look at it. VS 2013 Profiler pointed out the hashing method as a hot path. Looking at the method in question we are looping over the hashing process??
private const int totalHashCount = 1723;
public string CreateHash(string salt, string password, int securityIndex)
{
string hashedPass = this.GenerateHashString(salt + password, securityIndex);
for (int i = 1; i <= totalHashCount; i++)
{
hashedPass = this.GenerateHashString(hashedPass, securityIndex);
}
return hashedPass;
}
I went to the developer and he stated the client's security team wanted us to rehash the hash and to do it some prime number greater than 1000....and he provided the email as documentation.
Now I am not a cryptology expert and we have a good relationship with the client so before I went to them and connected this rehash loop to their performance woes I wanted to see if rehashing like this does indeed increase security?
To my understanding a single hash is practically impossible to invert so why waste cycles repeating the process?
Thoughts?
Edit
Added GenerateHash:
protected internal string GenerateHashString(string textToHash, int securityIndex = 0)
{
UnicodeEncoding uEncode = new UnicodeEncoding();
SHA512Managed sha = new SHA512Managed();
byte[] bytVal = uEncode.GetBytes(textToHash + hashIntPool[securityIndex].ToString());
byte[] hashVal = sha.ComputeHash(bytVal);
return Convert.ToBase64String(hashVal);
}
Repeating the hash operation is essential to secure password authentication, but you are doing it wrong and therefore indeed wasting CPU to achieve nothing.
You should use an algorithm like PBKDF2 that includes the password in each round of hashing in order to preserve all the unpredictability of the password. bcrypt and especially scrypt are good alternatives too.
Also, one thousand rounds is not nearly enough; to be secure against offline dictionary attacks, you need the hashing operation to be relatively slow, even when performed on the attacker's dedicated password testing hardware. Picking a prime number of rounds is meaningless mumbo jumbo. The number of rounds will depend on the algorithm you select, but for PBKDF2 with SHA-256, somewhere between 10,000 and 100,000 rounds should provide a reasonable level of security.
A slow algorithm is necessary to prevent an attacker who obtains a hash from quickly trying many different passwords to see which produces the same hash. It's true that a secure hash is not feasible to invert, but it won't stop guessing, and attackers are good at prioritizing their guesses to try the most likely passwords first. Repetition of the hash is what provides this necessary slowness.
This has been discussed many times on StackOverflow. I refer you to a previous answer for more background.
In C#, you could use Rfc2898DeriveBytes to perform password hashing securely. You can encode the derived key in Base-64 to be stored as a string, or actually use it as an encryption key to encrypt a known plain text like the bcrypt algorithm does. You'll notice that Rfc2898DeriveBytes uses a "salt", which I discuss elsewhere; you'll need to store this value along with the hash value to perform authentication later.
The technique, called "stretching", of repeated hashing is used to make brute force attacks more difficult. If it takes 0.1 second to hash a password (due to the repetitions) then an attacker can at best try 10 passwords a second to find a match. If you speed up the hashing process so it takes a microsecond, then the attacker can test a million passwords a second.
You need to balance speed against security. A user login only need to be fast enough to satisfy the user, so 0.1 to 0.5 second is probably acceptable.
If your server is overloaded then get a faster processor, or buy a dedicated hashing server. That will be a lot cheaper than the legal consequences of a data breach.
Related
I'm trying to secure my c# app. I know that we MUST store password hash and salt in DB. So my question: How I can compare that password is correct if I use Random salt? (Random salt gives random values each time).
I also have the code below
public static string HashPassword(string p, string s)
{
var combinedPassword = String.Concat(p, s);
var sha256 = new SHA512Managed();
var bytes = UTF8Encoding.UTF8.GetBytes(combinedPassword);
var hash = sha256.ComputeHash(bytes);
return Convert.ToBase64String(hash);
}
public static String GetRandomSalt()
{
var random = new RNGCryptoServiceProvider();
var salt = new Byte[1024];
random.GetBytes(salt);
return Convert.ToBase64String(salt);
}
I am open to other suggestions in general.
I am open to other suggestions in general.
I will preface this post by making a broad point but I believe it is widely enough held to not constitute an "opinion".
If you are doing this "to secure your app", stop now. There are much better solutions like BCrypt, Scrypt and Argon which take care of all this for you and protect against threats that most people haven't even considered. These of course include salt(s) internally, so understanding what they are for and how they work is still a useful endeavour. For approximately the same amount of code, you will be handling the credentials a lot more securely than the posted code indicates. Google them for details.
If you are just doing this as "an exercise to understand how it all works", continue reading.
So what is salt exactly and why is it useful for protecting security?
Salt is additional entropy that is not part of the user's password, but is instead known to or invented by the server at the time the password is hashed and stored. The generated salt must be known to the server when validating your password. There are many ways it can be stored. It may be the first/last/middle/every8th/whatever n characters of the password hash stored in the database. It may have its own separate field. It may even be based on other facts immutable like Primary Keys of the user record itself.
The threat model that this protects against could be described like this. Consider a database that was compromised and now held by a malicious actor. The challenge is, given the malicious actor holds the credentials (in hashed form), can we stop them from guessing people's password (at least without trying some sort of dictionary or brute force guess attack.
If you thought hashing solved that problem, then I will give two possible scenarios:
1. Two users may use the same password
If the password is hashed but not salted, then two users who choose the same password will end up with the same hash. And even if the password isn't "terrible", the other user may reveal your password by whatever they entered as the "Password Hint". If the passwords were salted, then the fact that the password hint gave away the other user's password doesn't leak the fact that the same password would work on your account.
2. Rainbow tables
If you have enough time and compute power, you can generate (or download) a set of rainbow tables. These are basically key-value pairs, where the key is the hash and the value is the original password. These are generated in reverse. That is to say, take a string, hash it, add the hash as the key and the original string as the target. To lookup, you simply lookup the hash key and see what value comes back. Near instantly. With a long enough original string though, it won't have been pre-computed so it won't have a hit in the rainbow table. If I know the salt you are using and the hashing algorithm, I can still do my own dictionary attack or brute force attack, but suddenly I am required to try each guess in turn until I am lucky, so if your password is good, I will not find it in "reasonable time".
The precise answer to your posed question
How I can compare that password is correct if I use Random salt?
Your verification process needs to know or derive exactly what exact salt value was chosen for the hash process. The salt may be randomly generated, but if so it needs to record the exact value used.
First , you have to get salt in database by username , then hash it with posted password , finally compare it to password stored in database
I'd like to generate (secure) local admin passwords based on computer names in our organisation. This way I can build a small UI that takes the computername and gives the password.
With PowerShell we will use the same DLL to generate the password and set it on each workstation.
I've already searched, but all the things I find about cryptography in C# is to hash a password, but I need the hash itself to be the password.
The password should also be of a length between 8 and 12 characters to make it easy enough to type it in.
I'm using .NET Core 2.0 (could use .NET Framework too if needed)
You definitely want to be able to change the passwords on your machines, so include some sort of date or counter in the formula.
You ideally also want to include some form of authentication into the tool, whether that be a master password, a complicated thing with smartcards, or something else. That way when your tool gets into the hands of a baddie they don't necessarily get all your data.
If you go the master password route, you need a plan for how to deal with suspecting that got leaked. (Including someone who knew it leaving the organization, since that's a leak.)
A strawman example which includes:
Using a date
Using a master password
Using HMAC to process the machine name, keyed by a key from the master password
An iteration count to PBKDF2 which matches modern computers.
.
private static string GeneratePassword(
string masterPassword,
string machineName,
DateTimeOffset lastChangeDate)
{
// Use the date (ignoring time) of the last password change as a salt.
byte[] salt = BitConverter.GetBytes(lastChangeDate.ToUniversalTime().Date.Ticks);
HashAlgorithmName prf = HashAlgorithmName.SHA256;
using (var pbkdf2 = new Rfc2898DeriveBytes(masterPassword, salt, 123456, prf))
{
byte[] key = pbkdf2.GetBytes(256 / 8);
using (HMAC hmac = new HMACSHA256(key))
{
byte[] value = hmac.ComputeHash(
Encoding.UTF8.GetBytes(machineName.ToUpperInvariant()));
// Or however long.
return Convert.ToBase64String(value).Substring(0, 16);
}
}
}
The Rfc2898DeriveBytes constructor overload which takes a HashAlgorithmName for the PBKDF2-PRF is new in netcoreapp20. If you are trying to be netstandard20 you can drop the last parameter and use the SHA-1-based version with probably little harm (since HMACSHA-1 isn't currently considered broken).
When going to change a password for a machine you'd enter the date of the last generation to get the existing one. Then enter today's date to get the new value, then write down the new date in whatever text file / spreadsheet / database / sticky note remembers these things.
Another alternative is generating random passwords and saving them in an encrypted structured file. Something like EnvelopedCms as the encryption container gives you smartcard for nearly free, and lets you add/remove readers without changing all the machine passwords (adding is easy, removing might warrant changing them all anyways).
Which is to say: Building a stable generator and deploying the usage is easy. It's maintaining it that gets tricky. Maintaining random might be easier, therefore it's possibly better to pay the cost up front.
I don't know if this is such a good idea - the tool only works as long as the passwords on each and every computer stay unchanged.
Anyway, you could hash the computer name and use the result as a password. Most if not all hashes produce larger hashes than 8-12 "easy enough to type in" characters, but you can solve that by:
Base64 encoding the hash (to get letters, numbers and a couple of other characters)
Take the desired number of characters from the result.
To make this a bit safer, let your UI take a password (a single one) and append it to the computer name before computing the hash. This way, when someone steals your tool, they still won't be able to generate valid passwords.
You won't ever be able to change that password, though. If you share it with a coworker, they will know how to reproduce every password, forever.
The code that follows uses the PRNG (pseudo random number generator) Random class to generate password characters for the initial temporary password instead of the much more cryptographically secure RNGCryptoServiceProvider as it should have used.
However, it does use the RNGCryptoServiceProvider to generate a seed for the PRNG, so I'm thinking that's maybe worth something, instead of seeding based on the current time of day as is typical practice when using a PRNG where security is not a concern.
My question is: how easy or difficult is this approach to attack in order to compromise the password generation system and guess new users' passwords?
// Generate 4 random bytes.
byte[] randomBytes = new byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);
// Convert 4 bytes into a 32-bit integer value.
int seed = (randomBytes[0] & 0x7f) << 24 | randomBytes[1] << 16 | randomBytes[2] << 8 | randomBytes[3];
// Now, this is real randomization.
Random random = new Random(seed);
The code then goes on to use random.Next() to generate characters to fill in the password string.
DISCLAIMER: This code is not of my invention. Do not blame me for it nor offer suggestions on how to fix it. I know how to fix it and I know it is bad. Do not waste time replying as such. Any comments or answers to this effect will be flagged as spam. I only found it in our code and am curious about its "security" properties.
The issue with PRNG functions is that of predictability. Being able to predict it's output based on previous output. The reason to avoid using the Random class is that by monitoring it's output, one can then start to predict future output.
The code above may or may not be a problem. This boils down to how often the Random class is instantiated. If you are creating a new instance with a seed from a crypto-strength PRNG and generating only a single password from that then you should be OK. I say this because even if I learn the state of the PRNG from one generated password, it has no relationship to future passwords generated.
If you instead are using this routine to initialize a static instance of Random, then you certainly have a potential problem. Let's say someone used this approach to send temporary reset passwords to an email. An attacker could reset their own password enough times to start predicting the future passwords. Once he can predict the next password, he simply initiate the rest for the account he wishes to compromise. Already knowing the password that was emailed, he can then access the account.
I am creating a login screen for an application in C#. In my login screen I am reading the username and password from the database and checking whether the entered username and password are correct or not. I need the password to encrypt while I am reading the password form the database. Can anyone explain how encryption and decryption works.
Whether I have to store the encrypted value in the database for reading.
Right now I have two fields
column names: username password
values: admin password
Should I store the encrypted value of the password in another field in the login table?
First: The common approach now is that store the salted hash of the password, instead of the plain-text password itself (SHA-1 and better hashing algorithm are preferred, avoid MD5 because it's not safe any more) . When the user login, you recalculate the hash of the input string, then compare it with string stored in the database.
EDIT: why shouldn't you use encryption for password? Because when the attacker knows the key of encryption, all of you passwords will be exposed (That's very bad). If you using hash, he just can guess one-by-one (and this is not easy). Otherwise, hash algorithms, in general, are faster then encryption, you'll take the performance benefit.
EDIT: why you should store salted hash, instead of a hash? Because hashing algorithms are guaranteed that if you hash identical strings, the result is the same. This may lead to a problem is that, when attacker see the same hash values, he can guess that the texts were the same, and this gives chance for him to get the original password.
Salt means that besides the original text, you put some random text, and therefore, two identical strings will generate different hash values
Take a look at this: http://www.obviex.com/samples/hash.aspx
In case of the user forgets his password, you can use the reset password function, which many sites are using:
The user requests a password reset
An email contains a special link (include a secret token/PIN) will be sent to registered email address, that allows user to reset his password.
A randomly created password will be sent again to user, then he can login and change his password.
UPDATE May 14th 2012: The answer seems to be old, and not completely true. People are moving to more secure hashing-encryption algorithm for storing password. One of notable solution now is bcrypt, and another (new and promising) is scrypt.
The advantage of these encryption? They're slow! Much slower than hashing algorithm. With the power of GPU (for example, CUDA from nVidia), cracking the hash value is not impossible now, and the slowness can make it much harder to crack these encryption.
You can find more about bcrypt at: http://codahale.com/how-to-safely-store-a-password/
Second: You should separate the users table (contains user profiles, such as full name, DoB, address,...) and logins table (Which contains user name and password, and some special attributes). This will lead to better management and reduce the risk of exposing sensitive information
Along with given advices, there are other methods to protect passwords:
One-Time Password: In spite of
implementing salted hash, passwords
are still stored on hard disk and
are prone to be cracked. So a better
approach is required here. In
contrast with static passwords,
one-time passwords are changed each
time a user logs on to the system
and usually users should carry a
small hardware used for
synchronizing with server. Mainly
there are two types of OTP: (Visit Safer Authentication with a One-Time Password)
Time-Synchronized
Counter-Synchronized
Using BCrypt which uses a variant of the Blowfish encryption algorithm's keying schedule and contains a work factor, which lets you determine how expensive the hash function will be. In order to get familiar with bCrypt, visit: http://codahale.com/how-to-safely-store-a-password/
In C#, you can use BCrypt.Net library which is a port of iBCrypt library: read the following article to understand how to get this library up and running in Visual Studio.Net:
Using BCrypt in a .NET Application – Why it’s better than SHA or MD5.
Of course, there are a lot of discussions about this algorithm in SO, search and study more about this.
Are you implementing your own authentication mechanism? You can use already existing System.Web.Security microsoft authentication. By using Membership class you can validate user password without retrieving it from the database. This way you will be able to store the salted (encrypted) password in your database. Just use Membership.CreateUser and Membership.ValidateUser.
If you don't need (performance wise or proprietary implementation) use existing implementations and save time.
The password should be stored in database with encrypted value itself. And when user tries to login, encrypt the password with the same algorithm and then compare it to the value in db.
Md5 is usually used for password encryption as it cannot be decrypted. Incase the user forgets the password, he cannot retrive it back, but it can only be reset.
Hope this helps !
You can encrypt the passwords in many ways.
One of the way is using the MD5 encryption. Let me show you one of the encryption method that I am using.
#region Encrypt
public string Encrypt(string simpletext, string keys)
{
try
{
XCryptEngine xe = new XCryptEngine();
xe.Algorithm = XCrypt.XCryptEngine.AlgorithmType.DES; //DES = Data Encryption Standard
string cipher = xe.Encrypt(simpletext, keys);
if (cipher != null)
return (cipher);
else
return null;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#region Decrypt
public string Decrypt(string simpletext, string keys)
{
try
{
XCryptEngine xe = new XCryptEngine();
xe.Algorithm = XCrypt.XCryptEngine.AlgorithmType.DES;
//Console.WriteLine(xe.Decrypt(simpletext, keys));
simpletext = simpletext.Replace(" ", "+");
string cipertext = xe.Decrypt(simpletext, keys);
if (cipertext != null)
return (cipertext);
else
return null;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
you need to use reference for XCrypt to use this.
using XCrypt;
The .NET framework ships with 6 different hashing algorithms:
MD5: 16 bytes (Time to hash 500MB: 1462 ms)
SHA-1: 20 bytes (1644 ms)
SHA256: 32 bytes (5618 ms)
SHA384: 48 bytes (3839 ms)
SHA512: 64 bytes (3820 ms)
RIPEMD: 20 bytes (7066 ms)
Each of these functions performs differently; MD5 being the fastest and RIPEMD being the slowest.
MD5 has the advantage that it fits in the built-in Guid type; and it is the basis of the type 3 UUID. SHA-1 hash is the basis of type 5 UUID. Which makes them really easy to use for identification.
MD5 however is vulnerable to collision attacks, SHA-1 is also vulnerable but to a lesser degree.
Under what conditions should I use which hashing algorithm?
Particular questions I'm really curious to see answered are:
Is MD5 not to be trusted? Under normal situations when you use the MD5 algorithm with no malicious intent and no third party has any malicious intent would you expect ANY collisions (meaning two arbitrary byte[] producing the same hash)
How much better is RIPEMD than SHA1? (if its any better) its 5 times slower to compute but the hash size is the same as SHA1.
What are the odds of getting non-malicious collisions when hashing file-names (or other short strings)? (Eg. 2 random file-names with same MD5 hash) (with MD5 / SHA1 / SHA2xx) In general what are the odds for non-malicious collisions?
This is the benchmark I used:
static void TimeAction(string description, int iterations, Action func) {
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++) {
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
static byte[] GetRandomBytes(int count) {
var bytes = new byte[count];
(new Random()).NextBytes(bytes);
return bytes;
}
static void Main(string[] args) {
var md5 = new MD5CryptoServiceProvider();
var sha1 = new SHA1CryptoServiceProvider();
var sha256 = new SHA256CryptoServiceProvider();
var sha384 = new SHA384CryptoServiceProvider();
var sha512 = new SHA512CryptoServiceProvider();
var ripemd160 = new RIPEMD160Managed();
var source = GetRandomBytes(1000 * 1024);
var algorithms = new Dictionary<string,HashAlgorithm>();
algorithms["md5"] = md5;
algorithms["sha1"] = sha1;
algorithms["sha256"] = sha256;
algorithms["sha384"] = sha384;
algorithms["sha512"] = sha512;
algorithms["ripemd160"] = ripemd160;
foreach (var pair in algorithms) {
Console.WriteLine("Hash Length for {0} is {1}",
pair.Key,
pair.Value.ComputeHash(source).Length);
}
foreach (var pair in algorithms) {
TimeAction(pair.Key + " calculation", 500, () =>
{
pair.Value.ComputeHash(source);
});
}
Console.ReadKey();
}
In cryptography, hash functions provide three separate functions.
Collision resistance: How hard is it for someone to find two messages (any two messages) that hash the same.
Preimage Resistance: Given a hash, how hard is it to find another message that hashes the same? Also known as a one way hash function.
Second preimage resistance: Given a message, find another message that hashes the same.
These properties are related but independent. For example, collision resistance implies second preimage resistance, but not the other way around. For any given application, you will have different requirements, needing one or more of these properties. A hash function for securing passwords on a server will usually only require preimage resistance, while message digests require all three.
It has been shown that MD5 is not collision resistant, however, that does not preclude its use in applications that do not require collision resistance. Indeed, MD5 is often still used in applications where the smaller key size and speed are beneficial. That said, due to its flaws, researchers recommend the use of other hash functions in new scenarios.
SHA1 has a flaw that allows collisions to be found in theoretically far less than the 2^80 steps a secure hash function of its length would require. The attack is continually being revised and currently can be done in ~2^63 steps - just barely within the current realm of computability (as of April, 2009). For this reason NIST is phasing out the use of SHA1, stating that the SHA2 family should be used after 2010.
SHA2 is a new family of hash functions created following SHA1. Currently there are no known attacks against SHA2 functions. SHA256, 384 and 512 are all part of the SHA2 family, just using different key lengths.
RIPEMD I can't comment too much on, except to note that it isn't as commonly used as the SHA families, and so has not been scrutinized as closely by cryptographic researchers. For that reason alone I would recommend the use of SHA functions over it. In the implementation you are using it seems quite slow as well, which makes it less useful.
In conclusion, there is no one best function - it all depends on what you need it for. Be mindful of the flaws with each and you will be best able to choose the right hash function for your scenario.
⚠️ WARNING
August, 2022
DO NOT USE SHA-1 OR MD5 FOR CRYPTOGRAPHIC APPLICATIONS. Both of these algorithms are broken (MD5 can be cracked in 30 seconds by a cell phone).
All hash functions are "broken"
The pigeonhole principle says that try as hard as you will you can not fit more than 2 pigeons in 2 holes (unless you cut the pigeons up). Similarly you can not fit 2^128 + 1 numbers in 2^128 slots. All hash functions result in a hash of finite size, this means that you can always find a collision if you search through "finite size" + 1 sequences. It's just not feasible to do so. Not for MD5 and not for Skein.
MD5/SHA1/Sha2xx have no chance collisions
All the hash functions have collisions, its a fact of life. Coming across these collisions by accident is the equivalent of winning the intergalactic lottery. That is to say, no one wins the intergalactic lottery, its just not the way the lottery works. You will not come across an accidental MD5/SHA1/SHA2XXX hash, EVER. Every word in every dictionary, in every language, hashes to a different value. Every path name, on every machine in the entire planet has a different MD5/SHA1/SHA2XXX hash. How do I know that, you may ask. Well, as I said before, no one wins the intergalactic lottery, ever.
But ... MD5 is broken
Sometimes the fact that its broken does not matter.
As it stands there are no known pre-image or second pre-image attacks on MD5.
So what is so broken about MD5, you may ask? It is possible for a third party to generate 2 messages, one of which is EVIL and another of which is GOOD that both hash to the same value. (Collision attack)
Nonetheless, the current RSA recommendation is not to use MD5 if you need pre-image resistance. People tend to err on the side of caution when it comes to security algorithms.
So what hash function should I use in .NET?
Use MD5 if you need the speed/size and don't care about birthday attacks or pre-image attacks.
Repeat this after me, there are no chance MD5 collisions, malicious collisions can be carefully engineered. Even though there are no known pre-image attacks to date on MD5 the line from the security experts is that MD5 should not be used where you need to defend against pre-image attacks. SAME goes for SHA1.
Keep in mind, not all algorithms need to defend against pre-image or collision attacks. Take the trivial case of a first pass search for duplicate files on your HD.
Use SHA2XX based function if you want a cryptographically secure hash function.
No one ever found any SHA512 collision. EVER. They have tried really hard. For that matter no one ever found any SHA256 or 384 collision ever. .
Don't use SHA1 or RIPEMD unless its for an interoperability scenario.
RIPMED has not received the same amount of scrutiny that SHAX and MD5 has received. Both SHA1 and RIPEMD are vulnerable to birthday attacks. They are both slower than MD5 on .NET and come in the awkward 20 byte size. Its pointless to use these functions, forget about them.
SHA1 collision attacks are down to 2^52, its not going to be too long until SHA1 collisions are out in the wild.
For up to date information about the various hash functions have a look at the hash function zoo.
But wait there is more
Having a fast hash function can be a curse. For example: a very common usage for hash functions is password storage. Essentially, you calculate hash of a password combined with a known random string (to impede rainbow attacks) and store that hash in the database.
The problem is, that if an attacker gets a dump of the database, he can, quite effectively guess passwords using brute-force. Every combination he tries only takes a fraction of millisecond, and he can try out hundreds of thousands of passwords a second.
To work around this issue, the bcrypt algorithm can be used, it is designed to be slow so the attacker will be heavily slowed down if attacking a system using bcrypt. Recently scrypt has made some headline and is considered by some to be more effective than bcrypt but I do not know of a .Net implementation.
Update:
Times have changed, we have a SHA3 winner. I would recommend using keccak (aka SHA3) winner of the SHA3 contest.
Original Answer:
In order of weakest to strongest I would say:
RIPEMD BROKEN, Should never be used as can be seen in this pdf
MD-5 BROKEN, Should never be used, can be broken in 2 minutes with a laptop
SHA-1 BROKEN, Should never be used, is broken in principal, attacks are getting better by the week
SHA-2 WEAK, Will probably be broken in the next few years. A few weaknesses have been found. Note that generally the higher key size, the harder the hash function is to break. While key size = strength is not always true, it is mostly true. So SHA-256 is probably weaker than SHA-512.
Skein NO KNOWN WEAKNESSES, is a candidate for SHA-3. It is fairly new and thus untested. It has been implemented in a bunch of languages.
MD6 NO KNOWN WEAKNESSES, is another a candidate for SHA-3. Probably stronger than Skien, but slower on single core machines. Like Skien it is untested. Some security minded developers are using it, in mission critical roles.
Personally I'd use MD6, because one can never been too paranoid. If speed is a real concern I'd look at Skein, or SHA-256.
In MD5's defense, there is no known way to produce a file with an arbitrary MD5 hash. The original author must plan in advance to have a working collision. Thus if the receiver trusts the sender, MD5 is fine. MD5 is broken if the signer is malicious, but it is not known to be vulnerable to man-in-the-middle attacks.
It would be a good ideea to take a look at the BLAKE2 algorythm.
As it is described, it is faster than MD5 and at least as secure as SHA-3. It is also implemented by several software applications, including WinRar.
Which one you use really depends on what you are using it for. If you just want to make sure that files don't get corrupted in transit and aren't that concerned about security, go for fast and small. If you need digital signatures for multi-billion dollar federal bailout agreements and need to make sure they aren't forged, go for hard to spoof and slow.
I would like to chime in (before md5 gets torn apart) that I do still use md5 extensively despite its overwhelming brokenness for a lot of crypto.
As long as you don't care to protect against collisions (you are still safe to use md5 in an hmac as well) and you do want the speed (sometimes you want a slower hash) then you can still use md5 confidently.
I am not an expert at this sort of thing, but I keep up with the security community and a lot of people there consider the md5 hash broken. I would say that which one to use depends on how sensitive the data is and the specific application. You might be able to get away with a slightly less secure hash as long as the key is good and strong.
Here are my suggestions for you:
You should probably forget MD5 if you anticipate attacks. There are many rainbow tables for them online, and corporations like the RIAA have been known to be able to produce sequences with equivalent hashes.
Use a salt if you can. Including the message length in the message can make it very difficult to make a useful hash collision.
As a general rule of thumb, more bits means less collisions (by pigeonhole principle) and slower, and maybe more secure (unless you are a math genius who can find vulnerabilities).
See here for a paper detailing an algorithm to create md5 collisions in 31 seconds with a desktop Intel P4 computer.
http://eprint.iacr.org/2006/105