Article : Encryption and Decryption using PHP and GnuPG

Encryption and Decryption using PHP and GnuPG

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 -ecommand 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 -e -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:

 $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:


 $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.


 $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.

 $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!