15

I learned that the Sun guys used the login name as salt for password hashing. Is this a common approach? What are the most common salt values?

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
Federico Elles
  • 253
  • 2
  • 4
  • 1
    welcome to the site! Are you asking, what are good salts to use (or actually, how to create salt) correctly? Or specifically, what is commonly used (even if it is insecure)? – AviD Jul 21 '11 at 09:52
  • 1
    Also see this related question on SO: [Non-random salt for password hashes](http://stackoverflow.com/q/536584/10080) – AviD Jul 21 '11 at 09:54
  • @AviD: I'm interested in the methods. I learned a salt could be: - the username (from sun) - a random string (from the answer - but where to store it?) - a fixed string in the source code (I did this, seems not a good idea) – Federico Elles Jul 22 '11 at 08:40

2 Answers2

15

Using the login name as salt is common but not really recommended: it does only part of the job. The point of a salt is to be as unique as possible among all instances of hashed passwords, so as to thwart any attempt as parallel attacks (attacking several hashed passwords simultaneously, using precomputed tables such as rainbow tables... are parallel attacks). On distinct systems, several users may share the same login name (there are so many Jones and Smiths out there). Also, a given user may change his password while keeping his name; but even an old password is valuable for an attacker (if only because an old password is often a password that the user will reuse the next time he is being instructed to change his password; also, many users will use identical passwords on other systems).

The recommended way to generate a salt is to use a good random number generator (ideally cryptographically strong RNG) and have it produce a bunch of random bytes. If the salt is long enough (16 bytes or more) then this ensure the required uniqueness with overwhelming probability, and without much hassle (no need to lookup in a database of existing salts, for instance).

We can only hope that this recommended way is also, or will soon become, the "most common" way.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • Additionally, if you're thinking about salts when storing passwords, you're working at much too low a level. Use something like [bcrypt](http://bcrypt.codeplex.com) or [scrypt](http://www.tarsnap.com/scrypt.html) that hides these details from you. – Stephen Touset Oct 01 '13 at 20:50
7

The following is a decent system for salting and hashing passwords. There are a number of points to keep in mind, which is why it looks long. This is a typical example of what one should do when it comes to salt-hashing; I am not going to address what Sun does.

Salts and passwords are best dealt with as raw bytes (byte[], unsigned char*, etc), in case the language one uses deals with text strings in some other form.

Let's generate a new salt using a cryptographically strong pseudo-random number generator to generate the salt. In Ruby, that library is conveniently called securerandom. Most languages also come with a random number generator, but that is not sufficient for a salt.

Let's use SHA256 as our underlying hash algorithm. All hash algorithms have an output size, which is the size in bits of the output of the hash function. All hash algorithms also have a characteristic internal block size, which is not the same as the output size. Let's use a salt as large as the hash algorithm's block size. We do this because this is the largest amount of entropy we can add to the password before hashing it. If we use a larger salt than the block size of the underlying hash algorithm, then HMAC will simply hash the salt first to obtain a smaller salt, reducing its entropy, before mixing it with the password. The block size of SHA256 is 512 bits (= 64 bytes), so let's use a 64-byte salt.

Let's use HMAC-SHA256 instead of SHA256 directly, which does a little bit more work to keep the password safe. We will use the salt as the key parameter to HMAC-SHA256 instead of prepending it to the password. HMAC-SHA256 wraps up SHA256 and does a little extra work to merge the salt with the password.

Finally, the hash algorithms such as SHA-256 are designed to be fast. Whatever our code does overall, it's likely to be spending 1% of its time authenticating users and 99% other stuff. If an attacker gets a copy of the password file, his code is likely to be spending 100% of its time brute-forcing the passwords. So let's make the overall algorithm super-slow: not too slow that it impinges on the rest of our code, but slow enough to discourage the attacker. Let's take a parameter called the work factor (which might be 16), and iterate HMAC-SHA256 2 ^ work-factor times (65536 times in the example). If the work factor were 2, then that would look like

HMAC-SHA256(salt,
  HMAC-SHA256(salt,
    HMAC-SHA256(salt,
      HMAC-SHA256(salt,
        password
      )
    )
  )
)

A good yet simple solution in Ruby:

require "securerandom"
require "openssl"

# method for generating a salt and computing a hashed
# version of a password
def salt_hash(password, work_factor)

  # get raw bytes from the password string; only needed in Ruby >= 1.9
  password = password.force_encoding(Encoding::ASCII_8BIT) if defined?(Encoding)

  # use SHA256 as the underlying hash algorithmn
  hash = OpenSSL::Digest::SHA256.new

  # generate a salt as long as the hash algorithm's block size
  # using a cryptographically strong pseudo-random number generator
  salt = SecureRandom.random_bytes(hash.new.block_length)

  # use HMAC, feeding it two parameters: the salt and the
  # underlying hash; since the underlying hash is SHA256,
  # this turns it into HMAC-SHA256
  hmac = OpenSSL::HMAC.new(salt, hash)

  # iterate running HMAC-SHA256 on the password 2^work-factor
  # times to make this function slow enough to discourage an
  # attacker, but not too slow as to make the service unresponsive
  iterations = 2 ** work_factor
  iterations.times do
    password = hmac.digest(password)
  end

  # return the salt and the hashed password to whoever called
  # this method
  {:salt => salt, :hash => password, :work => work_factor}

end

# how to call the method
salt_hash("seekrit", 16)
# and the output would be
 => {:salt => "raw bytes", :hash => "raw bytes", :work => 16}
yfeldblum
  • 2,807
  • 20
  • 13
  • 1
    Yknow... for many here code is not a first language... and for many more, Ruby is unreadable ;). Can you add some explantory text? – AviD Jul 21 '11 at 09:55
  • Wrote some explanatory text. Better? – yfeldblum Jul 21 '11 at 11:49
  • Can you explain this part of your explanation better: "Let's use a salt as large as the hash algorithm's block size. The block size of SHA256 is 512 bites, so let's use a 64-byte salt." ? 512 =/= 64... – Bill Weiss Jul 21 '11 at 15:58
  • Typo, sorry. 512 bits = 64 bytes. – yfeldblum Jul 22 '11 at 01:55
  • I also expanded on why we choose this specific size for the salt. – yfeldblum Jul 22 '11 at 01:59
  • 4
    @Justice: This is in many ways a really great answer, and your methods are well considered. But: The question is about *what's the most common salt", which you don't answer. :-) And secondly, the classic wisdom is "don't do crypto yourself, use a well tested library which implements a peer reviewed algorithm". In this sense, while your solution is sensible, solutions such as PKBDF2, bcrypt, or possibly scrypt are recommended. –  Jul 22 '11 at 12:56
  • 3
    The most common salt is `""` and the most common hash algorith is `f: x -> x`. It's true that it's generally good advice not to implement your own crypto. But hopefully people can learn something from this writeup that they didn't know before. – yfeldblum Jul 22 '11 at 23:35
  • 3
    See http://security.stackexchange.com/questions/211 I agree with @jesper - this is a misplaced answer, which is ill-advised since it is new and isn't presented in the places were we discuss hashing algorithms. There are already lots of good existing methods like bcrypt, scrypt (for more hardware resistance) and PBKDF2, which are implemented on many different platforms and languages. Being able to move your hashes to another language/DB/OS/etc is often helpful. And why add hmac here? I doubt we're very worried about anyone finding a fundamental weakness in a massively iterated SHA256 hash. – nealmcb Aug 01 '11 at 00:15
  • The algorithm shown above is completely portable and can be implemented simply in any language. It uses only the standard crypto primitives (crypto PRNG, HMAC, SHA256, and a loop). – yfeldblum Aug 01 '11 at 01:00
  • One generally might use HMAC to mix a salt with something being hashed since it's safer than prepending or appending the salt by avoding the length-extension attack. One should use HMAC at least in the first iteration with the underlying hash for the rest (`hmac[sha256^(2^work), salt]`), but it's slightly simpler code to use it for all the iterations (`hmac^(2^work)[sha256, salt]`) because of how HMAC libraries are typically implemented. – yfeldblum Aug 01 '11 at 01:00
  • @yfeldblum The algorithm shown above has not been extensively analyzed by cryptographers. PBKDF2 can also be implemented simply in any language, is portable, uses standard crypto primitives, and is a NIST standard. There is zero reason to use your homegrown attempt at cryptography over something like PBKDF2. Using "standard crypto primtives" is not enough, and does not magically convey the property of security. – Stephen Touset Oct 01 '13 at 20:53