I'm going to try a different approach to answering this. I'm not going to tell you something is bad, and not explain why. I'll explain exactly why it's bad, step-by-step, and show you how to break it, but I won't go too deeply into Rainbow Tables... it's assumed you know what that is.
Here's why your developer's hash is incorrect: because it just introduces a few factors that could be utterly brute-forced once the method is discovered, even if he were to randomize the shuffling.
How? Because if I have access to your server, I also know the method which your developer is using to hash your password because I've stolen that code too, and I can rearrange everything to suit my little crackpot application.
Let's say I hacked your company, and gained access to your database so that I can obtain these hashes. I know WHEN users register, correct? I know when they last changed their password because, unless you're a complete newbie, you should be logging that information to the database.
$time = date('mdYHis');
This timestamp is probably around the same time the the user registered his or her password, or changed it. We can know this because the last time it was updated should be stored in the database. The time you registered should be stored in the database. Part of the crypt has been defeated.
$rand = mt_rand().'\n';
Cool, a random number generator. You know, nothing is really random on computers. Random number generators aren't truly random. This is the Mersenne Twister
. All I need are 624
different combinations to figure out all future numbers. I've stolen your "salt" from the database as well, and I know how you're calculating it.
Because I know the dates on which your users registered, I know how to recreate the correct number for the Mersenne Twister routine at that specific time. I can write a little cracking method to extract the exact number that would likely happen at that time. Your salt is no longer random. But you know what? It's irrelevant. I know the exact format you're using for that salt, and I likely got it from your database anyway. Then I can use Rainbow Tables to utterly annihilate your salt in under a second because mt_rand()
alone produces a maximum of 10^10
hashes, and a minimum of 10^9
, which means 11 billion possibilities, and since all of them are numbers, and I know the format of your salt, they will be cracked in less than a second.
So now I know who this username belongs to because I jacked your database. I know when they registered, I know when they last changed their password, and I know your random number. I see you, Dave, a thief on the roof. My new satellite link has both infrared and the x-ray spectrum. I see your heart beating. I see you are afraid.
Now that $crypt
has been defeated, let's take a look at function hash_it()
.
function hash_it($string1, $string2) {
$pass = md5($string1);
$nt = substr($pass,0,8);
$th = substr($pass,8,8);
$ur = substr($pass,16,8);
$ps = substr($pass,24,8);
$hash = 'H'.sha1($string2.$ps.$ur.$nt.$th);
return $hash
}
Now let's take a look at some sample input: hash_it(Dave, testpassword1);
Results:
$pass = "b7e055c6165da55c3e12c49ae5207455"
$nt = "b7e055c6";
$th = null;
$ur = "3e12c49a";
$ps = "e5207455";
$hash Input
: "H" + "username + "RegistrationDate" + "1604716014" + "e5207455" + "3e12c49a" + "b7e055c6"(tldr: "HDaveRegistrationDate1604716014e52074553e12c49ab7e055c6"
)
$hash = 'H'.sha1("DaveRegistrationDate1604716014e52074553e12c49ab7e055c6);
`$hash output:
"6b347a1521b6b84501806268614abe1e7324c703"; (same thing every time)
Here's how an attack might work:
- Break Mersenne Twister (
mt_rand()
) after 624 observations, or just Rainbow Table the salt.
- Grab Dave's
REGISTRATION_DATE
from the database, or the USER_LAST_MODIFIED_DATE
- Grab Dave's SHA1 hash
- Initiate brute force attack (it becomes a static sha1 hash after we've broken your "security") with the following parameters:
"Username"
+ "RegistrationDate"
+ YourRandomNumber
+ DictionaryAttack[]
- Harm your customers.
And that's the story of why you shouldn't roll your own cryptography unless you really know what you're doing. Imagine if I were an actual cracker, and not someone who just went backwards through your code.