[Tutorial] Using new SHA-256 function
#1

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
Good way is to use a hash functions that can't be decrypted. But that's a naive way of storing passwords.
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!
Sorry if this is too long, but I think everyone who is dealing with passwords should know these things.
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;
}
This code will give us random generated salt which will be saved into the database as a plain-text, next to the password field.

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;
}
That's it! You should now have a more secure password saving system.
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.
Thank you for reading this tutorial. If you have some advices for better password managing, feel free to write them here.

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.
Reply
#2

Very nice!
Reply
#3

good job.
Reply
#4

Thank you guys.
Reply
#5

Its Ironic really; I was talking to someone when the update came out how SHA-256 can still be cracked, and anyone's best bet is to 'SALT' it, so Dominik, you sir have got yourself some rep just for doing this. GJ.
Reply
#6

Quote:
Originally Posted by zT KiNgKoNg
View Post
Its Ironic really; I was talking to someone when the update came out how SHA-256 can still be cracked, and anyone's best bet is to 'SALT' it, so Dominik, you sir have got yourself some rep just for doing this. GJ.
Thank you very much.
I think it's a good thing that we got a new function so we don't have to use other plugins just for password security. I'm also glad to see that salting is supported by the function so we don't have to go and concatenate strings and do other stuff.
Reply
#7

It's good to see someone post a decent hashing tutorial with salting method. I suggest you to also note about updating salts at a particular time. In case if MySQL is used, event scheduler method can be handy!
Reply
#8

Thanks for sharing that tutorial. It's nice to see some new cool stuff.
I haven't seen any tips on updating the salt over time but it might be useful.
Reply
#9

Wish you could explain it in Yini, but good job.
Reply
#10

Quote:
Originally Posted by Youssef221
View Post
Wish you could explain it in Yini, but good job.
Pretty much the same to be honest, just INI functions.
Reply
#11

Nice tutorial

Quote:
Originally Posted by dominik523
View Post
random(79) + 47; - we are getting a random value from the ASCII table from 33 to 126
Wouldn't the result be 47 - 125?
Reply
#12

a bit like Whirlpool complicated but is very good and also useful
Reply
#13

Quote:
Originally Posted by yugecin
View Post
Nice tutorial



Wouldn't the result be 47 - 125?
Random(79) will give anything from 0 to 79, and we don't want our characters to start from 0 which is null in ASCII. Because of that, we are adding 47 to it so we'll get anything from / to ~.

Thank you all for your kind replies.
EDIT: @Youssef221 - You can do the same thing. Just like saving password in INI, save the salt and load it when the user joins the server. If you really want it, I could add a small part to the tutorial which will be in y_ini.
Reply
#14

Quote:
Originally Posted by dominik523
View Post
Random(79) will give anything from 0 to 79, and we don't want our characters to start from 0 which is null in ASCII. Because of that, we are adding 47 to it so we'll get anything from / to ~.
It will give a value from [0,max), meaning that the highest value you will ever get is max-1, or in the case of random(79) it's 78.

Otherwise it's a decent tutorial, anyone dealing with passwords should be aware of hashing.
Reply
#15

Quote:
Originally Posted by Hiddos
View Post
It will give a value from [0,max), meaning that the highest value you will ever get is max-1, or in the case of random(79) it's 78.

Otherwise it's a decent tutorial, anyone dealing with passwords should be aware of hashing.
Yeah, that's what I meant but I have no idea why did I write 79. Oh well.
I totally agree. Hashing isn't that hard and it should be always done. Thanks!
Reply
#16

Nevermind, it was a mistake in some code.
Reply
#17

there is a problem, I can't log in my account, it always say invalid pass

EDIT: codes: http://pastebin.com/teJcJnHB
Reply
#18

Can you please check if you are saving correct salt and password (print it out when user registers) and then check if you are loading the correct values.
EDIT: There is now 0.3.7 R2-1 version of SA:MP which fixes SHA256 function. Be sure to update your server files.
Reply
#19

This is good way to hash passwords .. thanks for tutorial broo
Reply
#20

Why do we must hash a password ? there is any chance someone trying to hack player account??

Edit:

Is it possible to attack password inside .ini .json files?
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)