3

If a salt is not stored along with the hashed password in the database, is it possible that the password is salted?

I ask because in a system I am working on there is only a password column, but when I review the code it appears that whoever wrote this is attempting to salt the password.

From what I understood passwords/salts are supposed to be stored like below:

email         | password (hashed)        | salt (not hashed)
[email protected] | de898928393a893sfe7f98s7 | S#ne3

So when a user registered with their password ("froggy" in the example below) it would go something like this:

//Generate salt (S#ne3 for this example)
//encrypt ("froggy" + "S#ne3")
//Save encrypted pw + salt to database AND save unencrypted salt to database

Then when the user attempted to login with "froggy" it would go something like this:

//Query database for user's record.  Store this in curUser object
//Check to see if the following match: encrypt("froggy" + curUser.salt) == curUser.password

Does this sound right? If I am right, is it safe to assume that passwords on this system are not salted?

3
  • 3
    Fyi, there are some rather common formats to store salted password hashes - usually they don't even need multiple database fields. Usually it's something like hash-type$salt$hash (look e.g. at the hash bcrypt gives you) Aug 16, 2013 at 23:26
  • @ThiefMaster, gah that is totally it! It is all just stored in one field. If you want to post that as an answer I will accept. Thanks! Aug 16, 2013 at 23:30
  • There we go Aug 17, 2013 at 11:09

3 Answers 3

3

First of all, the passwords are stored safely (assuming the used hashing algorithm is safe) since the only plaintext thing is the salt which has to be plaintext - its only purpose is to prevent the final hash to be hash(password) since that would allow the usage of precomputed rainbow tables mapping hashes to passwords.

However, the way of storing them using two separate columns is not optimal. While somewhat easy to use when just passing salt and plaintext password to a hash function, most password hashing libraries use a better scheme. Let's have a look a bcrypt (or rather its python bindings for the sake of simplicity) which uses the same scheme as crypt(3) does.

>>> import bcrypt
>>> bcrypt.gensalt()
'$2a$12$xYkBJKIdbmAZlhpl96dopO'
>>> bcrypt.hashpw('foo', '$2a$12$xYkBJKIdbmAZlhpl96dopO')
'$2a$12$xYkBJKIdbmAZlhpl96dopOJug5oZcp4tVWJPug/xMdFQzVMJDOvH6'
>>> bcrypt.hashpw('foo', '$2a$12$xYkBJKIdbmAZlhpl96dopOJug5oZcp4tVWJPug/xMdFQzVMJDOvH6')
'$2a$12$xYkBJKIdbmAZlhpl96dopOJug5oZcp4tVWJPug/xMdFQzVMJDOvH6'

As you can see, the resulting hash consists of multiple parts. First the 2a indicating the algorithm, then the "cost" used by the algorithm, then the 22-character salt (in plain text), then the actual hash.

The advantage of this is that checking the password can be done using the same function you use for hashing it - you just pass the full hash string as the salt and then check if it returns the same string. Another, more relevant, advantage is the fact that by storing it like this you can easily write a function to handle various hash algorithms by checking the first field. This is relevant when you have to deal with legacy passwords that were hashed e.g. using MD5 or SHA-1.

3

Some password hashing function traditionally encode the salt and the hash output as a single string, so the salt is there, but does not appear in the database as a specific column. Most bcrypt libraries do that. This might be the case for your system.

Also, the salt might be implicit (e.g. computed as the concatenation of the user name and a row ID, or something like that).

2

The salt must be known to verify the hashed password. There is no reason not to store it with the hash in the database as it is perfectly safe to be public information. It's purpose is only to prevent precomputer hashes from being used to rapidly find insecure passwords.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .