-1

I'm going to preface this by saying I have absolutely no clue when it comes to cryptography, but I'm posting this question because I'm very interested and I have no doubt there are some smart people on here who will be able to explain this to me like I'm 5.

So to my understanding md5 is considered insecure because of how quickly things can be hashed, which means brute force attacks are very easy and attackers could even compare a hashed md5 password against a pre-generated table.

Which is why when (using php) I compute md5("password"); and it gives me 5f4dcc3b5aa765d61d8327deb882cf99I can plug that value in to a site like this and in 45ms it spits back 5f4dcc3b5aa765d61d8327deb882cf99 MD5 : password

But what if I add some "helper" data to the beginning and end of my password?

<?php
    $helper = "Qw3r7y1uioP[4]AsdfGh5jkl3'z7xcvb9nm,.?";
    echo md5($helper."password".$helper);
?>

It returns 9f1f60fc8d76caa77b11810a0d68e0c5 (which the same site can't decrypt, though I'm not sure if rainbow tables could, seems unlikely though right?) which I could then store, along with the "helper" to compare to future password sent by post:

<?php
    $helper = "Qw3r7y1uioP[4]AsdfGh5jkl3'z7xcvb9nm,.?";
    $accepted = "9f1f60fc8d76caa77b11810a0d68e0c5";

    $pass = $_POST["password"];

    if (md5($helper.$pass.$helper)==$accepted) {
        echo "Password was correct.";
    } else {
        echo "Password was incorrect.";
    }
?>

What is wrong with this approach? I'm sure there is some reason that it isn't a good idea, I just don't have enough understanding of how md5 and cryptography in general works to pinpoint why.

  • It cant decode it because it takes more time and probably just failed so it doesn't waste power on the websites server. but yea even if you add the "helper" also called a salt md5 is not secure because brute forcing takes a lot less time as you said. – user36976 Jun 8 '14 at 18:20
  • 1
    This method (hashing passwords together with a constant string) is commonly referred to as a "Pepper". – Philipp Jun 8 '14 at 18:30
  • Salts and peppers do not change the computational complexity of a hash-based system significantly. They are designed to prevent against precomputation attacks such as Rainbow Tables. – Polynomial Jun 9 '14 at 13:07
  • 1
    Your basic assumption is wrong. MD5 is not insecure because of its speed, it's insecure because it is broken (for certain important scenarios, mostly with regards to hashing of messages for signing / message verification). Speed is actually a good property for a hash function to have, as long as attacking the hash is sufficiently complex. – Maarten Bodewes Jun 22 '14 at 17:03
3

The helper string doesn't help.

If it's public, then it's just a constant prefix the attacker has to add to every password. You've basically created a slight modification of MD5 with the exact same issues as the actual MD5. This does nothing to stop brute-force attacks and might even introduce subtle weaknesses.

Yes, an attacker wouldn't be able to use a standard MD5 lookup table. But given the computing power of current hardware, there's no need for lookup tables in the first place: Even an old gamer GPU like the HD 6990 can calculate 10 billion hashes per second. And specialized hardware like an ASIC has much better performance. I couldn't find concrete figures for MD5, but you can currently get 200 billion SHA-256 hashes per second with hardware for only $ 500.

If the helper string is secret, then the entire password security depends on this one secret. As soon as the string is known, the attacker can again try billions of possible passwords per second.

Yes, this is somewhat better than plain MD5, but it introduces an unnecessary single point of failure. The whole reason why we hash passwords instead of encrypting them is because we don't want any shortcuts for an attacker. Even if the attacker knows everything about your system, the hashes should still be as secure as they were before. This is obviously not the case in your scheme.

So either way, this is no real improvement.

However, the idea of adding random strings to the password does lead to a valid concept: Specialized password hash algorithms like bcrypt have an extra parameter for a so-called “salt”. A salt is a unique random string which is generated per password and mixed into the hashing procedure. This forces an attacker to break each hash individually, because each hash was basically calculated with a unique variation of the main algorithm.

Salting alone isn't enough, though. The most important requirement for a password hash algorithm is that it must be computationally expensive. Calculating a hash should use a lot of resources. Instead of billions of hashes per second on stock hardware, we only want a few hashes per second. This makes little difference for legitimate users, but it's an enormous problem if you're trying a brute-force attack.

0

There's a lot wrong with your approach.

  1. PVD in Source. If there is a problem with your source code or an error message appears, your source code could reveal the value of $accepted. This would allow an attacker to use the hash they discovered to attack it offline. They could use an extremely powerful computer and blaze through billions of password possibilities with 0 latency.
  2. md5. There have been collisions found for md5. This means it lacks the characteristics of a cryptographic hash function.
  3. No Throttling. You're right about the speed. I could write a script that constantly posts your server and your code does nothing to slow them down. No timeout, etc.
  4. Your code protects nothing. I know you code is just an example, but for future readers this PHP code you do NOT want to copy and paste. After the if else branch, both authenticated users and unauthenticated users go back to the same path of execution. It will almost certainly be better to do this

    <?php
    $helper = "Qw3r7y1uioP[4]AsdfGh5jkl3'z7xcvb9nm,.?";
    $accepted = "9f1f60fc8d76caa77b11810a0d68e0c5";
    
    $pass = $_POST["password"];
    
    if (md5($helper.$pass.$helper)==$accepted) {
        echo "Password was correct.";
    } else {
        echo "Password was incorrect.";
        exit(0);
    }
    ?>
    

What you want to do is use a stronger function that is also slower. In php it is very easy to use the crypt() function, which implements bcrypt (which is quite good but there are other KDFs that work too like scrypt). Here is an example I took straight from the php docs. This is also bad code, but it does illustrate how to user the user input to verify a password.

<?php
    $hashed_password = crypt('mypassword');

    /* You should pass the entire results of crypt() as the salt for comparing a
    password, to avoid problems when different hashing algorithms are used. (As
    it says above, standard DES-based password hashing uses a 2-character salt,
    but MD5-based hashing uses 12.) */
    if (crypt($user_input, $hashed_password) == $hashed_password) {
        echo "Password verified!";
    }
?>

It is good to note that functions like SHA, md5, and other well known hashing algorithms were designed to be fast. Fast functions are what attackers like to see!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.