OpenPGP
The standard way of handling this is to store the encrypted messages in standard OpenPGP format.
Is there any reason not to use some off-the-shelf library that implements RFC 4880 and RFC 3156 ?
(There's lots of practical discussion of OpenPGP on this IT Security site and more theoretical discussion of OpenPGP on the Cryptography StackExchange site).
The OpenPGP-format encrypted message can be stored as a file, a SQL BLOB, etc.
details
OpenPGP works exactly as fin1te explained
(as far as I can tell, openssl_seal() also works exactly the same way):
- For each message, the system generates a fresh, new, random session key that nobody else could possibly guess. After storing the complete encrypted message BLOB, the system immediately forgets that key.
- The plaintext of the message is encrypted with that session key and stored in the symmetrically encrypted data packet inside the BLOB.
- Several encrypted session key packets are stored inside the BLOB -- each one containing yet another identical copy of the session key for this message, each one encrypted with a different public key. In this case, one copy is encrypted with the sender's public key, and another copy is encrypted with the admin's public key.
When anyone (the user or the sysadmin) wants to read an encrypted message,
that person gives the encrypted message and her passphrase to a piece of software that decrypts it and shows her the plaintext.
That software typically:
- Feeds the passphrase into a key derivation function. The software uses the resulting key to decrypt a keyring file to obtain that user's private key and its corresponding public key. (Alternatively, I suppose one could use a key derivation function to directly generate a private key from a passphrase, then generate the public key from that private key).
- searches all the encrypted session key packets inside the BLOB until it finds one with a matching public key.
- Uses the private key to decrypt the session key. Then uses the session key to decrypt the plaintext message.
As long as you avoid sending the password over HTTP or other plaintext protocols,
this seems secure against passive attacks (watching what goes over the wire; reading backup tapes of the server, including all the public keys and the admin's encrypted keyring).
EDIT:
where should I save encrypted keypair?
That's an excellent question, worthy of an entirely fresh question/answer page.
In an ideal world, you would give each user a security token that, when first turned on, generated a fresh new keypair and gave you the public key, but the private key would never ever leave the token.
In our less-than-ideal world, many people use Gnome Keyring or some similar software to store the encrypted keypair on their personal laptop or smartphone, as discussed at
"standard formats of private key storage?".
I suspect you would prefer a system where you don't have to buy a bunch of security tokens, and where your users could still access their own files on your server even if their smartphone was accidentally lost or bricked or destroyed in some other way.
That pretty much forces you to store an encrypted keyring on the server --
"Is this design of client side encryption secure?"
discusses some of the implications.