1
$\begingroup$

I hope this question isn't too similar to one that's already been asked. I also want to point out I know part the answer already, AFAIK: I just want some expert input on this.

Let's model a hash that more strictly is a possibly weak PBKDF. It would exist – if it worked – to slow down the cracking of passphrases (relatively short inputs), using well established secure hashes (i.e. SHA-2).

Looped hash on message (UserInput)

I'm well aware that modern ASIC/GPU technology would make cycling-hashing very brute-forceable on weak enough passwords and by cycling hashing I mean

PassHash := Hash(UserInput)  
Do Loop 1024 times{  
    PassHash := Hash(PassHash)
}  
Output := PassHash 

In this routine, "Hash" may be SHA-256 (NOT HMAC, but a regular Hash). This pseudo-routine would be just as vulnerable to rainbow tables as SHA-256, AFAIK.

So, let's purpose a small alteration, instead we use this (also bad) "KDF":

Looped hash on salted message (UserInput | Salt)

PassHash := Hash(UserInput | Salt)  
Do Loop 1024 times{  
    PassHash := Hash(PassHash | Salt)  
}  
Output := E(Hash(UserInput),Salt) | PassHash

E is performed with any good cipher that will take a 256bit key.

Above "Hash", would still be something like SHA-256. For example: Salt would be a randomly picked ~80 bits. The UserInput variable, (The Password/Passphrase) could be any length but ideally wants to be at least 112 bits.

PBKDF/2

In PBKDF/2, as I understand, we wouldn't use a HASH, but a HMAC (one reason being a lot of hash-functions are vulnerable to length-extension attacks).

Question

As I stated, I recon this code could be much worse than PBKDF2 and bCrypt and I can think of some reasons why. What I'ld like to know is: what are the biggest flaws in this routine, if any and why? And… maybe someone could demonstrate how we’ld go about attacking the design laid out above to show any major weaknesses?

$\endgroup$
  • $\begingroup$ your edited construction is completely different now, is there any purpose to hiding the salt behind a hash? $\endgroup$ – Richie Frame Jan 19 '16 at 6:52
  • $\begingroup$ The edit does make a big difference... you could ignore the idea of "hiding" the salt to answer the question easier. My thought process was, making knowing the salt dependent on knowing the input (in theory), then it's harder to brute-force as in this instance we've kept the salt a secret (something that doesn't normally need doing). In the output, the last 256bits are the ones for the key, the first 80 bits are the ones that simply represent the byte, without giving away it or the input (I hope). Essentially if we treat the 80 bits from the hash as random, we hid the IV using perfect secrecy $\endgroup$ – Iam Nick Jan 19 '16 at 7:00
  • $\begingroup$ @Richie Please feel free to tell me why this afterthought is a bad idea, if you think it is. (This new output is meant to be ideal for storing, rather than what a KDF is there for.) $\endgroup$ – Iam Nick Jan 19 '16 at 7:01
  • $\begingroup$ There are 2 main uses for PBKDFs: 1 is to generate key material, the other is to generate a digest to compare for access control. In the 2nd case, I do not really see a huge flaw disadvantage compared against PBKDF2, it actually looks like an improved version of PBKDF1. However, bad salt generation could be exploited... I dont trust that extra hash XOR at all. $\endgroup$ – Richie Frame Jan 19 '16 at 10:26
  • $\begingroup$ @Richie Thinking about it, hiding the IV inside an XOR of the last version of Hash(PassHash) would be better that the method stated. With regards to salt generation, I don't specify how salts are generated, they'd simply be generated using normal CSPRNG techniques. That is in the question we assume I gather entropy and apply a good DRBG for the salt. In a weird way though, you're giving my loose thinking a back-handed compliment. I'd rather hear an explanation of why it's weak but exploits have to be discovered, sometimes with great effort, I appreciate that $\endgroup$ – Iam Nick Jan 19 '16 at 12:24
1
$\begingroup$

Encrypting the salt is actually equivalent to just using the cipher as an initial step. That is, you could redefine the scheme as follows:

tmp := D(hash(password), salt)
password_hash = F(password, tmp)
output := salt, password_hash

Where D is the decryption function and F is the actual iterated password hash you defined.

The addition of the cipher is not significant from the point of view of slowing down dictionary attacks if it's a typical fast cipher like AES. It can only make a difference if the underlying hash function (which you call Hash) is completely broken to a degree e.g. MD5 is nowhere near being.

Note that the intermediate value, which I called tmp above and you called salt must be kept secret. Knowing it an attacker would be able to avoid the whole looping part and just test the encryption/decryption output. For that reason calling it a salt is a bit misleading.


The actual iteration function is very close to PBKDF1, as Richie Frame observed in the comments. It adds the salt at each iteration, but I do not see why that should be significantly stronger. It does not seem to offer any advantage over PBKDF2, but like PBKDF1 it is likely not significantly weaker either – with an iteration count that gives equal running time. (Any advantages PBKDF2 has are likely theoretical, but using HMAC may be a slightly better security margin. Or at least a security blanket...)

Compared to bcrypt it shares most of the advantages and disadvantages of PBKDF2. See e.g. Thomas Pornin's post on Security.SE for a treatment. The main difference being, of course, that yours is non-standard and could have undiscovered weaknesses. TL;DR is that bcrypt is superior due to having some GPU resistance, but does have some limitations like on password and output lengths.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.