1

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?

Iam Nick
  • 550
  • 2
  • 12

1 Answers1

1

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.

otus
  • 32,462
  • 5
  • 75
  • 167