bdx
bdx

Reputation: 3516

Is my method of encrypting encryption keys secure?

I'm writing a Rails 3 web app in which anonymous users will be able to enter details about an event and have them encrypted in my database, retrievable only by that user or anyone with the per-event password the user decided on when creating it.

I'm doing this all as an exercise to get my head around programming with encryption and hashing, so it might be a bit overkill, but I'm wanting to have a working model of the 'most-secure' way of doing things, without getting into two-factor auth or a computer not attached to any network hidden in a secret vault 30 km under the earth's crust (of which I already have two).

The current data I'm storing and the encryption of it all is as follows, I'd just like some feedback as to whether I'm using any insecure methods or anything that will weaken my application (and particularly my user's data) to attack.

Every event has the following fields stored in an Oracle database using Transparent Data Encryption:

The webserver is running with restricted system privileges, fully patched, and the webserver processes are unable to browse outside of the site's directory structure. The webserver only runs HTTPS.

When the user creates the event, they supply the clear-text data to go into the event_data field, and a password to secure that data with. To retrieve the data, they only need to enter the id number given to them once they have submitted the form, along with the password they chose. During event creation, the user can also check a box to allow for admin retrievable data to be generated, if they elect to. This option is set to false by default.

This clear-text of the event is still kept in memory for purposes of admin-retrieval, as described later.

The event data is secured using AES256 CBC encryption with a securely generated random IV and key. Both the IV and key are then encrypted using a public key (RSA 2048-bit) stored on the server. Both the IV and key are then XOR'd with the SHA-256 hash of the user-supplied password, and subsequently both stored in the DB.

The user password is then hashed with SHA-256 using a 256-bit securely random generated token as a salt, a string is created with a colon delimiter containing the hash and salt, which is then encrypted with the public key (same one as previous) and stored in the database password_hash field.

The clear-text event data then goes through the same process with a newly randomly generated key and IV for the admin retrieval and stored, the key and IV then encrypted with a different public key (only used for admin retrieval), and stored in the database without being XOR'd against anything.

To retrieve the data, the user enters their event ID and password. First, the password_hash is unencrypted using the private key (stored on the server in a non-web-accessible directory) (the password for that private key is hard-coded into the app), the user-entered password is then rehashed using the salt from the now unencrypted database entry, and if it matches the hash of the stored salted password, the process continues on (else, returns error of "Event ID not found or password incorrect").

The encrypted key and IV are then XOR'ed with a newly generated unsalted hash of the user's password, and decrypted with the same private key/password used for the password hash. These are subsequently used to decrypt the event_data, and return the data to the user.

If the admin wishes to retrieve the data, they must upload the private key and enter the private key's password, at which point the admin IV and key are decrypted, the in-memory private key is destroyed, and the admin retrievable event data is decrypted.


So, that is my design for this thing, the only current weaknesses I've identified is storing the private key used for event and user password encryption on the server, and having that private-key password hard coded into the app. I can't see a way around that however without spending a lot of money on a hardware based encryption appliance. If anyone can suggest a better way of architecting this to avoid that problem and not inconvenience end users by generating a separate cert for every event and giving them the private key, subsequently forcing them to re-upload it every time they want to decrypt the event data, I'm more than open to it.

If you see any problems other than those ones, I'm also very curious to hear about it, and would love to be given resources to read or an explanation of what the problem is and what I could do to rectify it.

Please be aware that I do not possess university-level mathematics knowledge and despite rather wanting to understand encryption, I'm far beneath a level where I can do any sort of cryptographic analysis for myself. With this project, I've simply done as much reading on overviews that were of a level I could understand, and tried to apply that knowledge.

Upvotes: 1

Views: 1654

Answers (1)

Scovetta
Scovetta

Reputation: 3152

The scheme seems very complicated, and the devil is always in the details. If your application is capable of retrieving the data without the user's permission, then all of the encryption sugar you add might not be worth much, because attacks are likely to come through the application layer.

Take a look at how (good) full disk encryption software works. Without getting too much into specifics, think about just taking the user's password, hashing it (using whatever hash function you like) and using that as a symmetric key when you encrypt the data. If the user forgets their password, the data is pretty useless.

You can add some salt in there to prevent a dictionary attack, but you need to store the salt somewhere...

For the admin access, generate a random password, e-mail it to the admin, and then hash it, encrypt the data with it, and store it separately on the database.

Take a look at http://blog.cryptographyengineering.com/2011/11/how-not-to-use-symmetric-encryption.html, it goes into depth about how to best handle IVs and encryption modes.

Upvotes: 1

Related Questions