0

I am writing a collaborative password management system and have questions pertaining to the storage of encrypted passwords. Essentially, I would like several users to be able to access and change a database.

High level:

  • User runs the client which asks for username/password authentication (backended with AD/Samba/Radius/local).
  • Upon success, the user is required to enter a shared keyring password. This should be known to all users who have access.
  • The encrypted database is sent to the client which decrypts it and displays it to the authenticated user.

Slightly more detailed:

  • Upon database initialization, a random key is generated and encrytped with the human-readable keyring password. This encrypted key is stored on disk.
  • Each entry in the database that contains passwords is stored encrypted with the original key.
  • The keyring password is therefore required to decrypt the rest of the passwords.
  • The keyring password can also be updated without re-encrypting the entire database. All that happens is you decrypt the key with the previous password and re-encrypt the key with the new one.

Is this all for naught? Is this considered bad design? My goal is to prevent someone from simply downloading the database if given access to the server. I relayed this off of a friend of mine who half-jokingly said "Yes, because this prevents people from stealing Chrome's database." How seriously should I take that?

Any recommendations for proper design, algorithms to use, etc.?

  • "My goal is to prevent someone from simply downloading the database if given access to the server." What do you mean here, and how does what you've described help with this? (also: you should just assume from the outset that people WILL get the database, and that you need to have a strong enough scheme to hold up to this, since you are sending the whole database to the client anyway.) – Joe Mar 1 '17 at 22:07
  • Why is the "shared /collaborative" element that you describe relevant? It looks like you simply give out a password to several people. – Pascal Mar 1 '17 at 22:16
  • I personally would not take on such a project because my gut tells me it will be a headache and make you open to liabilities when any flaws in the design happen to be exploited. But if what you are really after is protecting database data from being stolen by anyone who gains physical access, virtually all the DB products offer encryption to make it a lot less feasible of cracking into a database. If all your critical apps use this functionality, maybe you don't need to brew this solution? But if you, I'd certainly use this DB encryption to store what your app is storing. – Thomas Carlisle Mar 2 '17 at 0:13
  • Worrying prospect really. I'm not saying this is recommended, but as a user, I'd feel more comfortable putting a Keepass (or similar) database on a fileshare and allowing only the set AD users/groups access to that share. The password is still shared, but you'd get a lot less blame when something goes wrong! – user2867314 Mar 3 '17 at 14:19
  • Actually looking at the high level description it sounds as though the client checks the user against AD? Could that definitely not be shortcutted in the binary to get straight to the next stage, then the server only requests the shared password which is used by the server to both used to obtain and decrypt the database? – user2867314 Mar 3 '17 at 14:23
2

Your solution would work for a very small team. Anyone who knows the keyring password will be able to see all of the secrets stored in the database. If you want to remove a user, you will need to change the password and redistribute it to the rest of the team.

Better approach for collaborative secrets database would be to use asymmetryc encryption. Consider this design:

  • Every user has its own private and public key registered in the database
  • Private key is stored enrypted with AES (or other symmetrical algo), with key derived from a user password
  • Public key is stored unencrypted
  • Each secret is encrypted with a key generated from a strong CPRNG
  • The key itself is encrypted with users public key
  • Sharing a secret is done by encrypting generated key with a public key of the user you want to share the secret with

This is roughly how other password managers (for example LastPass) share secrets.

  • I agree that this is definitely a more robust solution. However, the same issue seems to arise, just pushed back a step. IF a universal key (key that can decrypt any password entry) is held in memory, then we can assume that a skilled attacker could potentially extract it, no? A solution would be to encrypt the data itself with the public key, thus removing the need for the universal key, but this would require the data to be stored in plaintext on the server so that it can encrypt it with each user's key on the fly, which is the exact issue I want to avoid. – Goodies Mar 6 '17 at 18:14
  • 1
    You will not have one universal key. Each secret will have its own randomly generated key. This is big difference. You will store this key in memory for a very short period of time and then purge it. There is no one master key that will enable any user to get access to all of the secrets. If you use public key for encryption, you will have single secret multiple times with different ciphertexts. It would then be difficult to modify such secret. – Marko Vodopija Mar 6 '17 at 18:22
  • Okay, then I'm confused. Say I have a simple string database entry "Passw0rd!". I want it to be shared to both Alice and Bob. From my understanding, "Passw0rd!" is encrypted with Alice's public key and Bob's public key and sent to them respectively. However, in order for this to work, "Passw0rd!" must be stored in plaintext. If it is encrypted with a key, and the key is stored in the database, this doesn't solve anything. Could you shed some light more on what, exactly, your recommendation is in terms of storage? – Goodies Mar 6 '17 at 18:54
  • You will generate a key and encrypt "Passw0rd!" with that key. Then you will use Bob's pubic key to encrypt original key and send it to Bob. Will do the same with Alice but with her public key. You will also send them ciphertext containing encrypted "Passw0rd!". Will be the same for both of them. This way, if you change "Passw0rd!" to "Str0ngerPassw0rd!", you will need to send them new ciphertext but again it will be the same ciphertext for both of them since they will have the key to decrypt it. Each string in your database will have its own key. – Marko Vodopija Mar 6 '17 at 19:04
  • The approach I'm explaining works best with client/server design. You will have a secret server and client will be a browser connecting over HTTPS to the server. The server will be the one encrypting and decrypting secrets, and HTTPS will be used to protect plaintext of secrets in transit. You as an administrator of the server will not be able to access any secrets not directly shared with you (the keys were not encypted with your public key). The same will be for anyone who gets access to the database. – Marko Vodopija Mar 6 '17 at 19:15
0

Looking at your proposal, I would tend to think there isn't a massive advantage over having e.g. KeePass available to users, and a central location to store the various database files.

As mentioned by @MarkoVodopija, the biggest issue here is that removing access for a given user is non-trivial once you hand over the database in the first place. This would require both changing the password for the DB itself (and getting the new password to all legitimate users), as well as potentially, changing all passwords present in the database.

One document you might find useful is Hashicorp Vault's security overview (https://www.vaultproject.io/docs/internals/security.html) - it may help your effort to work out what your own threat model looks like, and see if, and where, your current solution falls short.

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.