Intended audience
Background
How to use GnuPG
Encrypting files from within PHP
Decrypting GnuPG encrypted files with PHP
Pitfalls
Alternatives
Conclusion
About the author

Intended Audience

The purpose of this article is to show you how to encrypt and decrypt information with GnuPG using PHP. Most of the major Linux distributions will install GnuPG upon request. Otherwise you can get it by going to http://www.gnupg.org.

Background

Since almost the beginning of time, it seems, man has had a need to keep information private and, in many situations, needed to decipher information previously made private by others. In our age of high technology these needs have grown exponentially and become more complex.

In the past, the ability to encrypt information with relative strength could be found only in the realms of governments. Thanks to a gentleman named Phil Zimmerman, this ability has been brought to the masses. In 1991 Mr. Zimmerman invented Pretty Good Privacy or PGP for short. PGP was designed to be high-grade encryption software available for free to anyone who wished to use it.

One of the major aspects of PGP is that it utilizes "Public-Key Encryption". In a nutshell, that means that you actually have two keys: a Private Key that only you should have access to and a Public Key that you give away to anyone you want. When someone wants to send you an encrypted file, they use your Public Key to encrypt the file. Having done that, the encrypted file can then only be decrypted by you using your Private Key.

One way to think of Public-Key Encryption is someone sending you a snail mail letter in an envelope that only you can open. Anyone can see the envelope but only you can read its contents.

Because of the US Government's restrictions on exporting high-grade encryption technology, giving PGP to people outside the US was illegal. Because of this a team of programmers lead by Werner Koch in Germany took it upon themselves to write an Open Source, RFC2440 (OpenPGP) alternative to PGP called GNU Privacy Guard, or GnuPG. Because GnuPG was developed outside of the US the export restrictions didn't apply. It should be noted that PGP and GnuPG are virtually identical (with a few exceptions) so, in the interest of Open Source and keeping people out of prison, we will be using GnuPG in this article.

How to use GnuPG

GnuPG is strictly a command-line utility. There are several GUI wrappers to GPG but the binary is usually required. Since its core purpose is to encrypt and decrypt information, we're first going to have a look at doing just that, using GPG.

As with most Unix-based command-line utilities you first call the gpg command followed by switches that affect the output of the utility. For example, to encrypt a file called "my_secret_data.txt" you would call GnuPG with the -e command to encrypt followed by the -r NAME to tell GnuPG who should be able to decrypt the file. "NAME" in this instance is the first name or email address of the person who will be receiving the encrypted file. (Note that the user indicated by NAME must be in your public key ring and can be obtained by typing gpg –list-keys).

Here it is in action:

gpg --r john@doe.com my_secret_file.txt

Once this is done you will a file called 'my_secret_file.txt.gpg' in your current directory. Any attempts to view the contents of this file will prove futile unless you encrypted it using your own Public Key. Feeling like a secret agent yet?

Now suppose Mr. John Doe has encrypted a file and sent it to you. To decrypt it you simply use the -d switch followed by the encrypted file.

gpg -d john_doe_secret_file.txt.gpg

Since you have your private key contained within your secret key ring GnuPG can determine whom 'john_doe_secret_file.txt.gpg' was intended for and will decrypt it after you provide your passphrase.

All in all, this is pretty simple stuff huh? Let's take the next step of using GnuPG within a PHP script.

Encrypting files from within PHP

Now things get a little tricky. Quite often your PHP scripts are written to run automatically within the web server without any intervention by you. What kind of life can you expect to lead if you have to enter your GnuPG passphrase every time PHP tries to decrypt a file? But we're getting a little ahead of ourselves. Let's first look at how we can encrypt a file with GnuPG and PHP.

The following script does just that:

<?php
    $gpg 
'/usr/bin/gpg';
    
$recipient 'john@doe.com';
    
$secret_file 'secret_file.txt';

    echo 
shell_exec("$gpg -e -r $recipient $secret_file");
?>

After running this script you will find 'secret_file.txt.gpg' in your directory (Again, make sure 'john@doe.com' is in your public key ring!). This is assuming that GnuPG generated no errors. If it did then they will be echoed to STDOUT.

From here there are several things you can do. For one, if there are any errors you probably want to look for them within the script instead of just echoing them for the entire world to see. You might also want to email the encrypted file to Mr. Doe using PHP's mail() command.

But what if you want to encrypt raw data not contained in a file? This too is possible by piping the data directly to GnuPG:

<?php
    $gpg 
'/usr/bin/gpg';
    
$recipient 'john@doe.com';
    
$encrypted_file 'foo.gpg';

    
shell_exec("echo $argv[1] | $gpg -e -r $recipient -o $encrypted_file");
?>

This script takes the value of $argv[1], the first argument after the script name, and passes it to GnuPG for encrypting. GnuPG, using the -oswitch, writes the encrypted data out to $encrypted_file. Again, you will probably want to check for and deal with any errors generated by GnuPG.

Another option is to leave off the -o $encrypted_file part and store the encrypted data inside a variable. That way you can use PHP to do with the encrypted data as you please, saving valuable file I/O.

<?php
    $gpg 
'/usr/bin/gpg';
    
$recipient 'john@doe.com';
    
$encrypted_message =  base64_encode(shell_exec("echo $argv[1] | $gpg -e -r $recipient"));
    
mail('john@doe.net'
         
'Your Encrypted Message'
         
$enrypted_message);
?>

If you do this is especially important that you Base-64 encode the data so you can play nice with the email client receiving the encrypted message.

Decrypting GnuPG Encrypted Files with PHP

Decrypting an encrypted file with PHP and GnuPG can be a bit more complex than encrypting, since you are required to provide a GnuPG passphrase. The solution to having to type the passphrase every time the script is run lies in a handy little gpg switch called --passphrase-fd. This switch tells GnuPG to accept the passphrase from a file descriptor, which means that you can echo the passphrase and pipe the output to gpg, as seen in the following example.

<?php
    $gpg 
'/usr/bin/gpg';
    
$passphrase 'My secret pass phrase.';
    
$encrypted_file 'foo.gpg';
    
$unencrypted_file 'foo.txt';

    echo 
shell_exec("echo $passphrase | $gpg --passphrase-fd 0 -o $unencrypted_file -d $encrypted_file");
?>

This script tells gpg to accept the passphrase from STDIN (indicated by the 0 following the switch) and decrypt the information into a file named "foo.txt".

As with encrypting information, you can leave off the -oswitch to gpg and let the decrypted data be captured inside a variable.

It should be noted that the -o switch should always come before the -d switch.

Pitfalls

As with anything encryption related, there are pitfalls to the methods described in this article. The major pitfall is in storing your passphrase in plaintext within the script. Should your script's source ever been seen without having first been processed your supposedly secret passphrase will no longer be secret.

A second pitfall is in the use of PHP's shell_exec() statement. Since you are executing a shell command the passphrase is available for all to see due to having to echo it. Don't use this method unless you are sure that only trusted users are on your server!

These two pitfalls are enough to suggest you probably won't want to use these methods in situations of national security, to say the least.

Alternatives

One of the best alternatives is to take advantage of a recent project within GnuPG called GnuPG Made Easy (GPGME). This is a project to develop a GnuPG programming library so that GnuPG can be embedded within other applications and languages such as PHP. Having GnuPG would be a great addition to PHP because there would no longer be a need to use shell_exec() when encrypting/decrypting data.

Another alternative, and one which has already been built as a PHP module, is Mcrypt. However, it shares a downside with GnuPG in that you must still store the passphrase within your script or database.

Conclusion

Having the ability to encrypt data can provide a distinct advantage in this world of script-kiddies and nosey governments. You are encouraged to explore the power of bringing PHP and GnuPG together and, if you have the coding mojo, contribute to the PHP project by building a GnuPG module with GPGME!

About The Author

Darrell brogdon is an independent consultant specializing in Web Application development. He can be reached at dbrogdon@brogdon.biz.