1

I'm trying to develop a small solution with the possibility of user authentication. Because this will be later hand over to other developers, i want the first iteration of the solution secure as possible for user data.

After reading some stuff about security and hashing, i'm decided to store hash + salt in a single field in the database. Most of the time salt's in the examples are 16 byte's long. But technical they could have had any size.

That leads to my question:

  • If it isn't public how long my salt and my hash are and i set them to a 'random' value, is this an extra step for protecting user data?

If somehow the database gets in wrong hands, the attacker wouldn't know at which point the salt ends and the hash starts.


Given example in .net Core 2.0 which allows me to set the length of salt and hash:

static Dictionary<string,string> _memDict = new Dictionary<string,string>() {{"username","password"}};

static int _amountOfHashBytes = 32;
static int _amountOfSaltBytes = 16;
static int _amountOfIterations = 10000;

static void Main(string[] args) 
{
    string passphrase = "passphrase"; 
    string usrName = "dotnetcoreuser";

    // 1) Create the salt value with a cryptographic 
    byte[] salt; 
    RandomNumberGenerator.Create().GetBytes(salt = new byte[_amountOfSaltBytes]); 
    Console.WriteLine("Salt: " + Convert.ToBase64String(salt)); 

    // 2) Create the Rfc2898DeriveBytes and get the hash value
    var pbkdf2 = new Rfc2898DeriveBytes(passphrase, salt, _amountOfIterations); 
    byte[] hash = pbkdf2.GetBytes(_amountOfHashBytes); 
    Console.WriteLine("Hash: " + Convert.ToBase64String(hash)); 

    // 3) Combine the salt and password bytes for later use
    byte[] hashBytes = new byte[_amountOfSaltBytes + _amountOfHashBytes]; 
    Array.Copy(salt, 0, hashBytes, 0, _amountOfSaltBytes); 
    Array.Copy(hash, 0, hashBytes, _amountOfSaltBytes, _amountOfHashBytes); 

    // 4) Turn the combined salt + hash into a string for storage
    string savedPasswordHash = Convert.ToBase64String(hashBytes); 
    Console.WriteLine("Combine: " + savedPasswordHash); 
    _memDict.Add(usrName, savedPasswordHash);

    // 5) Verify the user-entered password against a stored password.
    string tryInput = "1234";
    Console.WriteLine("Try: {0} Result: {1}", tryInput, IsValidPassword(tryInput, usrName));
    tryInput = "password";
    Console.WriteLine("Try: {0} Result: {1}", tryInput, IsValidPassword(tryInput, usrName));
    tryInput = "passphrase";
    Console.WriteLine("Try: {0} Result: {1}", tryInput, IsValidPassword(tryInput, usrName));
}

static bool IsValidPassword(string userInput, string userName)
{
    string savedPasswordHash = _memDict[userName];
    byte[] hashBytes = Convert.FromBase64String(savedPasswordHash);
    byte[] salt = new byte[_amountOfSaltBytes];
    Array.Copy(hashBytes, 0, salt, 0, _amountOfSaltBytes);
    var pbkdf2 = new Rfc2898DeriveBytes(userInput, salt, _amountOfIterations);
    byte[] hash = pbkdf2.GetBytes(_amountOfHashBytes);
    for (int i=0; i < _amountOfHashBytes; i++)
    {
        if (hashBytes[i+_amountOfSaltBytes] != hash[i]) { return false; }
    }
    return true;
}
  • The whole point of a salt is being unique. That's it. – CodesInChaos Oct 10 '17 at 19:54
  • I just want to note that you should reduce HashBytes to a maximum of 20. That speeds up by your code by a factor 2 without hurting security, so you could in exchange double the number of iterations, to improve security. – CodesInChaos Oct 10 '17 at 20:03
8

If it isn't public how long my salt and my hash are and i set them to a 'random' value, is this an extra step for protecting user data?

If somehow the database gets in wrong hands, the attacker wouldn't know at which point the salt ends and the hash starts.

No. It is a completely pointless attempt at security through obscurity.

The only important thing is that your salt (and of course the hash) are long enough, 16 bytes are sufficient, 8 would be too little.

  • 4
    @Smartis Addendum: The principle behind this is known as Kerckhoff's principle en.wikipedia.org/wiki/Kerckhoffs%27s_principle – Thomas Junk Oct 10 '17 at 11:05
  • 2
    Or, put in layman’s terms, assume that if the hacker a gotten your database they’ve also managed to get your source code (either the actual source or the binaries that they can decompile.) – Paul Oct 10 '17 at 12:14
1

The value of using a salt is that with the salt, no two users have the same password. The same effort that an attacker would use to attack the complete unsalted password database is now needed to attack one single password.

You should assume that an attacker will find out what salt you are using. That's ok. As long as no users or very few users have the same salt.

The 8 byte recommendation means that with a 1 billion use database there is just a one in 39 chance that there are two users with the same salt. And even then it is harmless.

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.