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.
Hi, do you think that this method could work also between different os? Example: I create the public and private file in Linux but I have to use the public file into Windows’s enviroment.
Thanks
Alessandro
Yes, as long as you have php-openssl installed on both systems, their keys and data should work between them.
If you’re trying to write a portable app, I would avoid using php-openssl.
1. php-opensl isn’t installed on a lot of shared hosts in my experience.
2. php-openssl doesn’t fail gracefully. You can test to see if the extension’s installed by using extension_loaded() but that’s not enough – there needs to be a openssl.cnf file as well.
3. You can only load public keys if they’re contained within an X.509 certificate. openssl_pkey_get_details() provides you with a non-X.509 encoded public key but php-openssl doesn’t provide you with any mechanism to actually load it since it’s not contained within an X.509 certificate.
My own personal recommendation would be to use phpseclib’s Crypt_RSA implementation:
http://phpseclib.sourceforge.net/
Yes, some shared hosts don’t have it installed, but if you’re dealing with sensitive data, you would be using https, so I’d expect hosting services that provide that would also provide more common extensions such as php-openssl.
Also, it’s in your hosting provider’s interests to provide support so you can request that php-openssl be set up correctly if they have it installed.
In my case, it was a dedicated server that I have full access to, and a default extension suited me better than a third-party cryptography library which I’d have to assess it’s trustworthiness.
After all, php-openssl uses the same library as the https connection uses.
You can have OpenSSL installed but no PHP module available, just as you can have MySQL installed but no PHP module available (indeed, you have to add the MySQLi extension to php.ini manually upon installation). It’s annoying, but sometimes there just isn’t much you can do about it.
hey Andy,
thanks for the info. I had trouble generating keys using php openssl_pkey_new() and using/extracting/loading the key pairs using openssl_pkey_get_public($filepath) etc using osx 10.6/php5.3.0…
…but I did have success with the command line generation and manually loading the keys and supplying them as strings.
eg.
$public_key_string = file_get_contents($public_key_path);
$public_key = openssl_pkey_get_public($public_key_string);
$private_key_string = file_get_contents($private_key_path);
$private_key = openssl_pkey_get_private($private_key_string, $passcode);
hope this helps anyone else with the same problems stumbling across your post