Keeping Secrets Safe with GnuPG

Dustin Runnells

GnuPG stands for GNU Privacy Guard, a form of public key cryptography based on the OpenPGP standard. This article will show you how to perform a few essential tasks with GnuPG using PHP and the GnuPG PECL extension.

For our purposes, as someone who would like to transmit and receive encrypted messages, you need three keys: your own public key, your own private key, and the public key of the person that you would like to communicate with.

Private keys should never be shared, but your own is required to generate an encrypted message. Public keys can and must be distributed. Your public key is required by anyone who wishes to encrypt a message intended for your eyes only or to decrypt a message that you have sent them. The public key cannot be used to forge a signature or decrypt messages meant only for you.

GnuPG also serves as a means to verify the authenticity of non-encrypted data via encrypted signatures, but that topic is not covered here.

The GnuPG extension discussed here depends on the GnuPG installation on whatever machine you are working with along with the configuration of the user account under which the code will run. The examples provided here are intended to be run from the command line and will interact with the GnuPG environment of the user running them. It should be trivial to extend the concepts here to work from a web script.

Generating Keys

Before you can do anything with GnuPG, you must have a private/public key pair. Though the PECL extension does not let you create these keys right from PHP, you can easily do this from the command line with the gpg command, or a friendly GUI frontend for whatever OS you choose. In Linux, all you need is:

gpg --gen-key

After answering a few easy questions about your identity, selecting a passphrase for use of your private key, and accepting the defaults for everything else, your GnuPG keyring will be generated. The keyring stores your keys and the keys of anyone that you plan to interact with.

Once generated, your keyring is automatically populated with your first private/public keys. You should export a copy of both your public and private keys and keep them in a safe place so that you can reuse the same keys in all future interactions with GnuPG. You may also want to consider publishing your public key to a key server to make it available in a safe way to anyone who needs it. More information about GnuPG tools and key servers can be found on the gnupg website.

Exporting Keys

One way to export your GnuPG public key is with PHP. Before you can perform the export however, you must find the key “fingerprint” of your new public key. Every key in your keyring will have a fingerprint that is used as a unique identifier. To list them all, loop through a gnupg_keylistiterator() object:

$iter = new gnupg_keylistiterator();
foreach ($iter as $fingerprint => $user) {
    print "$fingerprint: $usern";

For the keyring of a user named “testuser” on my workstation, the above code results in the following output:

6436010991C352981F95F9A5D5AF916244CD449B: Test User (This is a test account) <>

The key itself is binary data, so to actually encode and print an ASCII version of the public key we need some new code:

$gpg = new gnupg();
$export = $gpg->export("6436010991C352981F95F9A5D5AF916244CD449B");
print $export;

This creates a new gnupg object, and uses the export() method to export the public key corresponding to the provided fingerprint. In my case, the test user’s key is:

Version: GnuPG v1.4.2 (GNU/Linux)


The extension only permits us to export the public key, so if you would like to export your private key in a similar fashion for backup purposes then you’ll need to use the GnuPG tool itself.

Importing Keys

We now have three keys as required for a private exchange. We’ve generated our own public/private keys, and you have the public key for testuser above that we’ll use as a third party public key.

To communicate with testuser, we’ll need to get her public key into our keyring. Importing a public key can be done by passing the public key to the import() method:

$gpg = new gnupg();
$info = $gpg->import($keydata);

You can verify that this key has been added to your keyring on the command line with gpg --list-keys and use the gnupg_keylistiterator() example from earlier to get the fingerprint.

Encrypting Messages

With all of our keys in our keyring, we can encrypt an important message for testuser. The message contains the answer to the question:

Q: How many programmers does it take to change a lightbulb?

We’ll use testuser’s public key to ensure that she will be the only person able to decrypt the answer. The code for encrypting the answer is:

$gpg = new gnupg();
$enc = $gpg->encrypt("A: None, that is a hardware problem!");
print $enc;

We use addencryptkey() to specify which public key to encrypt this message with, which should be the recipient’s key, not the sender’s. In this case it is the public key fingerprint of testuser.

Once encrypted, nobody will be able to decrypt the message unless they have testuser’s private key in their keyring… which should be no one other than testuser herself.

Decrypting Messages

From the other side, once testuser receives the message, she can use the code below to decrypt the secret answer:

$gpg = new gnupg();
$plain = $gpg->decrypt($encrypted);
print $plain;

The encrypted message is stored in $encrypted. We create a new gnupg() object, specify which of testuser’s keys should be used for decrypting the message by fingerprint and our private key password, and then print the decrypted message. It is important to mention that decrypting a message will always require the recipient to enter the password that they associated with the private key in addencryptkey(), except in gnupg v2 where you cannot enter a plain text password in the code – you will be prompted for a password while running this code in the CLI. If you plan to use this function in a web based tool with gnupg v2, you might want to consider excluding the passphrase on the web user’s private key.

In Closing

Now that we know how to encrypt and decrypt with GnuPG, why would you want to in PHP? With SSL you can secure data transmitted between a web server and client, and SSH can be used to secure shell sessions, so why something else?

Sometimes you need information to be secure, not only while it is in transit, but also where it is stored and all layers in between. Maybe you need to transmit financial information to a remote location; can you trust system administrators or those who have physical access at the location? Or perhaps a project requires you to transfer data using an insecure protocol, such as FTP.

While our simple examples above are useful for transferring encrypted messages, GPG and the gnupg extension can also be used to validate the authenticity of unencrypted messages by the use of signatures. Email is also a notoriously insecure method of communication and messages are easily forged, and though not described in detail here, using encryption and encrypted signatures ensures security and authenticity.

I encourage you to further explore the GnuPG tool options and concepts if you’re writing an application that calls for serious data security.

Image via Fotolia