I know that this is not the best use case for RSA, but for a customer of mine I have to encode user data on the server in a way so that it can be decoded/downloaded by the customer through a "secure" webpage.
Workflow
Users can register on the page and leave some sensitive data (no credit card data, but age, name, address and such) and this is then stored in a database. My customer then can access the page and download the data through a "safe" connection.
Hardware situation:
On the hardware side we are talking not about a dedicated server, but only a shared hosting account (shared server) but with full access (FTP, the works). So it is out of the question to distribute the keys on different servers to not have to store them together.
Current Implementation
Right now I am using a public key to encode the data (one big chunk instead of each field by itself) and write it to the DB.
I am using Drupal as a backend to facilitate the secure access to the page (SSL) for my customer (the users don't have to login). In addition to the Drupal password I gave my customer the passphrase for the private key, which (I know not good) is stored alongside the public key. The passphrase the customer sends (after logging in to Drupal) is not stored on site, but directly used to decrypt the private key, which in turn is used to decrypt the data stored in the DB. The result is then sent back as a CSV file to my customer's computer.
What can't be done
I told my customer that this situation is not optimal, that the best thing would be to decode only on the client side via an extra software and download only the encoded data to keep the private key out of harm's way, or to get more servers and change the setup, but this is not possible.
Questions
I know an exact assessment is not possible, but I was wondering how critical the fact that I have hundreds or thousands of datasets encoded with the same public key would heighten the risk of anybody getting to the data via access to the DB, or by reading the keys somehow (the encrypted one of course).
I know the Achilles' heel here is the private key that is stored on the server, so how easy is the private key passphrase to hack?
Solution
Heeding Ilmari's advice I modified my setup and ended up with the following:
Collecting the data:
- PHP Script PROCESSFORM receives data from an HTML form (SSL) and validates/purges it
- PROCESSFORM adds a delimiter character before and after each entry and pads the spaces between the entries with random characters so that the DATASET string has always the same size
- the DATASET is encoded using a public key and stored in the DB together with a cleartext unique ID and DATEADDED (DB table has three fields, ID, DATEADDED, ENCODEDDATA)
Retrieving the data:
- The user logs into a backend with username/password (SSL)
- The user then has to enter a passphrase which is sent via a form
- PHP Script DECODER receives the passphrase and
- Uses a PBKDF2 implementation to "harden" the key
- Uses the "hardened" key to decrypt the private key which is also stored on the server to decode the data from the DB
- Removes the padding from the decoded string
- Creates a CSV with the resulting data and serves it to the user
NOTE:
Although the fact that the private key is stored alongside the public key on the server is not ideal, it was not possible to sway the client to decode the data on his own computer, it had to be via a web interface.
There is a little separation due to the fact that the program part that does the encoding is in a different folder than the one that does the decoding, and that it only has access to the public key, but if the server is hacked, an attacker will have access to both keys and might use a brute force attack to decrypt the private key.
But as I used PBKDF2 to "harden" the key and therefore significantly increased the time necessary to try a key, it is most definitely not worth the final result (only semi-sensitive address data, no credit cards or anything).
The most likely point of attack would now be the hijacking of the form script after hacking the server to then grab the passphrase before it reaches the DECODER script.