July 15, 2009

PHP public key cryptography using OpenSSL

Recently I have been handling the security of some sensitive data. I had originally been encrypting/decrypting data with a symmetric-key system using mcrypt for PHP. This was due to the web frontend and the backend existing on the same server. However for security purposes I am now separating the frontend and backend onto different servers, so that there is no way the web accessible frontend, whether compromised or not, can get at the data it inserts into the database.

In order to do this, a asymmetric-key system is needed, such as public-key cryptography. Googling for examples of this in PHP, there doesn’t seem to be any results of this other than the php OpenSSL extension documentation, and systems that try to reinvent the wheel with their own implementations.

Using the PHP OpenSSL extension it is fairly easy to sort out a secure system for encrypting data with one key that only can be decrypted with another.

First, you need to generate your private and public keys. You can either do this yourself with the openssl command-line application:

# generate a 1024 bit rsa private key, ask for a passphrase to encrypt it and save to file
openssl genrsa -des3 -out /path/to/privatekey 1024
 
# generate the public key for the private key and save to file
openssl rsa -in /path/to/privatekey -pubout -out /path/to/publickey

or programatically using php-openssl:

// generate a 1024 bit rsa private key, returns a php resource, save to file
$privateKey = openssl_pkey_new(array(
	'private_key_bits' => 1024,
	'private_key_type' => OPENSSL_KEYTYPE_RSA,
));
openssl_pkey_export_to_file($privateKey, '/path/to/privatekey', $passphrase);
 
// get the public key $keyDetails['key'] from the private key;
$keyDetails = openssl_pkey_get_details($privateKey);
file_put_contents('/path/to/publickey', $keyDetails['key']);

Next, you can load the public key, and encrypt the data:

$pubKey = openssl_pkey_get_public('file:///path/to/publickey');
openssl_public_encrypt($sensitiveData, $encryptedData, $pubKey);
 
// store $encryptedData ...

When you need to get the sensitive data again, you can load the private key and decrypt:

// retrieve $encryptedData from storage ...
 
// load the private key and decrypt the encrypted data
$privateKey = openssl_pkey_get_private('file:///path/to/privatekey', $passphrase);
openssl_private_decrypt($encryptedData, $sensitiveData, $privateKey);

Alternatively you can use the private key to encrypt data, sign data or seal it against multiple other public keys, but that is beyond the scope of this article.

Leave a Reply