From this earlier question, I have a general need to obfuscate a set of third-party credentials stored in a user account, which are then used in an internal Winforms software client. The scheme from the accepted answer is below:
Password Creation and Encryption:
- User, having already authenticated with the internal system, chooses a new password P for that system, and/or changes sensitive data D.
- Client software hashes P with SHA-512 producing C.
- Client splits C in half resulting in C1 and C2.
- Client uses C1 and a randomly-generated IV as the key to encrypt D with AES-256, producing S (which includes the IV).
- Client transmits U, C2 and S to server.
- Server BCrypts C2 to produce H (which includes a random salt).
- Server stores U, H and S in the server.
Normal Login:
- User enters login credentials (Username U and password P).
- P is hashed with SHA-512 to produce C/*C1*/C2.
- U and C2 are transmitted to the server.
- Server hashes C2 with BCrypt to produce H.
- Server retrieves user record with username U and verifies H against stored value.
- Server transmits encrypted user data S.
- Client uses C1 to decrypt S, producing D.
This functions beautifully, except for one issue: because it's essentially a PBKDF, if you lose the password, you lose the data. At first that was acceptable, as the data could be reconstructed; however, end user complaints about having to reconstruct their user account after an admin password reset (which essentially nulls out the encrypted data) have made it less so.
I therefore need to implement something on top of the existing scheme that allows administrative data recovery and/or password reset. I have come up with the following; please comment:
Password Retrieval/Admin Reset:
- When changing a user password, client software additionally retrieves a common 2048-bit RSA public key K1 from the server.
- Client uses K1 (and a proper padding scheme) to encrypt C1, producing E.
- Client transmits E along with other user data, which is stored in the DB by the server
- When password recovery is desired, an admin authenticates with the server and requests S and E for the user, along with K1.
- Admin also obtains the private key K2 from offline, physically-secured storage.
- Admin uses K2 to decrypt E, producing C1.
- Admin uses C1 to decrypt S producing D.
- Admin chooses a new password for the user, and obtains a new C/*C1*/C2, then produces S and E, all the same way the client would normally.
- Admin transmits U, C2, S and E to the server, which BCrypts C2 into a new H and persists U, H, S and E.
- Admin transfers the new password to the user offline or otherwise secure from observation, and returns their source for K2 to its secure physical storage.
Advantages:
- Obviously, it solves the problem; lost or forgotten passwords can be reset by the admin.
- Data is still secure; no information is transmitted across a wire or stored in the DB or program code that could be used in that form to obtain sensitive data; not knowing the password, an attacker must either crack AES-256 encryption or crack RSA-2048 with OAEP in order to obtain the third-party credentials.
- While passwords are resettable, they are never recoverable; the admin never sees or knows the plaintext password the user had originally chosen. That password is the user's, and theirs alone (the password created by the admin can be treated as "temporary" and so required to be changed after one use).
- If the admin, for any reason, doesn't have access to the specific private key of the pair that was used to encrypt the user's password-based symmetric key C1, they can still fall back to the "blow it away and recreate it" method of restoring the user account.
Disadvantages:
- An additional piece of information must remain secure; the private key K2. This is not a human-consumable piece of information, and so must be stored in digital form; therefore that key storage must be physically isolated and secured, similar to (but probably not as well as) the private key for CA certificate generation.
The question is, is there anything I'm missing that would make this added piece of the scheme unsuitable or unworkable?
