3

The general method used for storing passwords securely involves generating a salt, feeding the salt and password to the password hashing function, and then storing the salt and the output of the password hashing function in the database.

However, instead of generating a random string of characters as a salt, why isn't a salt derived from the user's properties be used?

A "derived salt" could be obtained as follows:

  • Calculate some property of the user's password, such as the sum of the ASCII values of each character. (Example: "Pa$$word!" => 80 + 97 + 36 + 36 + 119 + 111 + 114 + 100 + 33 = 726).
  • Combine this with some other property known about the user, such as the email address of the user. (In our case, "[email protected]" + "_" + toString(726) => "[email protected]_726").
  • Use this as the salt for hashing passwords.

Of course, there could be multiple variations on the above described scheme, by varying the function of the password taken, and the properties taken for combination.

What are the disadvantages of using a "derived salt" scheme for password storage, over randomly generated salts?

Additionally: if both of these are nearly equivalent in their security properties, why are derived salts not used for password hashing?

3 Answers 3

1

The reason for adding a little salt to a password before hashing it, is to make it much harder to reverse the hashing. Therefore a completely random number is the best solution.

Having to come up with a "derived salt" number which is unique enough so as most of your user passwords have a different hash is going to be difficult. When generating a large enough salt number (16 bytes, for example) will likely be unique for all the users who will ever create an account on your system without much hard work on your part to determine the uniqueness.

Also, using a parameter such as the email address of the user can be tricky. If they want to change their email address, you lose your "derived salt" unless you force the user to change their password at the same time they change their email address (or any other user parameter used in the computation of your "derived salt".) So either way you would certainly want to save the salt in the database to make sure you can always compare passwords on future user log ins.

3
  • Uniqueness isn't a problem if you require unique emails. Commented Dec 25, 2015 at 20:48
  • Except that the salt "breaks" when your user changes his email address. Of course, you can always keep the old email address for calculating your salt, which is fine too. Yet it seems to me this defeats the purpose of a "derived salt". Commented Dec 26, 2015 at 4:32
  • 1
    I agree with what you said, just not the unique part. Commented Dec 26, 2015 at 4:47
1

I don't think a unique derived salt is any worse than a random unique salt. The only purpose of a salt is to confound discovery of the passwords when the table of hashes is obtained.

For a password to be discovered from a hash, it has to be somewhat guessable in the sense that it found in an existing rainbow table, or (for example) identical to another password in the data set.

+--------------------------------------------------+
|    password   |               hash               |
+---------------+----------------------------------+
| freaky        | 33ca4223307e2fa4fd77c394ceb4e37b |
| freaky        | 33ca4223307e2fa4fd77c394ceb4e37b | <- identical to previous
| Freaky Friday | 852d2f614f08a63911f8944df6df40df |
| ...

What that in mind, let me restate the purpose with one further grain of precision:

The only purpose of a salt is to confound discovery of easily guessable passwords when the table of hashes is obtained.

Even the worst possible salt supports that objective pretty well. Let's say for argument that I were to salt every row with the predictable and rather obvious 8 bytes "Salted__" (noting, please do not actually do this).

In Crackstation.net today I don't even find "Salted__123456", so presumably the attacker would have to identify or create a custom rainbow table before they could begin the attack. But note, weak passwords such as "freaky" would still have the same hash and would therefore still be an initial focus for the attacker to try the "top X passwords" or whatever. And once the rainbow table was built, the attack could continue for the entire data set.

The next most powerful choice of salt, therefore, would be unique per row. That would mean the attacker would have to build a new rainbow table for each password. This means if the attacker is only after one of your users, the effort is the same as the static salt above. But, if the attacker wants your entire table the time complexity of cracking has gone way up.

I don't believe it makes a difference whether the salt is unique and random; or just unique.

Imagine you are the attacker and you have the hashes. You know you are going to have to build a rainbow table to attack each and every row. Does it matter what the salt values are? Whether you see the unique salt value in the hashes table; or whether you know the salt is the customer_id or whatever, doesn't change the amount of work you have to do.

Next imagine you are the attacker and you do NOT have the hashes. What if you learned that the passwords are salted with the customer id? I guess this means you could precompute all of the rainbow tables prior to effecting a theft of the hashes, but this doesn't lessen the difficult part of your workload, so I would claim that it is insignificant.

2
  • By OpenSSL you apparently mean the commandline enc utility which is one of maybe ten interfaces to password-based AES encryption in OpenSSL (plus more non-PBE, to which salt does not apply). enc by default uses 8 octets (64 bits) random salt; the string Salted__ at the beginning of the file is just very simple (arguably too simple) metadata to distinguish the salted format from an earlier (roughly 1995) non-salted format. Commented Apr 20, 2016 at 4:20
  • Thanks @dave_thompson_085. Yes, I was referring to the enc openssl app. I really did think that the default 8 bytes are "Salted__" based on a superficial skimming of the source code. I will update my description. Commented Apr 20, 2016 at 12:01
0

The main point of adding salt is to increase the entropy of the password. This is to protect from the potential for anyone to create pre-built rainbow tables of a large set of passwords to crack passwords.

The easiest, and most straightforward way to do this is to simply generate a random number. You can generate as much entropy as you want. It's a simple design that's easy to implement, and hard to screw up.

Picking some random details of a user and using that as a derived salt is both more complicated, and easy to screw up. The scheme you came up with actually provides MORE information about the password, making it easier to crack. The email address is know, the password isn't. But since you're providing the sum of the password values in the salt, there's now an easy pre-check before trying the hash. Before you attempt to hash the password (should be slow) Just sum the (attempted) password, and compare it to the sum in your stored salt. If it doesn't match, try another. This can increase guess attempts GREATLY since summing the potential password is MUCH MUCH faster than hashing it.

That's solvable of course with a different design, but the point is that security design is HARD, and that's why you should normally go with well accepted solutions over your own. You're far less likely to fall into well known traps that way.

You must log in to answer this question.