5

A good way to salt password?
I have read a few answers related to salting password. But I started to get confused. I came across few functions people used to generate salt like:

So many functions out there, so which one I need use?


and one mini question:
What I know is salt must be as random as possible for each user's password. Currently I am using pseudo random bits (as in third in above list) to generate salt to bcrypt->hash(salt+password) and store the salt together with password in same row in mysql. Am I implement this wrong?

Loonb
  • 293
  • 1
  • 3
  • 9
  • 3
    In addition to the two excellent answers below, see: http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords, http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage, http://security.stackexchange.com/questions/17421/how-to-store-salt –  Sep 06 '12 at 06:45

3 Answers3

7

To be effective, a salt should be random (unpredictable) and unique (thus, a nonce). It doesn't have to be very long (though that doesn't hurt).

Your implementation is how a salt should be handled. However, bcrypt already includes a salt, so your efforts are a bit redundant. It definitely doesn't hurt anything, though.

Jeff Ferland
  • 38,090
  • 9
  • 93
  • 171
  • Randomness is not _necessary_ but it makes it easy to get uniqueness. – Tom Leek Sep 06 '12 at 11:22
  • Randomness helps with collisions when you have a lot of hashes. Think password hashes of a milion users, when stored as descrypt (12 bit salt, 4096 maximum). There's gonna be many hashes that share a salt, thus lowering the level of effort to cracking them, which undoes the whole point of having a salt. If you only have only one hash total, it makes next to no difference how long the salt is. But for any non-trivial amount of hashes, long salts good, short salts bad. (Assuming their randomness is equally good) – Marcin Sep 06 '12 at 14:29
  • Yes, but doesn't the uniqueness matter more than the randomness? My understanding of salting is that it is primarily designed to make it so that per-established tables can not be used for attempting to break a hash. As long as the salt value is different, then it should render table attacks useless. The main benefit I could see from randomness would be that it avoids the issue of salt overlap between systems (for example if company A started with a salt of 0000001 and so did company B, then most hackers would have tables for 00000001). Is this the only reason that randomness is desired? – AJ Henderson Sep 06 '12 at 15:06
  • @AJHenderson Yes, exactly that. – Jeff Ferland Sep 06 '12 at 15:49
  • although this answer is accepted, all answers below are great. So all 3 answers are accepted (implicitly XD) – Loonb Sep 09 '12 at 21:07
6

Normally, if I recall correctly, Bcrypt has it's own built in salt. So you don't need to define your own salt as Bcrypt generates salts when hashing and stores them with the output.

From stackoverflow:

Stored in the database, a bcrypt "hash" might look something like this:

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

  • 2a identifies the bcrypt algorithm version that was used.
  • 10 is the cost factor; 210 iterations of the key derivation function are used (which is not enough, by the way. I'd recommend a cost of 12 or more.)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa is the salt and the cipher text, concatenated and encoded in a modified Base-64. The first 22 characters decode to a 16-byte value for the salt. The remaining characters are cipher text to be compared for authentication.
  • $ are used as delimiters for the header section of the hash.

This example is taken from the documentation for Coda Hale's ruby implementation.

Lucas Kauffman
  • 54,169
  • 17
  • 112
  • 196
  • It depends entirely on the used library, if Bcrypt creates it's own salt. If you use PHP's standard function `crypt()`, you will have to generate the salt by yourself. – martinstoeckli Sep 06 '12 at 11:29
  • 1
    @martinstoeckli You should NOT be using php crypt() to hash passwords anyway. Don't reinvent the wheel. If you are using php, use phpass. –  Sep 06 '12 at 12:11
  • Extra info: [why bcrypt is better than PBKDF2](http://security.stackexchange.com/a/6415/12707) – Loonb Sep 06 '12 at 12:17
  • @Terry Chia - I didn't recommend to use `crypt()`, but crypt() is the only native PHP function that implements Bcrypt, there is no function bcrypt() which generates the salt [yet](http://security.stackexchange.com/q/16506/8343). So either you use a library and then it depends on the library, whether the salt is generated and how, or you have to generate it yourself. By the way, i strongly believe that one should understand how it works, and then one should use a well established library. – martinstoeckli Sep 06 '12 at 12:53
  • 1
    @martinstoeckli Even so, just use phpass. It is just one addition file to include, simple to use and very well documented and takes care of all the heavy lifting for you. Like i said, don't reinvent the wheel. –  Sep 06 '12 at 13:23
  • @Terry Chia - Yes i know, i studied it very thoroughly. – martinstoeckli Sep 06 '12 at 13:27
  • looking back these great answers. all three answers should be marked "answered" – Loonb Apr 03 '19 at 00:38
3

A salt must be unique. It does not have to be anything else (some password hashing algorithms have specific requirements on the length of the salt, but, in general, it is free-form).

Uniqueness should be understood worldwide and for all centuries. Ideally. Being unique to your server is not totally sufficient (an attacker could try to attack several servers at once, for the cost of attacking one). Being unique at a given time is not totally sufficient (e.g. if you reuse the salt whenever a user changes his password, an attacker could try to attack both the old and the new password for the cost of one password cracking effort).

An easy way to get the right sort of uniqueness is randomness. Being unpredictably random is not necessary for a salt, but if the salt is a sequence of at least 128 bits (16 bytes) which are obtained from a cryptographically strong PRNG, then you will get uniqueness "for free" with an overwhelming probability (and that's good enough).

(Unpredictable randomness is a requirement for other objects which are sometimes incorrectly called "salts", such as IV for CBC encryption; I assume that when you say "salt" you are really talking about password hashing.)

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • how do you call the unpredictable randomness? nonce? yes. password hashing. I have redundant salt, as Jeff Ferland said. Very great answer! I finally get an overview of the purpose of salt. Thanks – Loonb Sep 06 '12 at 11:50
  • I'd argue that the salts should be random. Perhaps not cryptographically random, but random nonetheless. If the salt is very predictable, e.g. 000001 and increasing, an attacker might very well try to generate password hash tables in advance to attack admin accounts which usually are the first few accounts. –  Sep 06 '12 at 12:08
  • @TerryChia - yes, but then it would not be unique in the cryptographic sense of the term. Starting from 000001 is not unique unless nobody else is doing the same thing and never has done the same thing. – AJ Henderson Sep 06 '12 at 15:17
  • @TerryChia: if every servers starts a counter at 1, then it is not unique _worldwide_ -- and, precisely, it allows precomputing tables which will be applicable to several servers. However, if every server uses a counter which starts at a big random value, then the counter for a given server is very predictable, and yet you get worldwide uniqueness. Purely random salts are still easier than a server-wide counter, though (in particular with multi-frontend servers). – Tom Leek Sep 07 '12 at 00:47
  • Out of curiousity, what about some globally-unique-but-not-random scheme, like concatenating your DNS name with a simple counter? E.g. `security.stackexchange.com-0001`. Obviously I would still recommend the simpler random value, but I'm curious how a scheme like this would hold up. – AviD May 13 '13 at 11:13
  • Reliably maintaining a counter is hard across reboots, and hard when there are multiple frontends as well. DNS names are unique worldwide but not necessarily forever (domains are sometimes abandoned and then registered again by someone else); also, uniqueness does not work for internal, closed networks. Apart from that, it would work. – Tom Leek May 13 '13 at 16:56