5

Though pretty interested, I'm everything but an expert in Information Security, please redirect me to any helpful resources if my question is stupid or correct me if my assumptions are wrong.
When reading through the Keepass Security page it seemed to me that the workflow of generating the password that's actually used to encrypt the kdbx file from the user-entered password (assuming no keyfiles or Windows user account is used) is as follows:

  1. Take user-entered password and hash it (SHA-256)
  2. Generate random password/retreive it from kdbx file
  3. Encrypt the hash from 1 N times using the key from 2
  4. Hash the output of 3 using SHA-256 again

Then, the output of 4 is the key to be actually used to encrypt the database.
What I'm wondering about is: Why the hassle with the key stored in plain and encryption? Why not just omit steps 2 and 3 and hash the user-entered password N (or maybe C*N, with C being the time relation between AES-encrypting and SHA-256-hashing) times? I'm pretty sure I'm overlooking something important here and I'd be grateful if you could enlighten me.

TheWolf
  • 1,069
  • 7
  • 12
  • 1
    From the Security page that you linked to, it sounds like it is all about increasing the time needed to try one key. Also, if the `N` and `C` is known, then I would guess that one could just precompile a list of list of keys. So if you want to attack several databases at the same time, you would only have to perform the hashing ones. In that sense the encryption with a random AES key works like a salt. But maybe someone with greater wisdom can say more. – Thomas Apr 20 '14 at 02:12
  • Yes, it's definitely about increasing the time of trying one key. However, this could also be reached by just hashing lots of times (as for example bcrypt does it). The argument about the rainbow tables is valid though, I didn't think of that. The AES encryption indeed seems to work as a salt here (but could then be replaced by a salt, too). – TheWolf Apr 20 '14 at 10:40

2 Answers2

4

[Disclosure: I work for AgileBits, the makers of 1Password]

I may have my history wrong here, but I believe that KeePass is designed to work with PasswordSafe databases, and that PasswordSafe was designed prior to general adoption of PBKDF2. So what we are seeing here is a "home grown" approach to do the job that PBKDF2 was designed to do. (And of course PBKDF2 isn't ideal, which is why the world is seeking a successor).

The choice of AES (in KeePass) over HMAC (as is typically used in PBKDF2) for as the PRF for each round isn't really a big difference, as both are PRFs. Indeed, PBKDF2 could be used in such a mode (though I've only ever seen it used with HMAC).

It is interesting to note that both schemes suffer from the issue of using a constant key/salt for the PRF. This is now recognized as a (small) problem (among larger one) with PBKDF2.

So off of the top of my head and based solely on your description above, I don't see that scheme as being any worse (though also little better) than PBKDF2. It isn't as general as PBKDF2 in terms of flexibility in the size of derived keys, but that is probably a good thing. Other than that, it appears (again, just from a casual glance) to be very like PBKDF2-HMAC in its strengths and weaknesses.

Over the years, I've gone from describing PBKDF2 as "Peanut Butter Keeps Dogs Friendly, too" to "People's Babies Keep Dingos Feed, too". Despite this, we still use it (carefully) in 1Password, but we are eagerly awaiting a successor to PBKDF2, scrypt, and bcrypt.

Bob Ortiz
  • 6,234
  • 8
  • 43
  • 90
Jeffrey Goldberg
  • 5,839
  • 13
  • 18
  • FWIW, the KeePass maintainer has expressed interest in moving to argon2 when it is more mature. – Ben Jun 24 '16 at 14:50
3

What KeePass does appears to be a custom password hashing, using AES encryption as part of the process. The AES key here plays the role of a salt. The salt is a non-secret parameter which selects the actual function used to process the input password (i.e. there is not one hash function, but a whole family, and the salt tells you which one is to be used). Salts thwart precomputed tables and, more generally, prevent cost sharing between attack instances: an attacker cannot reuse the work spent on cracking one hashed password to another hashed password, because the other hashed password uses a different salt.

More theory an practice about password hashing functions is available there.

The KeePass function appears to be some custom design, which is (generally speaking) a bad thing. Furthermore, it is based on AES, so an attacker can speed up the attack by using a PC which includes the AES-NI opcodes, i.e. a basic PC.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • So am I right in assuming that the encryption part could as well be substituted by `C*N` `SHA256(salt + password)` invocations? – TheWolf Apr 20 '14 at 15:08
  • Clarification: I mean `password = SHA256(salt + password)` and this is of course somewhat simplistic. – TheWolf Apr 20 '14 at 15:19
  • 1
    I'm not sure of the history, but the "home grown" aspect of it may be because the predecessor of KeePass may have predated PBKDF2. @TheWolf is wrong to say that AES each round could be substituted by `k_{i+1} = SHA256(salt + k_i)`. SHA-2 is *not* a pseudo-random function (PRF). So use HMAC in here if you don't want to use AES. – Jeffrey Goldberg Apr 20 '14 at 18:13
  • Could you elaborate on your last point? Why is it important for the key stretching function (is that denomination even correct?) to be a PRF? – TheWolf Apr 20 '14 at 23:05