webdevRefinery Forum: Building an Automatic Salt Generator - webdevRefinery Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

User is offline ShanePerreault 

  • Sleep Burns My Eyes
  • Group: Members
  • Posts: 1075
  • Joined: 19-March 10
  • LocationChicago, USA
  • Expertise:PHP,Java,Javascript,Ruby on Rails,SQL

Posted 03 February 2011 - 08:36 AM (#1)

Building an Automatic Salt Generator


Automatic Salt Generator

A Tutorial by ShanePerreault

Importance of Salting
To start things off, if you don't know what salting is, allow me to explain it to you. ;) Salting is essentially adding a random encrypted string to another encrypted string, which is usually a password, then encrypting that to change the whole string. That's sounds weird, I know. Think of it this way. You just entered a password for registration on a website, now, that website takes your password and stores it into the database without encrypting it. Would you feel safe using that website? No, of course not. That's why they may use a MD5 or SHA1 encryption on that string. Well, if someone were to get access to that database, your password could still be unsafe. Why? Because of Rainbow Tables. A Rainbow Table is a database table that is really f*cking big! It usually has every word in the dictionary (yeah, really big :blink: ) and next to it is its either MD5 or SHA1 encryption. Now, somebody could take your password that has been encrypted once, find a match in their Rainbow Table and match it up. Now, they have access to your online account. Or worse, if you use that password for other things like your online bank, now that is compromised too. And the scary thing is, Rainbow Tables are waaay easy to find. Literally, just google an MD5 Rainbow Table and there are a bunch that are free to download. :unsure: This is why we salt a password. A salt string is essentially just a weird string of characters. For example: a%I:_ Yeah, that's what a salt string could look like. And here's what one would do with a salt string.

$salt = "a%I:_";
$encrypted_password = md5(md5($salt) . md5($_POST['password']));


Now that password is safe from any Rainbow tables damage. Why? Because Rainbow Tables would have to get enormously gargantuan, even impossibly big, to be able to have a md5 string like the one above. Salting your encryptions is probably the easiest but most beneficial way to easily secure your website. So, now that we have a need for a salt, how do we get one.

Well, another leak i that if you're using the same salt string for every encryption, if someone looked at your code, they could most likely reverse engineer it to find the original password hash string. Which we don't want. So, we need to add one more column to our users table in our database called "salt", because every user's salt is going to be different. Here's what I use to generate random salts. It's randomized and shuffled around. And it gets the best salt strings anywhere. ;)

public function generate_salt(){
		$numbers = array("0","1","2","3","4","5","6","7","8","9");
		$lcchars = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
		$ucchars = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
		$symbols = array('!','@','#','$','%','^','&','*','(',')','-','~','+','=','|','/','{','}',':',';',',','.','?','<','>','[');
		$fake_salt = $numbers[array_rand($numbers)] . $lcchars[array_rand($lcchars)] . $ucchars[array_rand($ucchars)] . $symbols[array_rand($symbols)] . $symbols[array_rand($symbols)];
		$salt = str_shuffle($fake_salt);
		return $salt;
	}


The keyword public is in there because this method is from my Users class for registration and logging in. I hope that this is beneficial to you and your users. Keep your applications secure, because there ARE people who are going to try to break your software and hurt your users. I guarantee it. Salt away.

-Happy Coding

Languages: PHP | JS | Ruby | Rails | C# | Python | Java
0


User is offline Koen 

  • Leroy Jenkins
  • Group: Members
  • Posts: 2503
  • Joined: 10-March 10
  • Locationthe Netherlands
  • Expertise:HTML,CSS,Javascript,Graphics

Posted 03 February 2011 - 08:44 AM (#2)

This is bad. Your salt has a predefined structure which could bring down the number of possible salts by a lot, thus making it easier to find in a rainbow table. I'd do it like this:
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$charnum = 61;
$salt = $chars[rand(0, $charnum)] . $chars[rand(0, $charnum)] . $chars[rand(0, $charnum)] . $chars[rand(0, $charnum)];

Please click the + if I helped you!
Twitter: @KoenKlaren

<callumacrae> YOU DID A ROMNEY
0


User is offline ShanePerreault 

  • Sleep Burns My Eyes
  • Group: Members
  • Posts: 1075
  • Joined: 19-March 10
  • LocationChicago, USA
  • Expertise:PHP,Java,Javascript,Ruby on Rails,SQL

Posted 03 February 2011 - 08:52 AM (#3)

There are 351,520 possibilites without string shuffling. Then, when I add in string shuffling, I want to say the possibilities are 1,757,600. I don't think it's going to run out very quickly. ;)

And an even bigger solution would to add more Symbols to the symbols array, add more characters to the string itself instead of 5, and shuffle it.

AND, the structure is not predefined, it's structured to be able to add parts to the string, but then it's shuffled up randomizing the order.

Languages: PHP | JS | Ruby | Rails | C# | Python | Java
0


User is offline TheEmpty 

  • I say words in sequences.
  • Group: Members
  • Posts: 5154
  • Joined: 02-October 10
  • Expertise:HTML,CSS,PHP,Java,Javascript,Python,Ruby on Rails,SQL

Posted 03 February 2011 - 09:19 AM (#4)

It's bad practice. It makes your site eaiser to hack, because it will only only have one of each set. Also you're assuming you're building a crappy site (and the people that read this). That's bad too, assume you're going to have a gazzilion users.

موهد -
Reserved.
0


User is offline Koen 

  • Leroy Jenkins
  • Group: Members
  • Posts: 2503
  • Joined: 10-March 10
  • Locationthe Netherlands
  • Expertise:HTML,CSS,Javascript,Graphics

Posted 03 February 2011 - 09:22 AM (#5)

View PostShanePerreault, on 03 February 2011 - 08:52 AM, said:

There are 351,520 possibilites without string shuffling. Then, when I add in string shuffling, I want to say the possibilities are 1,757,600. I don't think it's going to run out very quickly. ;)

And an even bigger solution would to add more Symbols to the symbols array, add more characters to the string itself instead of 5, and shuffle it.

AND, the structure is not predefined, it's structured to be able to add parts to the string, but then it's shuffled up randomizing the order.

My solution is faster too.
Please click the + if I helped you!
Twitter: @KoenKlaren

<callumacrae> YOU DID A ROMNEY
0


User is offline ShanePerreault 

  • Sleep Burns My Eyes
  • Group: Members
  • Posts: 1075
  • Joined: 19-March 10
  • LocationChicago, USA
  • Expertise:PHP,Java,Javascript,Ruby on Rails,SQL

Posted 03 February 2011 - 10:08 AM (#6)

View PostPWNbear, on 03 February 2011 - 09:22 AM, said:

My solution is faster too.


Yeah, but it's not better. You've limited yourself to letters and numbers, I added symbols to really make it strange.

@TheEmpty, Like I said, you can just expand the size and variation of the string with more users. The main point of this tutorial also is to just give you the idea of this concept.

Languages: PHP | JS | Ruby | Rails | C# | Python | Java
0


User is offline NoizeMe 

  • Group: Members
  • Posts: 591
  • Joined: 06-May 10
  • LocationGermany
  • Expertise:HTML,CSS,PHP,Java,Javascript,Python,Node.js,SQL,MongoDB,CouchDB,Cassandra

Posted 03 February 2011 - 10:12 AM (#7)

You miss another detail.
Using a salt like this
md5(md5($salt) . md5($password));
is actually not best practice.
This constellation is more vulnerable to cryptographic analysis.
If you want to be on a save site use
md5(md5($password) . md5($salt));


Also a few words on generating salts.
Since doing it your way requires the salt to be hashed later with md5.
Use this with caution.
While an md5 hash only includes 128 bits (32 characters or 16 hexadecimal numbers), it is possible to easily generate longer and more secure salts, just saying.
Posted Image
0


User is offline Koen 

  • Leroy Jenkins
  • Group: Members
  • Posts: 2503
  • Joined: 10-March 10
  • Locationthe Netherlands
  • Expertise:HTML,CSS,Javascript,Graphics

Posted 03 February 2011 - 10:37 AM (#8)

View PostShanePerreault, on 03 February 2011 - 10:08 AM, said:

Yeah, but it's not better. You've limited yourself to letters and numbers, I added symbols to really make it strange.

You can just add those characters if you want :lol:

4 arrays instead of 1 string and 1 integer is a lot slower, like a LOT.
Please click the + if I helped you!
Twitter: @KoenKlaren

<callumacrae> YOU DID A ROMNEY
0


User is offline ShanePerreault 

  • Sleep Burns My Eyes
  • Group: Members
  • Posts: 1075
  • Joined: 19-March 10
  • LocationChicago, USA
  • Expertise:PHP,Java,Javascript,Ruby on Rails,SQL

Posted 03 February 2011 - 11:03 AM (#9)

View PostPWNbear, on 03 February 2011 - 10:37 AM, said:

You can just add those characters if you want :lol:

4 arrays instead of 1 string and 1 integer is a lot slower, like a LOT.


How much slower, because page registrations for me happen in an instant on my local MAMP server?

Languages: PHP | JS | Ruby | Rails | C# | Python | Java
0


User is offline Koen 

  • Leroy Jenkins
  • Group: Members
  • Posts: 2503
  • Joined: 10-March 10
  • Locationthe Netherlands
  • Expertise:HTML,CSS,Javascript,Graphics

Posted 03 February 2011 - 11:16 AM (#10)

This is the difference:
Shane's time: 0.000,027,35 seconds
PWNbear's time: 0.000,004,09 seconds

Tested with this code:
<?php
function ShanePerrault(){
    $numbers = array("0","1","2","3","4","5","6","7","8","9");
    $lcchars = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
    $ucchars = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
    $symbols = array('!','@','#','$','%','^','&','*','(',')','-','~','+','=','|','/','{','}',':',';',',','.','?','<','>','[');
    $fake_salt = $numbers[array_rand($numbers)] . $lcchars[array_rand($lcchars)] . $ucchars[array_rand($ucchars)] . $symbols[array_rand($symbols)] . $symbols[array_rand($symbols)];
    return str_shuffle($fake_salt);
}

function PWNbear(){
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $charnum = 61;
    return ($chars[rand(0, $charnum)] . $chars[rand(0, $charnum)] . $chars[rand(0, $charnum)] . $chars[rand(0, $charnum)]);
}

$shane = $pwnbear = 0;

for ($i = 0; $i <= 1000; $i++){
    $start = microtime(true);
    ShanePerrault();
    $end = microtime(true);
    $shane += ($end - $start);
    
    $start = microtime(true);
    PWNbear();
    $end = microtime(true);
    $pwnbear += ($end - $start);
}

echo 'Shane\'s time: <strong>', number_format($shane / 1000, 8) . '</strong> seconds<br />';
echo 'PWNbear\'s time: <strong>', number_format($pwnbear / 1000, 8) . '</strong> seconds';
?>

Please click the + if I helped you!
Twitter: @KoenKlaren

<callumacrae> YOU DID A ROMNEY
0


User is offline Sephern 

  • Group: Moderators
  • Posts: 967
  • Joined: 04-June 10
  • LocationReading, UK
  • Expertise:HTML,CSS,PHP,Javascript,Python

Posted 03 February 2011 - 11:44 AM (#11)

View PostShanePerreault, on 03 February 2011 - 08:36 AM, said:

Well, if someone were to get access to that database, your password could still be unsafe. Why? Because of Rainbow Tables. A Rainbow Table is a database table that is really f*cking big! It usually has every word in the dictionary (yeah, really big :blink: ) and next to it is its either MD5 or SHA1 encryption. Now, somebody could take your password that has been encrypted once, find a match in their Rainbow Table and match it up.

That's not what a rainbow table is. What you've just described is a brute-force attack, whereby all the possible combinations are combined until the correct one is found. A refinement of that is the dictionary attack, where only common words and passwords are attempted. A rainbow table is an algorithm which uses chains hashes together to (more intelligently) attempt to match plaintext to a hash. They're not the same thing - Rainbow tables are far, far more feasible (and quite a bit more complex too).

View PostShanePerreault, on 03 February 2011 - 08:36 AM, said:

Now that password is safe from any Rainbow tables damage. Why? Because Rainbow Tables would have to get enormously gargantuan, even impossibly big, to be able to have a md5 string like the one above. Salting your encryptions is probably the easiest but most beneficial way to easily secure your website. So, now that we have a need for a salt, how do we get one.

Not quite. By doing this you merely thwart brute-force attacks of the dictionary classification. By using the same salt for each user, you allow the attacker to generate a rainbow lookup table for your particular salting scheme. They could also generate a brute-force dictionary for your particular salt too (by just prefixing it to common passwords and then hashing them).

View PostShanePerreault, on 03 February 2011 - 08:36 AM, said:

Well, another leak i that if you're using the same salt string for every encryption, if someone looked at your code, they could most likely reverse engineer it to find the original password hash string. Which we don't want. So, we need to add one more column to our users table in our database called "salt", because every user's salt is going to be different. Here's what I use to generate random salts. It's randomized and shuffled around. And it gets the best salt strings anywhere. ;)

This is what stops brute-forcing and rainbow attacks. The reason for this is that when each users password is encrypted with a unique salt, they will have completely different hash values. If me and you both have the password "Password" for example, the hashes will be completely different. This means that one brute-force dictionary or rainbow table will not find the password for all users. In fact, it won't even find it for a small proportion of users. It'll be able to find the correct plaintext for the users with the same salt (often 1). By adding a 12 bit salt for each user you would need an additional 4096 rainbow tables (because obviously there's only a set amount of 12 bit combinations). Most modern Operating Systems use 48 or 128 bits, both of which make it cryptographically infeasible to crack at this moment in time.


View PostNoizeMe, on 03 February 2011 - 10:12 AM, said:

You miss another detail.
Using a salt like this
md5(md5($salt) . md5($password));
is actually not best practice.
This constellation is more vulnerable to cryptographic analysis.
If you want to be on a save site use
md5(md5($password) . md5($salt));


Also a few words on generating salts.
Since doing it your way requires the salt to be hashed later with md5.
Use this with caution.

Really good call ;)
Probably not going to make a difference to anyone on this forum, but definitely worth a mention.


Kyek wrote a very good post a while back on the specifics of making a secure md5, where he went into the actual bit-level operations carried out and what's optimal. Worth a read if you're interested in this kind of thing.

[link]
0


User is offline derTechniker 

  • BadBoy™
  • Group: Members
  • Posts: 1210
  • Joined: 06-July 10
  • LocationAustria
  • Expertise:HTML,CSS,PHP,Javascript,SQL

Posted 03 February 2011 - 01:12 PM (#12)

If you search the user login system of Kyek you'll find a post from him how to make a salt. And thats a good way to make it - at least better than yours.
0


User is offline DarkCoder 

  • Group: Members
  • Posts: 1463
  • Joined: 08-March 10
  • LocationEngland, United Kingdom
  • Expertise:HTML,CSS,PHP,Javascript,SQL

Posted 03 February 2011 - 03:35 PM (#13)

http://twaddlr.com/view/40
0


User is offline Koen 

  • Leroy Jenkins
  • Group: Members
  • Posts: 2503
  • Joined: 10-March 10
  • Locationthe Netherlands
  • Expertise:HTML,CSS,Javascript,Graphics

Posted 03 February 2011 - 03:41 PM (#14)

View PostDarkCoder, on 03 February 2011 - 03:35 PM, said:

Using a for loop is still slower, I think it's best to just hardcode that number.

I'm starting to be some kind of speed-nazi like Kyek :P
Please click the + if I helped you!
Twitter: @KoenKlaren

<callumacrae> YOU DID A ROMNEY
0


User is offline soulcyon 

  • 兄貴 シャンク
  • Group: Members
  • Posts: 1591
  • Joined: 14-April 10
  • LocationNew Brunswick, NJ
  • Expertise:HTML,CSS,PHP,Java,Javascript,Node.js,Graphics,MongoDB,CouchDB

Posted 03 February 2011 - 07:11 PM (#15)

http://twaddlr.com/view/41

even cooler version :D
Posted Image
0


User is offline TheEmpty 

  • I say words in sequences.
  • Group: Members
  • Posts: 5154
  • Joined: 02-October 10
  • Expertise:HTML,CSS,PHP,Java,Javascript,Python,Ruby on Rails,SQL

Posted 03 February 2011 - 08:16 PM (#16)

Twaddlr looks nice.

Btw mo3: http://twaddlr.com/view/56 - if @title isn't set the title will be "Nil" not what you want. Try a short hand like: <%= @title.blank? ? 'Untitled' : @title %>
Reserved.
0


Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

2 User(s) are reading this topic
0 members, 2 guests, 0 anonymous users


Enter your sign in name and password


Sign in options
  Or sign in with these services