Question

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;
}
Était-ce utile?

La solution

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.

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
scroll top