1

Currently I am using a particular scheme for securing passwords, and I think I have some points for improvement. The implementation is in Java, so I prefer to use SHA-2 512 as encryption form.

Currently I have a client-server model, so these things can happen:

  • Client wants to login, he sends his password with one time normal SHA-2 512 encryption over the network.
  • The server has the passwords stored in the database as for example SHA-2_512(SHA-2_512(password) + salt), with the inner SHA-2_512(password) being the 'encrypted' password it receives over the network.
  • Password checks are done server side and there is no way anything can leak out from the server, the only possible vulnerability would be if someone could read out the RAM I think.

I have these questions:

  • An attacker usually creates collision attacks when wanting to hack a password. However how are collision attacks sufficient? If the password needs to be used for other applications like Outlook.com, Facebook or whatever (which likely use another salt as they have nothing to do with my applications), how is a collision attack enough then? Don't you need the real password?

  • Does SHA-2 512 already use iteration? And even if so, should I change my encryption methods to automatically use a number of iterations plus how many iterations is preferred? I have also read about using a random number of iterations (in a range), how do I store the random factor determenistically?

  • Should I store system secrets for every iteration in the server code? See http://blog.mozilla.org/webappsec/2011/05/10/sha-512-w-per-user-salts-is-not-enough/ . I could store an array which would hold a static secret for every iteration, with the nth secret being for the nth iteration. Nobody can know the secrets, they are computed once (I guess as encrypting some random string), and then basically stored in the Server's RAM.

  • Currently I send the typed password from the client to the server as just SHA-2_512(password), should this process be improved, and if so, how? I cannot use salts, because the client does not have the salt available.

Regards.

skiwi
  • 66,971
  • 31
  • 131
  • 216

1 Answers1

5

TLDR: You need to send the password using an encrypted channel, such as TLS. Consider using bcrypt for password hashing.

SHA-2 512 is not an encryption algortihm, it is a message digest algorithm. An encryption algorithm requires a key and a message to encrypt. It produces ciphertext. The important thing is that an encryption algorithm has a decryption algorithm.

ciphertext = E(key, plaintext);
plaintext = D(key, ciphertext);

A message digest takes a piece of plaintext and produces a message digest. There is no corresponding reverse mechanism to take a message digest and retrieve the original message. There is also no secret key.

digest = hash(plaintext);

If an attacker is able to access a database with hashes, the attacker can retrieve the original password by brute forcing, trying lots of guesses with the hash algorithm.

digest1 = hash(guess1);
digest2 = hash(guess2);    //repeat with lots of guesses

Firstly, sending a hash over a network is not secure. It needs to be sent through some secure communications mechanism such as SSL. If an attacker can intercept the hash over the communications they may be able to work out the orignal password.

A hash collision is not the same as brute forcing the password. A hash collision is caused when two different messages produce the same message digest.

digest1 = hash(plaintext1);
digest2 = hash(plaintext2);
if ( ( plaintext1 != plaintext2 ) && ( digest1 == digest2 ) )  
    // hash collision

SHA-512 does not have iterations designed to prevent brute-forcing. The SHA set of algorithms are designed to be efficient. The reason for adding iterations when hashing passwords is to increase the time it takes to brute force a password. The idea being the cost to perform a legitimate login attempt and perform 100 iterations is tiny compared to an attacker who has millions of passwords, each of which requires 100 iterations. Adding more iterations helps reduce the impact of improved processor speeds (which would help an attacker try more iterations quicker).

You should make the number of iterations a configurable limit that is stored against each user. So you store the password hash, salt and iteration count for each user. This means that in the future you can increase the number of iterations to take into account increased hardware power.

Sending the SHA-2 512 in plaintext is not secure. You should send it within an encrypted channel, such as SSL.

Having said all that, SHA-2 is not designed to be a password hashing algorithm. It is designed for message validation and is to be efficient. Consider using a purpose built password hashing algorithm. One example is bcrypt. It is designed to be computationally difficult and has salt and iterations built in.

Steve
  • 7,171
  • 2
  • 30
  • 52
  • I researched a bit and I think this is an important note to add: BCrypt should be done client side for authorization (and server side once for registration / password change). So the stress on the server is really really low. Correct me if wrong though. Is there a way to determine a good work factor? – skiwi May 19 '13 at 15:33
  • @skiwi I don't think you should perform the bcrypt calculation on the client side. Could you share your references please? The stress on the server for using bcrypt is still quite low, but the stress for an attacker trying to bruteforce it by trying 1000s of guesses is very high. – Steve May 19 '13 at 15:42
  • Take a look at http://stackoverflow.com/questions/4443476/optimal-bcrypt-work-factor for determining work factor. – Steve May 19 '13 at 15:42
  • 1
    Can BCrypt be safely used without adding an extra salt (by myself) to the password you want to hash? I know it already incorporates a salt, is that enough for the job? Also Java gives a `char[]` from the `JPasswordField` but BCrypt forces me to use a `String`, meaning that the password floats around in the memory, is that a concern? – skiwi May 19 '13 at 15:55
  • Yes, it's good enough for the job. You don't need to add another one in there. – Steve May 19 '13 at 16:00
  • It's a bit of a concern [see here](http://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords). However, if an attacker is already on the client machine and reading process memory they've got other ways of getting the password (such as key logging). I wouldn't let it stop you using the library. – Steve May 19 '13 at 16:05
  • Could you kindly look into a new post of mine? http://stackoverflow.com/questions/16636711/java-is-this-good-use-of-bcrypt Sadly I haven't found the option to PM on this site as this being a comment isn't the best idea. – skiwi May 19 '13 at 16:42