views:

62

answers:

3

I am new to AES encryption but trying to build a solution which:

  • Accepts consumer data
  • Encrypts that data using AES and a "public" key
  • Store that data in a MySQL database
  • Have the ability to pull and decrypt the data ONLY with a private key (stored on my personal machine, not the server itself).

I realize this may be overkill but want to be overly protection for my consumer data.

A few things to note:

  1. This is not credit card information so please don't write telling me about PCI-DSS, it is other form of personal information all under 500 characters in length for each field.
  2. I may store pieces of the consumer information and others in a second database tied together by a unique member ID for additional security.
  3. Incoming MySQL calls can only be made to my server directly from my static IP.
  4. SSH root is disabled, ports changed, and so on so I feel my server is in faily good shape to prevent any "basic" misuse.

I have looked for articles online and SO but have not found much in terms of keeping the private key off the server completely. Even if I need to keep on the server itself - thoughts or suggestions for how to move forward are appreciated.

EDIT - CLARIFICATION

Just to be more clear, the goal I am trying to achieve is this (in very basic form):

  • Customer enters his/her phone number online.

  • The phone number entered is encrypted online using key A and stored within the mysql db

  • The customer will never be able to see the full phone again at this point, but can certainly update it (going through key A process a nth time)

  • As a system administrator, I am only able to access the data by either downloading and decrypting the data on my local machine (that or I must first upload a temporary file which is used to then decrypt the data I need).

EDIT 2 - I'm a an idiot

I am using Andrew Cooper's response below but am having trouble getting my script to read the contents of the .pem file I generated. Based on the code below - how would I get $public key to correspond to a specific .pem file on my server?

<?php

if (isset($_SERVER['HTTPS']) )
{
    echo "SECURE: This page is being accessed through a secure connection.<br><br>";
}
else
{
    echo "UNSECURE: This page is being access through an unsecure connection.<br><br>";
}


// Create the keypair
$res=openssl_pkey_new();

// Get private key
openssl_pkey_export($res, $privatekey);

// Get public key
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];

echo "Private Key:<BR>$privatekey<br><br>Public Key:<BR>$publickey<BR><BR>";

$cleartext = '1234 5678 9012 3456';

echo "Clear text:<br>$cleartext<BR><BR>";

openssl_public_encrypt($cleartext, $crypttext, $publickey);

echo "Crypt text:<br>$crypttext<BR><BR>";

openssl_private_decrypt($crypttext, $decrypted, $privatekey);

echo "Decrypted text:<BR>$decrypted<br><br>";
?>

EDIT 3 - maybe not 'idiot' but semicolons hate me

I had a semicolon misplaced. I am using the function: file_get_contents() but is there a more preferred method of reading in the data for the .pem file?

A: 

... That doesn't strike me as possible. MySQL's AES_DECRYPT method requires the encoded message as well as the original key in order to decrypt something. This means that anyone that can get the encryption key can decrypt the message.

Christopher W. Allen-Poole
But he doesn't want to decrypt it. He wants to store the data in the database in its encrypted form. Is that right @JM4?
Andrew Cooper
That is correct - I *may* decrypt online using my own key in temporary situations but I never want to be able to look directly into the DB and see open data
JM4
If I am trying to use the key "foo" to encrypt, then PHP needs to have AES_ENCRYPT( $password, 'foo' ) somewhere. This means that anyone who has read access to the file which controls encryption can then decrypt the database. If he's the only one with read access, though, then it shouldn't matter where the private key is.
Christopher W. Allen-Poole
The answer is - don't encrypt on the server. Have the data encrypted on the client side, and sent to the server (and then stored in the database) in encrypted form along with the session key encrypted with the public key. The only way to decrypt the data is by first decrypting the session key using the private key that is kept, um, private.
Andrew Cooper
I'm assuming that the encryption is going on server side because he said he wanted to use AES. AES simply does not work the way you are suggesting (http://stackoverflow.com/questions/273396/aes-encryption-what-are-public-and-private-keys).
Christopher W. Allen-Poole
@Christopher W. Allen-Poole: I understand how AES works. You can encrypt a message using AES (symmetric encryption) and a session key. You can then encrypt the session key using the RSA alogrithm and a public key. You then send both chunks of cyphertext to the other end. The only way to decrypt is to decrypt the session key using RSA and the private key associated with the public key that was used to encrypt. You can then use the decrypted session key to decrypt the data using AES.
Andrew Cooper
@Christopher W. Allen-Poole: He did ask for AES. He also asked about using a "public key", hence my solution. The beauty of doing it this way is that all his web and database servers ever see is cyphertext. The data is never "in the clear" on either of these systems, so compromise of the server can't compromise the data.
Andrew Cooper
+1  A: 

You should be able to generate the public/private key pair on your personal machine, and then publish the public key in your app so the data can be encrypted. In this way the server never sees the private key, and if the server is hacked the data is still safe.

You'll want to make sure the whole transaction occurs over SSL. The client side can generate a random session key, encrypt the data with that key (using AES), then encrypt the key with the public key from your app (using RSA), and send the encrypted data and key to the server. You could store the whole blob in one database field or two. The only way the data can be decrypted is to decrypt the key first, and the only way that can be done is by using the private key on your personal machine.

Update

Check out http://plugins.jquery.com/project/jQuery-Gibberish-AES. It's a JQuery plugin that appears to allow this type of scenario. I have no experience in using it, but it appears to me to be a good start.

New Update

Just to be clear about what I'm suggesting, and to address your edit:

You can't use only AES encryption. With AES there is one key that is used both to encrypt and decrypt. The key would have to exist wherever the encryption operation occurs, either in the client code, or on the web server. In the first case anyone can get your key. In the second case, if the web-server is compromised, then the key, and the data, are also at risk.

The solution is to use good, strong AES encryption in combination with public-key crypto (RSA). I'd suggest doing to the crypto on the client-side, for reason I'll outline below. Here, though, are the steps I'd suggest:

  1. On your private machine create a public/private key pair, and keep the private key safe.
  2. Put the public key somewhere in the code you send to the client.
  3. When the user submits the form the client code:
    1. Generates a random AES key (the session key)
    2. Encrypts the form data
    3. Uses your public key, and the RSA algorithm, to encrypt the session key
    4. Discards the plaintext session key
    5. Sends the encrypted form data, and the encrypted session key to your server
  4. Your server accepts the encrypted form data, and stores it, along with the encrypted key, in the database.

You now have encrypted data in the database that can only be retrieved using the private key stored on your private machine. Even if the user somehow manages to capture the session key while it's in the clear on his machine, the worst that can happen is that that one record could be decrypted.

The reason I'd suggest this client-side approach is that it means that your server never see the encryption keys in the clear. If the same scheme where employed on the server-side then, theoretically, an attacker could be sitting on your server watching it happen. At the end of the day it basically comes down to how paranoid you want to be.

Following this scheme, when you want to retrieve the data you'd dump the required data, in encrypted form, from the database to your private machine. The for each chunk of encrypted data:

  1. Decrypt the session key using the RSA algorithm and your private key
  2. Decrypt the data using AES with the session key from step 1.

Anyway, that's the approach I'd suggest. I'm sure there's libraries out there to handle this.

Andrew Cooper
I'm not sure how that is supposed to work: AES_ENCRYPT can encrypt using only one string and one key. Anywhere that has access to the key has access to whatever is contained in the blob that the key encrypts. How can the server encrypt something without having access to that key?
Christopher W. Allen-Poole
@Christopher W. Allen-Poole - You're assuming the encryption happens on the server. If it happens on the client, and then the client sends encrypted data and the key encrypted with a public key then there's nothing on the server that can decrypt it. The server doesn't need to know the session key used to encrypt the data.
Andrew Cooper
@Andrew Cooper - i looked at the gibberish, jquery code but doesn't necessarily seem to function as stated and the "documentation" is horrible. I have added a new edit to further explain my goal.
JM4
@JM4: Like I said, I have no experience with Gibberish - I just found it through Google. I'm sure there are tools out there that will help you. See my update for a more detailed explanation of my suggested approach.
Andrew Cooper
@Andrew Cooper - I have already started the process of going with your method and I do like it the best. Would you mind taking a look at my most recent edit if you get a shot.
JM4
I had a missing semi-colon (duh...) but am using file_get_contents(); is there a more preferred method?
JM4
@JM4 - I don't know if there's a preferred method. If file_get_contents(); works then I'd stick with that.
Andrew Cooper
Thanks for all your help!
JM4
@JM4 - No worries.
Andrew Cooper
+2  A: 

Encrypts that data using AES and a "public" key ... decrypt the data ONLY with a private key

But AES is a symmetric encryption algorithm - i.e. the same key is used for encryption and decryption.

Or do you mean you want to implement something like SSL, where some assymetric algorithm is used for encrypting a randomly generated key then the end points use that key for a symeetric algorithm? This kind of approach is only of benefit where the data to be encrypted is significantly larger than the keys used - is that the case here?

Have a google for PHP and RSA or ELGamal for assymmetric encryption algortihms. (note it'll probably be significantly faster and easier to program if you shell out to something like GPG to do the encryption - there are wrappers on phpclasses for this).

C.

symcbean
+1 for using GPG, fits the requirements perfectly without having to get your hands dirty with crypto.
SimonJ
Just remember to back up the key somewhere :)
SimonJ
@symcbean - ultimately, I am only trying to ensure that somebody cannot 'decrypt' the data within my database if the server is compromised (and by having the only 'decrypt key' stored locally, thought it was at least a strong security measure).
JM4