Encrypt files using PGP in PHP?

Going to leave an answer here as many examples across the net for PHP GnuPG are very bare bones and hopefully this saves someone some frustration.

Basically, it mirrors how the GnuPG command line tool works. You need to import a key if it's not already in gpg's key ring then you need to select the recipient's key to use for encryption/decryption.

gpg --import recipients-public-key.asc
gpg -r recipient --encrypt test.txt

If you did what I did and passed in the key as the recipient it doesn't work!

It's not clear what this field is in either the GPG manual or PHP documentation which refers to this field as "fingerprint". Check gpg's key ring for your freshly imported key with:

gpg --list-keys

This will output something like this:

pub   rsa2048 2019-04-14 [SC] [expires: 2021-04-14]
      0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA
uid           [ultimate] Dean Or
sub   rsa2048 2019-04-14 [E] [expires: 2021-04-14]

This will give you the UID and on the second line the fingerprint associated with every key. As far as I can tell you can use the UID and fingerprint as the recipient.

So your PHP code to encrypt might look like this:

// Encrypt
$gpg = new gnupg();
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);

// Check key ring for recipient public key, otherwise import it
$keyInfo = $gpg->keyinfo('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
if (empty($keyInfo)) {
    $gpg->import('recipients-public-key.asc');
}
$gpg->addencryptkey('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
echo $gpg->encrypt('This is a test!');

Then the recipient's code will look like this:

// Decrypt
$gpg = new gnupg();
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);

// Check key ring for recipient private key, otherwise import it
$keyInfo = $gpg->keyinfo('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA');
if (empty($keyInfo)) {
    $gpg->import('recipients-private-key.asc');
}
$gpg->adddecryptkey('0DAA2C747B1974BE9EB9E6DCF7EE249AD00A46AA', '');
echo $gpg->decrypt($encyptedMessage);

Note the fingerprints are the same for both the recipient's public and private key.

There is also a known issue with adddecryptkey not taking a passphrase! You either need to remove the passphrase or change your version of GnuPG.


Question 1: About PGP

  • PGP (Pretty Good Privacy) is a product and trademark of Symantec Corporation (they bought it some years ago).
  • OpenPGP is the standard used by PGP.
  • GnuPG (Gnu Privacy Guard) is a free and open source implementation of PGP.

So what you want to do is encrypt to an OpenPGP key. Which implementation of OpenPGP your client uses to decrypt the data is not important for you. With PHP, commonly GnuPG is used and there are interfaces built-in.

Question 2: Using GnuPG in PHP

Use the GnuPG interface, which is an extension that can be installed for PHP.

At first, import the key, where $keydata is the ASCII armored public key:

<?php
$gpg = new gnupg();
$info = $gpg -> import($keydata);
print_r($info);
?>

Then use this key to encrypt the data, this time using the client's key's fingerprint:

<?php
  $gpg = new gnupg();
  $gpg -> addencryptkey("8660281B6051D071D94B5B230549F9DC851566DC");
  $enc = $gpg -> encrypt("just a test");
  echo $enc;
?>

If you want to encrypt files, read and pass them to encrypt(). Be sure to use at least long key IDs (eg. DEADBEEFDEADBEEF), better fingerprints (as in the example) when referencing keys; and never use short key IDs (DEADBEEF), as those are vulnerable to collision attacks.


The is a more comprehensive example for doing both added by a user in the PHP manual.