27

I want to use PGP encryption to encrypt a CSV files, I am generating through a PHP script and then send that file to client via email. Client will give me the encryption key, which I need to use for encryption files.

I Googled about PGP and found it is Pretty Good Privacy, also I found OpenPGP http://www.openpgp.org/ and GnuPG http://www.gnupg.org/ What are these two types of PGP? and which one should I use?

Also how to encrypt a files using PGP in PHP with the key that my client will provide?

I have heard this term first time, can anyone please help in understanding this and implementing this in PHP.

djmzfKnm
  • 26,679
  • 70
  • 166
  • 227

2 Answers2

50

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.

Community
  • 1
  • 1
Jens Erat
  • 37,523
  • 16
  • 80
  • 96
  • After that how should I sent this in mail, should I simply put $enc variable as mail body and then PGP enabled emails softwares will be able to read it by themselves? or what to do to send this in mail? – djmzfKnm Apr 12 '13 at 12:43
  • Do you want to mail encrypted files as attachment or encrypt the whole mail? – Jens Erat Apr 12 '13 at 13:28
  • I am not sure client said encrypt the file with PGP and send it in mail. – djmzfKnm Apr 13 '13 at 09:40
  • Clarification: addencryptkey requires the fingerprint. You can get the users' fingerprint with `gpg –fingerprint {user_id}`. – Matthew Mar 17 '15 at 20:27
  • Never use user IDs, especially not the short (8 digit) ones. See [What is an OpenPGP Key ID collision?](http://security.stackexchange.com/questions/74009/what-is-an-openpgp-key-id-collision/74010#74010). For programming/scripting purpose, always store and process the full fingerprint. Long key IDs are acceptable for user interaction, if using short key IDs for interaction, always warn the user and make sure not to trust anything without checking the fingerprint or long ID. – Jens Erat Mar 17 '15 at 20:50
  • What does it mean when $gpg -> encrypt() function returns empty string? According to php docs, it is supposed to return encrypted string or false, but I get an empty string. Does that mean gnupg is not installed on the system? – James Oct 25 '16 at 18:07
  • This sounds like a good candidate for a new question. Make sure to provide a minimal example ("shortest possible code to reproduce the issue"). Are you omitting warnings and error messages? The function is supposed to return a string (or `FALSE`), but an empty string should never occur. – Jens Erat Oct 25 '16 at 18:12
  • If I use this code to just print the info. I always get FALSE. I am tried using client's public key as key data and my public key, same output FALSE everytime. import($keydata); print_r($info); ?> – Asit Oct 27 '16 at 08:41
  • Please ask a new question, Stack Overflow comment's aren't really made for broad discussions. – Jens Erat Oct 27 '16 at 14:26
  • So does the PGP encryption works only in file content level or file level? or they are basically the same thing? – Greyson Oct 23 '18 at 06:54
  • OpenPGP handles both in the same way, the only difference is that when encrypting a file, the [filename field is set in the literal data packet](https://tools.ietf.org/html/rfc4880#section-5.9). – Jens Erat Nov 24 '18 at 07:03
5

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.

Dean Or
  • 2,822
  • 2
  • 26
  • 25
  • I also tried for csv file encryption but did not get any solution. My requirements is to encrypt CSV file and put in to SFTP. In php we can do message level encryption only. – Naveen BT May 25 '21 at 15:11