2

Using a one- way function (e.g. BCrypt) for password handling in password based login is a common approach.

When an application uses a key derived from user’s password for encrypting a private key, is it secure to rely on successful decryption on login?

Example:

  • Registration (all steps performed client- side):

    1. Derive a key (A) from user’s password (e.g. using PBKDF2 with 100k iterations).
    2. Use key A to encrypt user’s private key (using authenticated encryption; e.g. AES in GCM mode).
    3. Store required information in user’s database record (e.g. ciphertext, salt, …).
  • Login (all steps performed on client- side):

    1. Load user's database record by username.
    2. Derive key (B) from user’s password (using same method used on registration).
    3. Try to decrypt users private key using key B.
  • A and B are actually the same thing, right? you derived them using the same method from the same password. – NH. Jan 12 '18 at 22:12
  • One of the biggest weaknesses would be brute forcing of passwords, which if successful would give you the user's private key – jrtapsell Jan 12 '18 at 22:20
  • @NH In case the valid/correct password was entered: yes. – Ratlos Jan 12 '18 at 22:22
4

Yes, this is a workable approach, when you use authenticated encryption, as you've indicated. The authentication tag on the encrypted data is analogous to a stored password hash, and GCM is specifically designed to prevent message forgery (i.e., a valid tag constructed without access to the private key).

In fact, GMAC is a variant of GCM mode that is designed not to encrypt data, but just to provide a signature with a shared key over some data.

It's important to note that this should not be done with non-authenticated ciphers, as even with padding being used to detect "correct" decryption, this would lead to a (slightly better than) 1/256 chance of any password working correctly by having correct padding despite being the incorrect key.

All this being said, I don't think this is a good idea, because it's much easier to have implementation errors in this than it is in a standard password storage scheme. Attacking this scheme is equally easy/difficult to attacking a separate PBKDF2 hash for the user password, which is a well studied authentication mechanism. If you're worried about CPU time with computing two PBKDF2 hashes, you can do the following:

  1. Compute key = PBKDF2(Password, Salt, N) to derive the symmetric key.
  2. Compute pwhash = PBKDF2(Password, Salt, N+1) to derive the stored password hash. (This can be done with only a single extra round on the original hash above.)

Inverting PBKDF2(Password, Salt, N+1) into PBKDF2(Password, Salt, N) is equivalent to inverting HMAC on whatever hash function you use.

The scheme above is the scheme used by Lastpass for authentication vs decrypting your password vault. (Only pwhash is sent to their server so they cannot recover the key for the password vault from that.)

  • 1
    In this case, I would also recommend knocking a few bytes off the output; for instance, only use the first 48 of the native 64 bytes of PBKDF2-HMAC-SHA-512, so that output of PBKDF2(x,y,N) is by definition insufficient for use in calculating PBKDF2(x,y,N+1). Personally, I'd say run two different salts instead, but as you said, if the CPU time was a very serious concern... – Anti-weakpasswords Jan 15 '18 at 2:49

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.