I have built a messages system for my website. Users can send the admin messages which are stored in the DB after being AES-encrypted.

I think that using asymmetric crypto (RSA through openssl) would be more secure: no decryption key to hardcode in php source. In fact, only the admin would have the private key.

The problems start when I create the sent folder feature in PHP. How can users decrypt their own sent messages, if they don't have the private admin key?

EDIT! Please, tell me if this approach is valid and more secure than hardcoding symmetric keys in PHP:

1) script generates user key pair from his password (manually entered)

2) openssl_seal encrypts the message using public keys (admin standard-generated pub key and user password-derived pub key).

3) script stores the results in the DB.

4) when user requests the content, script re-derives user keypair and decrypts.

5) when admin request the content script uses standard generated admin key and decrypts.

4 Answers 4



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.


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).


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.

  • Great and detailed. Just a problem. I haven't found an already made piece of software that generates keypair from passphrase. I suppose it isn't easy and so I'm going to derive a key from password and then decrypt keypair using resulting key. But where should I save encrypted keypair? Commented Aug 16, 2012 at 7:52
  • I find that ssh-keygen works pretty good -- setting up ssh private keys -- for generating keypair and saving the encrypted keypair in a standard place.
    – David Cary
    Commented Sep 23, 2014 at 2:43

If you encrypt the message using a symmetric algorithm (AES), then you store this key twice - once encrypted with the admins public key, and the other with the users public key.

This way when the admin wants to view the message, he decrypts the first key, and the user uses the second.

  • 3
    In a web application there is one problem with this: Where would you store the user's private key? Commented Aug 15, 2012 at 12:11
  • That's a good point. You could have the users private key stored encrypted with a password, which they have to enter each time they wish to decrypt something
    – fin1te
    Commented Aug 15, 2012 at 12:14
  • fin1te & @CodesInChaos Thanks, updated question! Please, check it out :) Commented Aug 15, 2012 at 13:26
  • Is "keyslots" a widespread or agreed-upon term for this? At least dm-crypt uses it... Commented Aug 16, 2012 at 0:09

I think a better question is: "What problem are you trying to solve using this encryption?"

In practice, public-key cryptography is used over insecure channels to ensure both data-integrity and non-repudiation (the message is intact, unchanged, and came from who it is claimed to have come from). Conceivably the only reason I can think of that you'd be encrypting information before it goes into the database is because the database itself is the insecure medium - for which I'd say secure the medium before you secure the data.

Though if you absolutely intend to secure this information using public-key, then I'd take an approach similar to what @fin1te came up with. Encrypt the message in two places, once (in the Admin's inbox) using the admin's public key, such that only the admin can read it; and a second time (in the user's Sent box) symmetrically using the User's password as the AES key (or allowing the user to choose a separate encryption password). That way the user still has access while ensuring only the Admin has access to those sent to him.

The only caveat I'd be aware of is that if the user changes the password, you'll have to walk through all the sent messages and re-encrypt them using the new password.

EDIT : I don't see any mathematical flaw in your proposed algorithm above that hasn't already been spoken to in the referenced question, one thing to note though, that PHP's OpenSSL_Seal generates a random symmetric key and encrypts that using the public key pairs provided. You'll have to store that key in the database as well to be able to reverse the process.

Your reverse process would look like:

  1. User provides expanded password as seed to PRNG
  2. Use PRNG to "seed" key generation scheme to recover private keys
  3. Decrypt stored symmetric key using derived private key
  4. Decrypt messages using decrypted asymmetric key.

All in all that seems like quite a lot of work and computationally expensive if you're doing this upon every page refresh, just to read some sent messages.

Since openssl_seal uses symmetric keys anyway, why not just short-circuit that and use the user's password?

  • Thanks, updated question! Please, check it out :) P.S. = I don't envisage password changing. Commented Aug 15, 2012 at 13:26
  • Thanks again, about your last suggestion: I store in the db only the hash of the password. So how can the admin read user's message? If I use gpg instead of openssl_seal (you have correctly pointed out that it uses symmetric crypto, after all), will the things change? Commented Aug 15, 2012 at 13:56

I'm assuming you are doing as @Sean Madden describes in the steps above - that there are two copies of the data stored - 1 copy encrypted with the Admin's private key, and 1 copy encrypted with the user's private key generated from his encryption password.

Yes - that should work.

In terms of comparison - the tradeoffs would be :

  • you don't store the critical secret (the private key) on the OS this way. If the hacking of persistent memory is your big concern - then this fixes it.

  • with the asymmetric encryption, you are likely adding a time factor to decryption - both for the admin and the user. Asymmetric encryption/decryption is a higher CPU cost than symmetric and it can have a lot do with how well your engine is implemented. Expect some growing pains here - where and how you perform the calculation will have a great impact on user satisfaction.

  • either way- without spiffy hardware, your private keys will be handled by the OS during the encryption process. It becomes harder to hack when they aren't stored in a file somewhere in the OS, but nothing is impossible - this is heavily dependent on the nature of the threat you are trying to protect against.

  • How confident are you that the users can remember their passwords in a security compliant way? If they are taping passwords to their screens, you have a whole other kind of risk. With the system you describe, a user loose access to all the sent mail in his folder if he forgets his password. If you offer him a password recovery mechanism - then you have to protect it more heavily than you protected the original symmetric keys. Any time you aggregate security secrets in one place, you create a more high value target for attackers and must protect it accordingly.

  • Great answer. Just a note: if user tapes password to their screen, it's their problem and their responsibility. Is it right? Secondly, if they loses their password, I can regenerate crypted records with new generated password. Is it right, again? Commented Aug 15, 2012 at 13:52
  • Password taped to screen - is usually the user's responsibility, but from common practice, it's also the company's responsibility to train the user not to do this. In the end, regardless of who's fault it is, everyone looses when users weaken the security of the system. Lost password - yes, if you have an admin encrypted copy, the admin would decrypt his copy and provide the data to the user to re-encrypt with his new private key generated from his new password. How that happens will be its own design, since you need to figure out who shares what - the data or the key. Commented Dec 27, 2012 at 17:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .