I read an interesting article about an alternative way to store password hashes ans was rather intrigued.

A better way to store password hashes?

The primary concept is having a large table full of salted password hashes that doesn't have any key tying them to a user; the user records would contain only the unique salt. When a user attempts authentication, the provided password is then hashed with their salt, and if it exists, they are authenticated.

This allows for a huge amount of fake data, making the hash table practically useless to an attacker, not to mention far to large to copy/transport easily (eg, via USB key).

Is this a sound method?

What kinds of metrics can we use to compare this with the more common method of storing a hash in the user record? Any Experts care to give us a comparison?

  • 1
    "far to large to transport." Hug? If it is so large that you cannot transport it, then you cannot do anything useful with it (store, backup, check, etc.)
    – curiousguy
    Jul 10, 2012 at 3:03
  • That was a bit off-point--I clarified a bit. Thanks
    – Bryan Agee
    Jul 10, 2012 at 3:29
  • The author suggests a method to fix the hidden backdoor problem at opine.me/all-your-hashes-arent-belong-to-us Jul 24, 2012 at 15:27
  • I would add, it wouldn't be a major increase in CPU time and RAM to search the table like the article suggests, most databases would end up with the hashes in a binary tree index or sorted. Once that is done, a search of the table for a matching hash would only be logarithmic time.
    – ewanm89
    Jul 25, 2012 at 11:20
  • Even without sorting/indexing it would only be a log(n) increase. But if I was an attacker and just stole the database, I would just index it before running an attack.
    – ewanm89
    Jul 25, 2012 at 12:21

6 Answers 6


Maybe I don't understand but if I were an attacker I would do the following:

I would steal both tables. Then I would select a user I am interested in (e.g. an administrator) and start hashing passwords using his salt and look if the resulting hash is to be found in the hash table.

So what's the difference? (except that I have to lookup if the computed hash exists instead of just comparing (DB servers are good at such tasks)

P.S.: The author also argues that the size of the table might make it harder for the attacker to steal it. That's a good point. (Unless he doesn't steal it but runs the lookup queries on the site's DB servers)

It is an interesting idea that should be topic of more (academic) research.

P.P.S.: The author suggests a method to fix the hidden backdoor problem here. On first impression this seems to fix it.

  • 7
    Not to mention all the additional inconveniences, like making your backups grow several GB. Also an attacker could grab the admin salt and insert a new hash in the table. It'd be a completely stealthy backdoor.
    – Zzz
    Jul 10, 2012 at 0:46
  • 1
    That's just it--rather than only having to lookup one result (the one associated with that user) you have to check for the result of each attempt, with each salt, through the whole table. If you're using the right hashing algorithm, this is no trivial thing.
    – Bryan Agee
    Jul 10, 2012 at 2:42
  • And to also mention that the more heavier the hash table is, the longer it will be required to find the corresponding value in the table. I think the link between increased security and complexity is inegal here.
    – Cyril N.
    Jul 10, 2012 at 8:16
  • 1
    If the attacker is running lookups on your server, the password security may be irrelevant by that point.
    – Bryan Agee
    Jul 10, 2012 at 8:27
  • 1
    (Inserting additional hashes with correct salts) That is a very important point I didn't think of, @Zzz! This breaks it. Any ideas how to fix it? Jul 10, 2012 at 9:47

I think its silly. It will just be more expensive to verify which you can already control with bcrypt. Also, theres a small chance one of the many user with a weak password will collide with an admin's salt+strongpass. When there are 1M users you'll have 1M more chances a password will match. It's also harder to control performance. And what happens if you want to reset a users password? You'd have orphans passwords which will also be checked if a password matches.

Theres also logical problems like: what if you want to shard the DB so users from certain continents have servers dedicated to them? There are too many problems. All this to prevent someone from guessing your password when they stole the hash? If the hash is stolen you have other concerns like what else is stolen. Just use bcrypt with more passes for a slower time which doesnt cause collision and other drawbacks mention.


-edit- I rethought what the performance difference will be. After thinking about it, hashes could be sorted and organized so you don't actually need to look at as many as one may think. The difference is instead of CPU performance of checking out the password its CPU+disk/ram. The biggest difference is how much data a hacker would need to take. But remember, the burden is on you as well. I rather force more CPU time (which is possible with bcrypt) then how much disk space i need.

It may be more noticeable or take longer for a intrude to transfer all that data but if the CPU time is long enough that it takes several weeks to decode a 6letter password (remember you can force users to use longer passwords) and you notice intrusions the week of (let alone day) then you can lockdown all old passwords. It not worth making your data fat in the name of security. (Thats kind of like security through obscurity, except its just fat rather then a secret)

  • 1
    Per snobby_penguin on reddit: k(k-1)/2N with 160-bit hashes and 6 billion users * 10 passwords (pretty optimistic, yes?) we get: .6 * 10^13 * (.6 * 10^13 - 1) / 2 * 1.461 X 10^48, or 3.6 * 10^21 / 2.923 * 10^48 OR ... Less than 1 IN 10^26 chance of collision.
    – Bryan Agee
    Jul 10, 2012 at 11:10
  • @BryanAgee Check out my edit in a min or two. After remembering its 160bits i thought about where the performance difference would be and... check my edit ;)
    – user5575
    Jul 10, 2012 at 11:17

I posted a follow-up article which explains in more details what my design goals are, and also why collisions are not a problem here: http://www.opine.me/all-your-hashes-arent-belong-to-us/

This approach decouples hashes from specific users, and fuzzes your hash tables with random data. This is not as a replacement for scrypt, but instead attempts to increase the cost of an attack across new axis--storage and bandwidth--which should help deter and increase detection of attempts to steal your hashes.

An additional benefit is that attackers can no longer target specific users without first managing to steal a large portion of a database of which you can directly set the size.


Okay, so you are trying to protect against an attacker who HAS access to your database from benefiting from it.

If I was said attacker I would cycle through your user table and create new hashes for a standard password for all of the users. As you are using a salt that will mean that the hash table grows by the number of users, but since you have such a bloated hash table you are unlikely to notice.

In short, I am not sure you are gaining any additional protection but you are losing on performance which will get worse as the solution scales or users come and go.

  • 1
    To be fair though, if you can insert/update rows into the live DB then no password security could keep you out, since you can simply change the admin's hash to one which you know. Sep 15, 2014 at 11:10
  • I was thinking in terms of a rogue operator who gains short term access to the database, and can perform such an action to be utilised quite some time later. In my line of work the admin of the system logs on via separate infrastructure rather than using the web so that is not an issue. Point taken though for web admins.
    – DodgyG33za
    Sep 15, 2014 at 12:40

This is beyond insecure.

First, the means for authentication just checks for hash existence in the table, there is no such thing as fake data in the table. If you add a hash to the table, fake or genuine, then you have just added a hash that is valid for all accounts. So, if you have a table with one million hashes then there exists at least one million valid passwords for EACH account. Increasing the number of hashes in the table with additional fake data merely increases the number of valid passwords as well. Thinking intuitively, what is easier to accomplish: finding a password that generates a specific hash or finding a password that generates one of many hashes?

Second, the DB performance is a most likely a non-factor. The SQL lookup required would be searching for the existence of a primary key. Primary keys are always indexed so the lookup will always use the index and should at most need to scan one record. Additionally, the lookup would involve a covering index so the query would merely return the value stored in the index and not even have to use the actual table data fetched from disk. The performance of the query would be most likely be constrained by how much of the index can be held in memory at one time.

  • -1: By storing salted hashes in my table, there already exists an infinite number of passwords for EACH account that match that hash. Once I have infinity, multiplying it by a few million doesn't make it any bigger. (I admit that's not very intuitive).
    – David Cary
    Jul 17, 2012 at 16:58

Summary. This is a clever idea that in principle might help improve security a little bit, but in practice probably doesn't help enough to be worthwhile. To really evaluate the idea, you have to measure quantitatively how much it helps, and when you do that, I think you find that the idea provides almost-negligible benefit. Nonetheless, it is a clever idea and one that in some sense "almost worked". I salute the author of this idea for thinking outside the box. Even though the idea turns out not to be useful, at least the author was trying something creative and innovative.

The purpose. Let's be clear on what the goals are for this scheme. It is not intended to be perfect: it not intended to make password-hashing impossible, merely to make it a little bit more expensive. So, to measure how much it helps, we need to measure exactly how much more expensive it makes password-cracking (see below). Also, this proposal is not intended a replacement for using a proper password hashing function (scrypt, bcrypt, or PBKDF2), but rather a supplement. It might add only a modest amount of additional security, but hey, I'd take anything I can get: if it significantly increases the cost to the attacker, at essentially no increase in cost to the good guys, that would be a great tradeoff.

Unfortunately, it turns out that things are not so rosy. The benefit is negligible.

Database size. Let me start off by refuting one argument that I totally don't buy at all. One person raised the suggestion that if you add enough bogus chaff to the list of password hashes, then the database will be too big for the attackers to steal. Baloney. I don't buy that argument at all. There are limits to how much chaff you can add, because you need to be able to store the database, back it up, etc. And given those limits, I don't believe the size will be a barrier to theft of the database. So let's just agree to take that argument off the table. Instead, I want to focus on the aspect of the proposal that I think does improve security.

Cost of password cracking. So how much does this proposal help? It forces an adversary who wants to crack your password to do many lookups into this table. That sounds like something that might make password-cracking expensive. But to see how much it helps, we need to measure precisely how much more expensive it makes password-cracking.

So, let's do a comparison between plain bcrypt (the current state-of-the-art), vs this proposal with bcrypt. Suppose the attacker has stolen a copy of the database. With plain bcrypt, if the attacker wants to try one billion guesses at my password, the attacker has to compute the bcrypt hash one billion times. We can make that go pretty slow, let's say 10 milliseconds per hash, so that might take about 100 million CPU-seconds, or about 4 CPU-months. So that's our baseline.

With this proposal, the attacker has to compute the bcrypt hash one billion times, and check each resulting password hash to see whether any of them appears in the database of password hashes. The latter sounds like it might be expensive: it could easily take 10 milliseconds to do a database lookup, so maybe we've introduced the cost from 10 milliseconds per guess to 20 milliseconds per guess? Sounding promising.

But wait, don't get too optimistic. The attacker can optimize the password-cracking attack if she uses just a little bit of ingenuity. Rather than checking each of the billion bcrypt-hashes, one by one, as they are generated, it is more efficient to batch them up and check them all at the end. The attacker could compute one billion bcrypt hashes, save all the results (all one billion of them), and then check whether there is any overlap between those billion bcrypt-hashes and the hashes in the database. The latter operation can be done quite efficiently; it is just a database join operation. For instance, you can concatenate the two lists, sort them, and look for duplicates (since you've sorted them, you know duplicates will be moved next to each other, so checking for duplicates becomes very easy). Such a merge-join operation can probably be done in minutes.

Let's tally up the total cost to the attacker if we are using this new proposal. The attacker spends about 4 CPU-months generating one billion bcrypt-hashes, then spends a few minutes doing the merge-join operation. The total time is 4 CPU-months plus a few CPU-minutes. Compare to if we use standard bcrypt hashing (without this proposal); there the attacker's cost would be 4 CPU-months. The difference is negligible.

Bottom line. In conclusion, if you take a careful look at the cost of password-cracking, you'll find that this proposal does not seem to increase the cost of password-cracking by a noticeable amount. Therefore, I do not believe this proposal is worth implementing: while it is a clever attempt, it doesn't really help in the end. That's a shame, but so it goes.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .