12.07.2015, 10:12
Introduction
Hey there! This will be a small tutorial about how to create salted passwords which will be hashed with the new SHA-256 hashing function.
First of, what is hashing?
Hash algorithms are one way functions. They turn any amount of data into a fixed-length "fingerprint" that cannot be reversed. They also have the property that if the input changes by even a tiny bit, the resulting hash is completely different (see the example below). This is great for protecting passwords, because we want to store passwords in a form that protects them even if the password file itself is compromised, but at the same time, we need to be able to verify that a user's password is correct.
Example of a hash:
pawn Code:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
hash("waltz") = c0e81794384491161f1777c232bc6bd9ec38f616560b120fda8e90f383853542
Better way is to add a salt to a password. A salt is an array of characters which is added to the password before the hash so it gets harder for people to crack the password by using brute force or dictionary attacks.
If you ever wondered how those attacks look like, here's a small example:
Code:
Dictionary Attack Trying apple : failed Trying blueberry : failed Trying justinbeiber : failed ... Trying letmein : failed Trying s3cr3t : success!
Code:
Brute Force Attack Trying aaaa : failed Trying aaab : failed Trying aaac : failed ... Trying acdb : failed Trying acdc : success!
SHA-256
SHA-256 is a hash function that comes from SHA-2, set of hash functions designed by the NSA. It's a widely used in the Linux systems and some other security applications and protocols like TSL and SSL.
Let's write some code
In this tutorial, I'll show you how to make a code which will generate a random salt which will be added to our passwords later on. I'll show examples of storing the data in MySQL but you can use y_ini or some othes data saving system. It really doesn't matter.
So to start our code, I'm going to show you how to create a salt which will be inserted in our database along with password and other data.
pawn Code:
enum pInfo
{
pName[MAX_PLAYER_NAME],
pPassword[65] // SHA-256 creates a hash of 64 characters,
pSalt[11]
};
new PlayerInfo[MAX_PLAYERS][pInfo];
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
if(dialogid == REGISTER_USER)
{
new salt[11];
// generating random string of characters which is 10 character long
for(new i; i < 10; i++)
{
// storing random character in every slot of our salt array
salt[i] = random(79) + 47;
}
salt[10] = 0;
SHA256_PassHash(inputtext, salt, PlayerInfo[playerid][pPassword], 65);
// inputtext - text that we've entered in the dialog
// query to save our name, password and salt
new query[256];
mysql_format(mysql, query, sizeof(query), "INSERT INTO `users` (`Name`, `Password`, `Salt`) VALUES ('%e', '%e', '%e')", PlayerInfo[playerid][pName], PlayerInfo[playerid][pPassword], salt);
mysql_tquery(mysql, query, "", "");
}
return 1;
}
salt[i] = random(79) + 47; - we are getting a random value from the ASCII table from 33 to 126, our you could say, we are getting one by one random generated character. After the salt is generated, we are adding a null value to the end of it.
Our users can now register at our server but they can't login yet. Here's the code for it:
pawn Code:
public OnPlayerConnect(playerid)
{
// checking for user in the database
new query[128];
mysql_format(mysql, query, sizeof(query),"SELECT `Password`, `Salt` FROM `users` WHERE `Name` = '%e'", PlayerInfo[playerid][pName]);
mysql_tquery(mysql, query, "OnAccountCheck", "i", playerid);
return 1;
}
forward public OnAccountCheck(playerid);
public OnAccountCheck(playerid)
{
// if the users exists
if(cache_get_row_count(mysql))
{
// saving password and salt from the database
cache_get_field_content(0, "Password", PlayerInfo[playerid][pPassword], mysql, 65);
cache_get_field_content(0, "Salt", PlayerInfo[playerid][pSalt], mysql, 11);
// login dialog
ShowDialog(playerid, LOGIN_USER);
}
else
{
// user doesn't exist, show the register dialog
ShowDialog(playerid, REGISTER_USER);
}
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
// ...
else if(dialogid == LOGIN_USER)
{
new hash[65];
// hashing the text that user entered and salt that was loaded
SHA256_PassHash(inputtext, PlayerInfo[playerid][pSalt], hash, 64);
// if the hash is same as the loaded password
if(!strcmp(hash, PlayerInfo[playerid][pPassword]))
{
// load user
}
else
{
// wrong password, show the dialog again etc.
}
}
return 1;
}
This is how it looks like in my database:
Some of the wrong ways of salting
- Do not reuse salts (using same salt over multiple passwords)
Code:A common mistake is to use same salt for hashing your passwords. This is ineffective because if two users have the same password, they'll still have the same hash. A new random salt must be generated each time a user creates an account or changes their password. Oh, and don't use user's name for the salt since it's predictable and often reused for accounts on other services.
- Do not create short salts
Code:If the salt is only three ASCII characters, there are only 95x95x95 = 857,375 possible salts. To make it impossible for an attacker to create a lookup table for every possible salt, the salt must be long. A good rule of thumb is to use a salt that is the same size as the output of the hash function.
- Do not do double hashing
Code:It's easy to get carried away and try to combine different hash functions, hoping that the result will be more secure. In practice, though, there is very little benefit to doing it. All it does is create interoperability problems, and can sometimes even make the hashes less secure.
- Do not use wacky hash functions
Code:Never try to invent your own crypto, always use a standard that has been designed by experts.
Thanks to:
-CrackStation for making awesome article on secure salted password. You can find it here:
https://crackstation.net/hashing-sec...#normalhashing
- SA:MP team for adding SHA-256 hashing function alongside with many other useful stuf.