8

I have searched IT Security and Google for something similar to this, but wasn't able to find anything remotely related to what I'm doing.

I'm developing software which has 2 parts - a C# program run on a single, secure, trusted computer, and PHP software running on a server. This system deals in sensitive data, namely pharmacy records (not in the US, HIPPAA doesn't apply).

I want to securely encrypt the data, so that even in the case that the database is stolen, as little of the data can be decrypted as possible. I'm already protecting the data by not storing any identifiable data like Name, Address etc, save for an email address.

I initially wanted to use a variant on this solution, however on further contemplation I realised that RSA was not an appropriate way to encrypt plaintext directly. My research led me to believe that AES is the most appropriate algorithm for that. I know that the advice given to most people who are not experts on encryption is to follow an industry-standard protocol, however I was not able to find one which matched my criteria.

The criteria are:

  • For each user's data, only the user himself should be mathematically able to access his data given the contents of the server - meaning a key derived from his password is used (the C# software has full access to all users' data, it can have access to the keys)
  • Decryption should not be possible having obtained solely the contents of the server
  • Plaintext data should never be stored on the server (therefore I want to encrypt in the C# software)
  • Data needs to be able to be encrypted without having the user available to provide his password
  • Data will only be decrypted and read in PHP - no new data or modified data will need to be re-encrypted and written
  • Only a hash of the user's password can be stored or accessed

Here is a solution I have come up with:

Naturally, all connections are made through TLS/SSL (over HTTPS). Before any sensitive data is transferred, the server and software are "primed" or paired. An asymmetric key pair is generated on the server, and the private key transferred to the software (I refer to the C# component as "the software"). The private key is deleted from the server, and the public key stored.

When a user registers, their password is used to generate a 128-bit key using PBKDF2. This key is RSA-encrypted using the previously generated public key and stored.

When data is uploaded from the software onto the server (every 24h), the software sends a list of user ids it will be uploading data for (over HTTPS of course). The server sends back a list of the RSA-encrypted 128-bit keys along with the corresponding user ids. The software decrypts them one-by-one using its private key, obtaining a list of 128-bit keys. For each user, the server takes that user's data and encrypts it with AES-128 using that user's corresponding key. The whole payload is uploaded to the server and directly stored.

When a user logs in, their password is accessible for a short time, and PBKDF2 is used to generate their AES-128 key. To prevent them from having to re-enter their password on each page load, the AES-128 key is stored in a secure cookie on their machine with a short (5-10min) expiry time and used on subsequent page loads to decrypt and display that user's data. It's not actually stored on the server at any point.

Is this security protocol appropriate? Should I modify it? Is there anything which is industry-standard and would work here? Any help would be greatly appreciated.

Matt Jadczak
  • 83
  • 1
  • 4
  • Does "register" and "login" mean that the user interacts with the server (PHP)? Does "Data will only be decrypted and read in PHP" mean that the data will have to be decrypted on the server? – twobeers Feb 28 '13 at 08:51
  • Yes, the software sends users a custom registration link where they create a username and password which they can use to access their data. – Matt Jadczak Feb 28 '13 at 09:58

1 Answers1

5

Rolling out your own protocol is hard. You will easily have something which more or less runs, but getting something which is also secure will require a lot of work and a significant amount of luck as well.

From your requirements, you would like a protocol which looks like this:

  • Each user has an asymmetric key pair, suitable for encryption (say, RSA or ElGamal).
  • The private key Kpriv is encrypted with a symmetric key K derived from the user password, and then stored on the server.
  • The public key Kpub is stored on the server with no encryption (it is public).
  • Data elements are encrypted with Kpub. Anybody can encrypt anything with a public key (that's the point of the public key being public).
  • To decrypt the data, the user types his password, which is used to recompute K, then decrypt the blob which contains Kpriv. With that asymmetric private key, the user can decrypt all the data files which have been encrypted with the corresponding public key.

The OpenPGP format contains all the needed primitives for that. BouncyCastle is an opensource library which can use that format, and it as a C#/.NET version.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • That's exactly what I initially wanted to use. However I read that asymmetric encryption is mostly used to encrypt symmetric encryption keys, and isn't good for encrypting plaintext by itself? Can I use a block cipher with asymmetric encryption? – Matt Jadczak Feb 28 '13 at 19:33
  • 1
    Asymmetric encryption is good only for messages of very limited size (117 bytes at most with a 1024-bit RSA key). It is customary to use "hybrid encryption" in which you generate a random _symmetric key_, encrypt the data with a block cipher and the symmetric key, and encrypt the symmetric key with the RSA public key. OpenPGP includes formats and procedures for that, and you do not have to worry about it (which is good because it is rather easy to get it wrong when assembling algorithms together). From your point of view, you "encrypt the message with the RSA public key" and that's it. – Thomas Pornin Feb 28 '13 at 19:37
  • Ah, thank you. I didn't realise OpenPGP would do that for me - hence me trying to encrypt my symmetric key asymmetrically. – Matt Jadczak Feb 28 '13 at 20:05
  • Is there any simple-standard way to store and use OpenPGP keys without having to use the "keyrings"? Ie just store the AES encrypted OpenPGP key and use it at will? I'm using PHP for this. – Matt Jadczak Feb 28 '13 at 21:39
  • KeyCzar is another excellent choice for a library that implements these scenarios and tries to prevent you from messing up. – MichaelGG Mar 02 '14 at 22:12