# How vulnerable is RSA when using it to encode ~1000s of datasets with 500bytes each? How easy can the private key passphrase be hacked?

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 DB. 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 privatekey, 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 customers 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 harms way, or to get more servers and change the setup, but this is not possible.

Questions

1. I know an exact assesment is not possible, but I was wondering how critical the fact that I have hundreds or thousands of datasets encoded with the same publick key would heighten the risk of anybody getting to the data via access to the DB, or by reading the keys somehow (the encypted one of course).

2. 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 Ilmaris 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 padds 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 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
• Usese 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 definately 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.

-

First of all, I see nothing intrinsically wrong with your setup. Done correctly, it could be as secure as only decoding the data on the client's system. That said, it does introduce some potential vulnerabilities that you should be aware of.

First, if your server is compromised by an attacker, they could (in addition to everything they could do anyway, such as copying new data before it's encrypted or adding bogus data to the database) capture the client's password when he logs in, allowing them access to the private key and thereby to all the data. Thus, this is an extra incentive to make your server as secure as possible.

Second, even if the client's password is not directly compromised, an attacker who manages to obtain the encrypted private key from your server could launch a brute force attack to guess the password. The main defense against this (besides securing your server, as noted above) is twofold:

1. Have your client choose a strong password, e.g. using diceware. As a quick illustration, you could try showing them this comic (but don't forget to also show them this one).

2. Derive the actual key-encryption key from the password using a KDF that features key stretching. PBKDF2 and scrypt are good choices. Make sure to use as high an iteration count as possible (and design your system so that it can be increased as hardware gets faster).

Finally, let me note that you haven't specified how you're encrypting the data in the database with RSA, so I can't rule out the possibility of vulnerabilities there. At least, whatever you're doing, I hope you're using a secure padding scheme such as OAEP (at least unless you're using key encapsulation, which avoids the need for padding).

-
Thank you for this detailed and exhaustive answer, as i have to create the passphrase for the privatekey anyhow, i will now also change the user account password setting to only allow long and difficult passwords. As for the padding, i am adding random characters between the substrings to always reach the same final string length. The substrings are separated by three distinctive characters. The padding scheme that is used by RSA i have to check. –  Larzan Oct 21 '13 at 7:43
Wouldn't it be better for the second problem to create a completely new key and send this to the user via snail mail? so that there is no relation between them? Or am i not getting sth here? I wanted the user to choose their pass for the backend (must be strong) and then (after login) have them insert another key that i send them via snail mail, which is the passphrase for the privatekey. –  Larzan Oct 21 '13 at 8:14
IMO, "password strength checkers" frequently do more harm then good: diligent and security-conscious users don't need them, and lazy users will just pick the easiest password that passes the check, leading to passwords like "paw0rd" or "asdfghjkl;'1234567890". Better to tell your users how to choose good passwords, and/or provide a secure random password generator. –  Ilmari Karonen Oct 21 '13 at 16:23
As for the second problem, what I meant is that is should be as slow as possible for an attacker to test whether a guessed password is correct. The typical way to do that is to use a deliberately slow function (such as PBKDF2) to transform the password into whatever it is that you'll actually use to verify the correctness of the password and to decrypt the encrypted RSA key (which can be the same thing -- if you use an authenticated key wrap algorithm like SIV to encrypt the RSA key, then a successful decryption means the password must be correct). –  Ilmari Karonen Oct 21 '13 at 16:28
Yes, i was actually wondering how to do that (make it slower to guess). I found an PHP implementation of the PBKDF2 algorithm and will use this on the passphrase the user supplied, before using the result to decrypt the privateKey. After i am done i will present my final solution here. –  Larzan Oct 21 '13 at 17:27