# bcrypt and pbkdf2 double hashing

If I want to protect myself from implementation of algorithm issues and inherent design flaws of algorithms in password hashing, what would be most secure way to combine two hashes?

1. bcrypt(pbkdf2(pw))
2. pbkdf2(bcrypt(pw))
3. f, l = split(pw); pw = bcrypt(f) + pbkdf2(l) # loses entropy, bad
4. pw = bcrypt(pw) + pbkdf2(pw) ## one broken, both broken, particularly bad

Something else? Should I do variation of 1-2 where I'll add entropy?

Why isn't this common/best-practice when storing user data in databases? Using any single hash algorithm seems risky when you combine implementation + design risks. Using SHA seems odd choice, as it's designed to be fast.
Seems odd that end-user needs to think about this and figure out safe way to store PWs.

I don't want to make perfect-world bcrypt or perfect-world pbkdf2 better by this means, I simply want to assume that there are scenarios where in particular environment one of them may be bad to begin with at least. Or in future one of them is found to be not as nearly secure as it was thought to be, giving me safety margin to migrate to another combo of hashes, without going into panic mode.

-
For this level of paranoia I would suggest using scrypt, although the intended use may allow one to provide a better answer. pbkdf2 can use any hash algorithm by the way. –  Richie Frame Sep 15 '13 at 9:13
As neither pbkdf2, scrypt or bcrypt are extremely common, I don't think it's paranoid to think that in some less used programming language implementation may have naive mistakes which make it much less secure than intended. I'm happy about the scrypt suggestion, but the main question remains, how should I combine two hashes to protect myself from scenario where one of them is not as secure as intended. –  ytti Sep 15 '13 at 9:23
This question might be of interest, and it's loosely connected to yours –  rath Sep 15 '13 at 11:51
@ytti - Perhaps bcrypt and scrypt aren't that common (scrypt less so), but pbkdf2 is very widely used - it's even been standardized. –  hunter Sep 15 '13 at 14:53

You have two algorithms, $A$ and $B$, that claim to compute two (essentially) injective, hard-to-invert and costly-to-compute functions $F$ and $G$. Your fear is that either of the algorithms instead compute functions $F'$ and $G'$, that may be neither injective, hard-to-invert, nor costly-to-compute. This may happen because of programming mistakes or (these days) deliberate sabotage.

What you want is some way to combine $A$ and $B$ such that the corresponding combination of $F$ and $G$, $F'$ and $G$, and $F$ and $G'$ is (essentially) injective, hard-to-invert and costly-to-compute. (If both are defective, then it will obviously not be possible to do anything.)

Observe that $F(G(\cdot))$ and $G(F(\cdot))$ are bad constructions (they fail injective).

The construction $(F(\cdot),G(\cdot))$ does not fail injective and costly-to-compute, but may fail hard-to-invert.

If we assume that $F$ and $G$, $F'$ and $G$, and $F$ and $G'$ are in some sense independent (that is, say, $F'$ is not $G$), then $$F(\cdot) \oplus G(\cdot)$$ should be ok.

Why don't we do this? To a certain extent, you can verify the implementations by comparing with test vectors and other known-to-be-good implementations.

-
Why would you even consider the possibility that F(G(·)) is hard to invert? If this is a tangible possibility, it means that there is some message m that is considered weak - namely F(m) is not hard to invert (in your scenario, we declare m = G(·) ). Is there a message that is considered weak for any of the common hash functions? –  Ninveh Sep 15 '13 at 15:10
I was thinking about pre-image resistance, rather than inverting the hash function. I'll fix. –  K.G. Sep 15 '13 at 16:07