2

Scenario:

User A, B, C need to access an encrypted data from a web application. They all access the same data.

The encryption key must be tied to their login so that it's not stored in the server.

Question: Is it possible to tie the key to their login details even if they all have different username/passwords? What's the best approach in this scenario?

  • Why does the data need to be encrypted- what threat or compliance issue is at stake? What problem does storing an encryption key on the server create? – Jonah Benton Sep 7 '16 at 3:43
  • @JonahB API Keys and Personally Identifiable Information. Storing the key in the server defeats the purpose of encryption. – IMB Sep 7 '16 at 8:59
  • I see- so API keys generally do not have to be stored in encrypted form. They are non long lived credentials, that you issue, and you expire. Users do not reuse them. Compromise of an api key just results in revocation. What you can do is store hashes of them, but this does not require encryption. – Jonah Benton Sep 7 '16 at 9:45
  • PII encryption is a tricky thing on a field by field basis. A strategy to consider is segregation- store PII field values in a separate database or schema, and use database level or filesystem encryption on that PII database. This key is stored with the same level of care as database credentials or other secrets. – Jonah Benton Sep 7 '16 at 9:52
  • To more securely store an encryption key in proximity to the data, consider a passphrase model. That is, encrypt the key with a passphrase and store that on disk. Then at application startup, arrange to type in the passphrase to unlock access to the key. Difficult workflow, but not uncommon. – Jonah Benton Sep 7 '16 at 9:57
4

In general, solutions that do this work something like the following. You should find a trusted system that already does this and use it, rather than trying to build one yourself.

  1. First, generate a symmetric key. This is the Master Key and no user will ever see it directly. Do not store this key (in plain text) anywhere an attacker could potentially reach it.
  2. Use the Master Key to encrypt the data, and ideally also HMAC it for integrity (or use some other way of ensuring integrity, such as using AES in GCM mode).
  3. Run the user's password through a Key Derivation Function (like PBKDF2 or scrypt) using different parameters (such as a different salt) than is used for the password verifier. Do not store these Password-Derived Keys anywhere at all.
  4. Encrypt the Master Key once with each user's Password-Derived Key. Store these encrypted copies of the Master Key with each relevant user's account data.

To access the data:

  1. Authenticate the user. (This typically means retrieving the password verifier parameters for their account, running their password through the key derivation function that uses those parameters to produce a password verifier, and then checking whether that password verifier matches the one stored for that user.)
  2. Get the Password-Derived Key for the user. (Retrieve the second set of KDF parameters, and pass the password into your KDF using those parameters; we already know the password is correct so you can expect that the re-derived key is correct without checking it against anything.)
  3. Using the Password-Derived Key, decrypt the Master Key. Purge the Password-Derived Key from memory as soon as possible after doing this.
  4. Using the decrypted Master Key, verify the data's HMAC (or otherwise ensure its integrity) and then decrypt the data.
  5. Either purge the decrypted Master Key from memory and then access the data (in which case you'll need to repeat steps 2-4 if you want to modify the data and save the changes), or hold onto the decrypted Master Key in as secure of memory as you can arrange.
  6. Purge the decrypted Master Key, and the decrypted data, from memory as soon as possible.

To change a user's password:

  • If the user has their old password (password rotation), verify the old password and then use it to generate the user's current Password-Derived Key and with that, decrypt the Master Key. Using the new password, generate the user's new Password-Derived Key and re-encrypt the Master Key with it. Replace the old encrypted Master Key with the new one (in the user's account info).
  • If the user has forgotten their old password, have an administrator verify the user's identity through some other means, and have the user select a new password. Then have the administrator get the decrypted Master Key by entering their own password, deriving their own Password-Derived Key, and using it on their own copy of the encrypted Master Key. Using the user's new password, generate the user's new Password-Derived Key and use it to encrypt the Master Key. Place the encrypted-with-the-new-key Master Key in the user's account information, replacing the one that was encrypted using the key derived from the old (forgotten) password.

To manage users:

  • For new users, basically just follow the "forgotten password" flow above.
  • To delete a user, or even just revoke their access to the data, delete the copy of the Master Key encrypted using that user's Password-Derived Key. This makes it impossible for the user to use their own password to get the Master Key by any means.

Despite the detail (which is only present to help you understand the system), PLEASE do not attempt to implement this yourself. There are numerous additional critical details that are either missing or mentioned only in passing. For example, it is vital that the user never directly see the Master Key (otherwise they can store a copy of it, removing your ability to effectively revoke their access without regenerating the entire key structure and re-encrypting the data). Many of these details (such as secure key storage in memory) will be platform-dependent.

Additionally, there are many ways to screw up the crypto itself, even if using library implementations of the cryptographic primitives; if you generate your keys or key derivation parameters incorrectly, and choose the wrong primitives, or implement any of the steps in a way vulnerable to side-channel attacks, your whole scheme could be compromised. Don't try to figure this stuff out on your own; go with something that somebody knowledgeable about crypto implementation has already put together, and that somebody else knowledgeable has reviewed.

  • Thank you for your comprehensive answer and concerns about me implementing it but I am asking to this question exactly to learn how to implement it properly :) – IMB Sep 7 '16 at 9:06
  • @IMB: "How to implement it properly" is, if you are at the point of "how would you even do that", a question better answered by a semester-long applied cryptography course than by any StackExchange answer. You know how people keep finding weaknesses in SSL/TLS that require deprecating old cipher suites and protocols, and fixing implementation bugs galore? Those suites and protocols were designed and implemented by people with a solid education and years of experience with crypto. You will not do even so well as them. For the sake of your data, go with a well-reviewed solution. – CBHacking Sep 7 '16 at 12:24
  • Surely I will not roll out my own crypto library but looking at the overview I can't see why I am not suppose to do it myself? E.g., At least the first part is very doable using existing libraries. – IMB Sep 7 '16 at 12:29
  • @CBHacking - Great answer for it's readability and succinctness. What would you suggest as a method for encrypting the Master Key? In my use case we are using openSSL and a public/private keypair to encrypt/decrypt the actual data. We keep the public key on the server and I was searching for a way to protect the private key. Your solution provides a great mechanism for that. – pathfinder Sep 9 '16 at 17:14
0

So much will depend on the specifics of your application, but in broadest terms...

You could generate a public/private keypair for each user. Encrypt the data with a symmetric key, then encrypt that symmetric key with each of the users' public keys. Store those individually encrypted copies of the single symmetric key, and hand them back to the respective users when they log in, and the single copy of the (symmetrically) encrypted data.

The user uses their private key to decrypt their copy of the the symmetric key, then uses that to decrypt the data.

WARNING - I am hand-waving away all sorts of concerns here that may make this approach not viable for your application. Consult a local security professional before trying to ever "roll your own" crypto protocol. But that said, the above broad outlines should do what you are asking for.

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.