Multiple users getting access to same (secret) encryption key on a single computer? I am developing an application for Desktop PCs (Mac primarily, Windows later) that uses an encrypted SQLite database. I want to give multiple authenticated users access to this &quot;main&quot; database. I like to make this as secure as possible.
My constraints are:

Everything happens on a single computer. No server involved (I plan to change that, as well as introduce the use of SmartCards, but that's quite the challenge on OS X).
I roll my own user authentication (I don't want to use something complex like Kerberos or whatever else is out there as I don't have the time to dig into and manage that all as well. I'm a single fighter and need this all as simple as possible).
I understand the risk that a hacker will be able to infiltrate the system and then grab the encryption key as soon as a user logs in. I also understand the risk that a running computer may still have the encryption key lingering in memory, so a system memory dump may be a viable attack. I have to live with that for now.
My main goal is to protect the database against someone simply breaking in and stealing the computer, or copying files off it, then trying to gain access to the database.

Currently, I envision this to work as follows:

The DB encryption key is stored with another (&quot;secondary&quot;) password using symmetric encryption (not sure what to use here, I've used Blowfish before, is that good?). That lets me change the DB encryption key centrally if needed.

That secondary password is stored in a separate &quot;users&quot; database, protected by the user's password, e.g. using a cypher or whatever is appropriate (I need help here).
So, when a user logs in, I simply look up the value from the users database, decrypt it using the entered password, and then use that to decrypt the DB key, and use that DB key to open the main SQLite database. If that opens the database, the user's entered password was valid.


Is that reasonable and sound, or am I missing something? Can it be improved to make it more secure or is that the best I can do under the mentioned constraints?
It is a no-no to use SHA-512 alone as entropy-stretching key derivation function protecting a password: that would leave dangerously vulnerable to brute force password search, even if salt is mixed. Other than that, the principle outlined in the question is sound, though slightly more complex than needed; also, I'd replace PBKDF2 by a better substitute like bcrypt, scrypt, or Argon2.

Sharing the main database key among many users each having a login/password can be achieved with a single level of a PDKDF2 (or better) rather than two, and nothing more complex than comparison and XOR (the later being used as the currently unspecified encryption method for the main database key).

Recall that an entropy-stretching key derivation function like PBKDF2 produces a bytestring of desired size, from


key (the password)
salt (typically at least concatenation of an application-specific constant and user id)
desired output size (not available for stock bcrypt, see note)
difficulty parameter(s), including at least an iteration count (set as high as tolerable), and for modern entropy-stretching key derivation functions (scrypt and later) maximum CPU count, and size of memory to use.


We can make the output size parameter say 48 bytes: 16 bytes for password verification purpose, and 32 bytes for the main database key. What's stored in the password database for each user includes its user id (the search entry, as plaintext), and the 48-byte output of the password entropy stretching key derivation function, with the 32-byte portion combined using XOR with the 32-byte database key. The user's record can additionally contain security parameters currently used for the entry, extra random salt, and other details like when the password was last changed.

On login we fetch the (alleged) user's record from the login/password database, compute the entropy-stretching key derivation function with the given password, and combine the result with the above 48-byte user record using XOR. We allow login only if the 16-byte subfield is all-zero, and then only use the rest as the database key, without need for further verification.

Finding the database key is as hard as finding any user's password (the stated security goal). Changing a user's password only involves changing the corresponding entry in the login/password database.

This leaves unspecified the cryptography used to protect the database by way of its key; that one is a complex issue.

Note per comment: bcrypt has fixed output size 24 bytes. It would be tolerable to halve the fields used for password check and data base key; or we could change bcrypt's OrpheanBeholderScryDoubt string constant to something twice as long, taking care that no 8 byte segment repeats (but then that's no longer bcrypt).