3

In a recent discussion somebody mentioned the following hashing scheme:

passHash = sha256(password)
saltedHash = sha256(passHash+passHash.substr(-10)
finalHash = sha256(secret+saltedHash)

The password is hashed, then hashed again with the last 10 characters of the previous hash as 'salt'. Finally a secret is appended and everything is hashed again before it's saved to the database.

How secure is this? I know that equal passwords will have the same finalHash. But apart from that, how bad is it to use part of the hashed password as salt? Does having a secret salt later help? How bad is it to have only 3 iterations of sha256 instead of a few thousands? Is there an easy attack that proves this hashing scheme is bullshit?

Lincoln
  • 141
  • 4
  • 1
    That person needs a stern reminder not to roll their own crypto. Password-specific hashing functions like bcrypt and scrypt exist, they handle the details for you, and they have been designed and reviewed by actual cryptographers. Use those. Please don't inflict another poorly-conceived password hash onto the world. – Stephen Touset Aug 19 '14 at 05:17

4 Answers4

17

Don't do it. Salts have to be unique, that's their only requirement. But your approach doesn't generate unique salts, but password-dependent ones.

A per-db-unique salt helps when its long enough (256 bits), and you also hash in the username, but that still leaves issues.

Having only 3 iterations of SHA256 is rather not the way password hashes should be, although its not just a 'higher is better'. If an attacker is busy doing lots of iterations of sha, they can't try new passwords. Make sure you use PBKDF2 or similar to prevent further attacks. You can take the logarithm by 2 from the iteration count, and then you get the added 'bits of security' for breaking a password. Iterations give you a tradeoff between computation power and security, but to a very (1:1 instead of 1:exp with password length) unefficient conversion rate.

What you are doing is not salting, its baking a new hashing function from another one. For every user, create a random string with 256 bits of entropy from a PRNG, and use that as salt.

user10008
  • 4,315
  • 21
  • 33
  • 8
    `What you are doing is not salting, its baking a new hashing function from another one.` This is **REALLLLLLY** the key point. +1 – Cruncher Aug 18 '14 at 20:55
  • Ditto this, use a real, computationally expensive KDF like PBKDF2, BCrypt, or SCrypt with a significant amount of computational effort required to check a password. – Naftuli Kay Aug 19 '14 at 03:24
  • "A per-db-unique salt helps when its long enough (> 256 bits)" not when hash function is vulnerable to collision attacks. – sampathsris Aug 19 '14 at 05:03
  • Although I broadly agree, the choice of using >256b of entropy is probably overkill. You only need enough bits to know that, with high probability, there will be no collisions in your database; taking into account the birthday paradox. For many small databases, this can actually be a surprisingly small number of bits. I often just leave it at 128b and call it a day, but resource constrained applications will want to consider this. – Tinned_Tuna Aug 19 '14 at 09:10
  • 1
    @Tinned_Tuna you are right its overkill. I've edited my answer to remove the >. I've taken the number from [How to securely hash passwords?](http://security.stackexchange.com/a/31846/52967) – user10008 Aug 19 '14 at 09:22
4

Short answer: don't do it.

Salt should be used to provide some security against leaked hashed passwords, since the same password will have the same hash, when unsalted.

If salt is predictable, there is no gain.

Since you're not adding any entropy by doing that, there is no gain by doing that kind of thing.

And since you're using a very small number of iterations, it just leaves the too-fast-to-be-used-in-passwords SHA-256 alone, prone to all those weakness you said in your question.

woliveirajr
  • 4,462
  • 2
  • 17
  • 26
1

Your "salt" doesn't seem to provide any of the benefits that are the point of using a salt. Using your scheme, each password only produces a single output, so an attacker knowing your scheme (which you must assume they do) can easily produce a rainbow table of possible hashes to match against those in your database.

A salt is supposed to prevent this, because a different salt for each password means that even if they are the same password the resulting hash will be different, so generating a rainbow table is infeasible, because it would need to contain not only a hash for every possible password, but a hash for every possible combination of password and salt.

As others have said, 3 iteration of SHA256 is still going to execute way too fast. You should be using a mechanism that has been specifically designed for hashing passwords such as BCrypt. Even when you are using a mechanism that is suitably slow you should not permanently tie yourself to a single speed or number of iterations; computer speeds are always increasing and you will want to increase the number of iterations to keep ahead of them. BCrypt allows you to do this without breaking existing hashes as it encodes the strength to be stored along with the hashed password.

Sean Burton
  • 141
  • 7
  • If there is only one implemention of this scheme, what benefit do a rainbow table have? Will not a direct bruteforce be equally computationally expensive? – Dog eat cat world Aug 19 '14 at 06:14
  • 1
    Well, yes, they're just different ways of going about the same thing. There's nothing stopping you generating each possible hash on the fly and then comparing it to each entry in the database. A rainbow table just allows you to compute the table in advance, then once you have the table the actual comparison goes much quicker (at the cost of the size of memory/storage the table takes up). If you generate the hashes on the fly rather than generating a rainbow table, and then you get a bunch more hashes you need to crack, you'll have to generate them all again. With the table you won't. – Sean Burton Aug 19 '14 at 15:32
1

Simply put, the purpose of the salt is to make hash different for the same password.

hash('password') == hash('password') // same password, same hash
hash('password'+salt#1) != hash('password'+salt#2) // avoid hash collision with salt

Now let's take your approach and expand it. It is equivalent to:

finalHash = sha256(secret+sha256(sha256(password)+sha256(password).substr(-10)))

For a given password, this will return the same value every time. This is essentially a new hash function built on top of sha256. That means your credentials table has hash collisions. But you already know that. But do you know this:

This means that attacker may be able to even find the secret by brute force (if the secret is considerably smaller in length, or the hash function has collisions), because there's always that bunch of users who use 'password', '123456', etc for their password. Attacker simply has to attack against the most common hashes in your credentials database.

From this point onward, chaining of hash functions is not going to give you much additional security, because four calls to sha256 does not contain much practical overhead to an attacker than a single call.

TL;DR: Don't do this.

sampathsris
  • 805
  • 1
  • 6
  • 12