This is the first part of a two-part article about using the OpenSSL functionality in PHP to encrypt and decrypt data. This part will cover key generation and the second part will show you how to use those keys to encrypt and decrypt data.
The project I am currently working on requires some JSON data to be encrypted and later decrypted in a different location (potentially on a different platform). Because of the cross-platform component, we have chosen to use OpenSSL.
Rather than just showing PHP code, I am going to explain what is going on. I won’t cover signing or certificates as this article is long enough as it is.
Nor will I be dealing with sockets. Although SSL stands for Secure Sockets Layer, this article is about using OpenSSL to encrypt and decrypt data rather than about transmitting it from one place to another.
Symmetric and Asymmetric encryption
For centuries, encryption/decryption was symmetric. This simply means that you use the same key to encrypt and decrypt your message. Decryption just reverses the encryption process. Even complex codes such as Enigma used symmetric encryption.
In the 1970s, asymmetric encryption was invented. This uses a pair of keys which are related to one another. Unlike symmetric encryption, once a message is encrypted with one key you cannot decode the encrypted version of the message with that key. The process to decrypt the message is not to run the encryption in reverse, but to decrypt it using the other key.
These two keys are usually referred to as the public and private keys. The public key can be given out freely because it cannot be used to decode an intercepted message. The private key is the one that must be kept safe.
Asymmetric keys
Asymmetric keys are essentially very long numbers that relate to one another. When the keys are generated, two large prime numbers are chosen. Multiplying these two numbers together is trivial, but taking the resulting number and trying to deduce the two prime factors would be an incredibly time-consuming task, even with large amounts of computing power. The larger the numbers, the more time-consuming the task becomes.
The private key contains the two prime numbers. The public key contains the product of these two numbers (ie. The two primes multiplied together).
When the keys are generated, you specify the size of the key in bits. These are typically powers of 2 (512, 1024, 2048, etc), although they don’t have to be. Larger keys are more secure because of how long it would take to calculate the two prime numbers, but there are also disadvantages. It takes longer to encrypt data with a larger key and a larger key can also generate a longer encrypted message. Beyond a certain point, increasing the size of the key only really adds overhead without making things any more secure. Depending on your circumstances, you may decide to choose a shorter key to keep speed and storage/bandwidth down. As with many things in life, it’s a compromise.
OpenSSL and PHP
So let’s look at some of this in practice. I’ll start by generating a 1024-bit private key using the OpenSSL functions available in PHP (provided they have been compiled in).
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
));
openssl_pkey_export_to_file($privateKey, 'private.key');
This code snippet generates a new 1024-bit private key and exports it to a file called private.key. You can specify a different key size if you like (the minimum size is 384 bits). The larger a key is, the longer it takes to generate.
The resulting file looks like this:
MIICXAIBAAKBgQDVK04tGOVw+ya5s1t7CeRYrAyLFd/YudfwOx6eHB+D1rFjj5q8
phMTdVDr+XjS8EVVNJzcQhuoYeiyLS2jeZyd6VIiT13W5spcOd8icMp0zWjQvFSH
z3iQadyIfu2b6H/uABRA3q8bXzXLlpQ70RurSnu1a6K/jRDlpdI1JIIi0QIDAQAB
AoGARqDMjCCdlKuCDzEf9Eo4wDBxD3w16Ibaxxuvb09+GZ5+s7AW4r5bv6y1HRpR
MAKv1iVSe5/jrgySnsZdQra+bvC1sjaSbBrTtdMRlWaWcJ2eK5eCyJopDA2QQMF2
4pMjukA/AkFPdAkvlAv2AtRnBqtzxdgvQXR01YnBhx8oTuECQQD0LLm5GNQSCAM2
AyNRiKm9GJ23KEdyHNsgM6bH+7npKySbxB6VjzySbObVZ3iP4HGxmsJWXdxnq0Ol
NGbzUixVAkEA334sbuJ9K0wXDgFjQt0Sb/0Xe7+e1exRNc1m9t9ZWvTlo94rYitK
Vl/PU5PpoxA6NGDyMATBhoQ9H5ZF93jYjQJAZI3qqhRUeVx9Xgfqyo/6PtpdUOkw
iwjhIKDExUSgKirPN6qLYdIMAs0APtAOsUmf6KEv+PtMYhEAmY87+mZTxQJAAYVc
TAziiS7lYUUFJelXPMfeJwtwy0fmbZVORBPVCdds0KasaOieguP4BzuUdXWgz8Zx
H36Iyp+Pwu1E4KBD6QJBAPP4knEVJfbFl+Jhl9DbBfvWtx4vTvKdHQaMp3XgSIzg
VQZheyFObscs3lsaBF3jSb3nkF5a06NwR2EcmdpZc7Q=
—---–END RSA PRIVATE KEY—---–
As you can see, the key details are base64 encoded.
If I were to run the script again, I would get a different private key because different random primes would be picked.
If I want, I can even password-protect the private key. In this example I’m exporting to a different filename:
This gives a longer private key file:
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C34CCE74A28AA18B
7RGQVqozMD6hZqTiXqXjTNrKaFLRATtdNZrydD38RGaZ7CZMrZRLCNDDpl9z9elJ
k8/zWCDroqT45R+qJq1MdGKhGsdB0p68sSp+PG71YNVRvI/SnxcaZX19U4GxcNiX
/DHthBX43Bur7ytngvLx79i1wF/AsiCsPnPcP3nZk5V3/aKtsz/in/3+H+UGwec4
mK/S9R5Eqif4ANTl2NHiqGOYRZIec4uBHhxcw2JYxqueIjvDF/w3hXQ/c+sEvIXy
Fr7bgxNVo8wCl9g6czAtLsLblJmusKl91/Plp9ozW2QBlaav/YULqK2EyTOdgOGl
bRz7Fs0K/6ifaL0QimPvJgfC5fOu1Le62FMB84bj4A3tNkCX5PhSdafJnYSaMCJr
kwqoTJ7PeOklYLzZg7IKzbsKSNb8V0HsyBx+4iYtO8MgJ4pJeGfzuO95UojO4FY5
5brIbGSWzZPr6pwv+wASTaesKyvZB9xb2VQc1W+8v4QpwTtKdNe3iunpb6zd1bF+
JVpb3yeOLt9kQcyKxD+idgCUznzASOS5nI0EE6+uCUXH6v3QcT/MlQ3JiIoUZAQ8
lthPoZDFA3TiFU1EO48+kW2mc0WKE+/PL7HfRz0aXOKIFlNjUAQf7UqWVlelk6LS
R0iLaZzsIlXvPbor8rzexYAUsmN39cUbmdfQSVjRPpOaD0bVZceh3SLu3dEkTe8s
drCrsUQvTpyoHRWP3PJ2aFp4/LRLFpjIl3kBKJjhDAg3Gb7lOFHCHujE4AlBiSRR
JYwN6G/z/jEATzGRaPx6dAKgdJd/EOKEsOIcL69MPuUmsuRmZc8RzQ==
---—–END RSA PRIVATE KEY—---–
Note that the password is only applied when the private key is exported to file. The private key itself is not affected by this password, but you will not be able to load the key from the file without this password.
Adding a password is probably a good idea when a human is using the key, but probably of less value when the process is automated. Loading an encrypted private key uses more processor resource than loading an unencrypted one. If a server is compromised and the private key obtained, the chances are that the file containing the password would also be obtained. It is much better to protect the server itself than trying to protect the private key with a password.
Obtaining the public key
Having generated the private key, we next need to get the corresponding public key. The openssl_pkey_get_details() function provides some information about the private key:
The result tells us the size of the key as well as the public key for this private key:
(
[bits] => 1024
[key] => —---–BEGIN PUBLIC KEY—–---
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVK04tGOVw+ya5s1t7CeRYrAyL
Fd/YudfwOx6eHB+D1rFjj5q8phMTdVDr+XjS8EVVNJzcQhuoYeiyLS2jeZyd6VIi
T13W5spcOd8icMp0zWjQvFSHz3iQadyIfu2b6H/uABRA3q8bXzXLlpQ70RurSnu1
a6K/jRDlpdI1JIIi0QIDAQAB
—---–END PUBLIC KEY—---–
[type] => 0
)
If your implementation requires a server to have access to both public and private keys (for example, it may generate the key pairs and send the public key to a user or another server), this means that you do not need to store both keys in files or in a database. Storing the private key is enough, since you can get the public key from the private one.
Writing the public key to file is simple enough, using file_put_contents() or similar.
Finally, it’s not a bad idea to free a key once you have finished with it – in the same kind of way that you would close a database connection once you’re done with it. It’s not strictly necessary under normal circumstances since it normally happens at the end of a program and resources will be freed up once the program ends. But it’s a good habit to get into.
The full code for generating a public/private key pair looks like this:
'private_key_bits' => 1024,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
));
openssl_pkey_export_to_file($privateKey, 'private.key');
$a_key = openssl_pkey_get_details($privateKey);
file_put_contents('public.key', $a_key['key']);
openssl_free_key($privateKey);
This code is obviously very bare-bones and you would probably want to add error checking at various stages, but I am keeping the code simple for this article.
In the second part of this article I will show how to use the public and private keys to encrypt and decrypt data.

Awesome looking website. I recently built mine and I was looking for some ideas for my site and you gave me a few. Can I ask you whether you developed the website by youself?
We had a designer friend help us you can see her other work and get in contact through her site http://www.lisathompsondesign.co.uk/
This will be a terrific blog, would you be interested in doing an interview about just how you developed it? If so e-mail me!
Hi there there administrator, I just wished to firmly leave a short statement to actually admit that in fact I enjoyed your posting. Thanks!
Hey Steve,
It’s a very comprehensive article covering all major aspects of PKC in PHP. I reside in India and when I try to export private key using openssl_pkey_export() or openssl_pkey_export_to_file(), I get nothing (NULL maybe) as return value or output.
Are there any US export restrictions which maybe affecting key generation using openssl? I feel atleast I should get TRUE or FALSE. Are there any ways of debugging where exactly does the problem lie within openssl_pkey_export_to_file.
The environment is Windows, XAMPP and below is the configuration I am using:
$config = array(
‘config’ => ‘C:/xampp/apache/bin/openssl.cnf’,
‘private_key_bits’ => 384,
‘private_key_type’ => OPENSSL_KEYTYPE_RSA,
);