3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
6 * Crypt_GPG is a package to use GPG from PHP
8 * This package provides an object oriented interface to GNU Privacy
9 * Guard (GPG). It requires the GPG executable to be on the system.
11 * Though GPG can support symmetric-key cryptography, this package is intended
12 * only to facilitate public-key cryptography.
14 * This file contains the main GPG class. The class in this file lets you
15 * encrypt, decrypt, sign and verify data; import and delete keys; and perform
16 * other useful GPG tasks.
21 * // encrypt some data
22 * $gpg = new Crypt_GPG();
23 * $gpg->addEncryptKey($mySecretKeyId);
24 * $encryptedData = $gpg->encrypt($data);
32 * This library is free software; you can redistribute it and/or modify
33 * it under the terms of the GNU Lesser General Public License as
34 * published by the Free Software Foundation; either version 2.1 of the
35 * License, or (at your option) any later version.
37 * This library is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40 * Lesser General Public License for more details.
42 * You should have received a copy of the GNU Lesser General Public
43 * License along with this library; if not, write to the Free Software
44 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
46 * @category Encryption
48 * @author Nathan Fredrickson <nathan@silverorange.com>
49 * @author Michael Gauthier <mike@silverorange.com>
50 * @copyright 2005-2010 silverorange
51 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
52 * @version CVS: $Id: GPG.php 302814 2010-08-26 15:43:07Z gauthierm $
53 * @link http://pear.php.net/package/Crypt_GPG
54 * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php
55 * @link http://www.gnupg.org/
59 * Signature handler class
61 require_once 'Crypt/GPG/VerifyStatusHandler.php';
64 * Decryption handler class
66 require_once 'Crypt/GPG/DecryptStatusHandler.php';
71 require_once 'Crypt/GPG/Key.php';
76 require_once 'Crypt/GPG/SubKey.php';
81 require_once 'Crypt/GPG/UserId.php';
84 * GPG process and I/O engine class
86 require_once 'Crypt/GPG/Engine.php';
89 * GPG exception classes
91 require_once 'Crypt/GPG/Exceptions.php';
93 // {{{ class Crypt_GPG
96 * A class to use GPG from PHP
98 * This class provides an object oriented interface to GNU Privacy Guard (GPG).
100 * Though GPG can support symmetric-key cryptography, this class is intended
101 * only to facilitate public-key cryptography.
103 * @category Encryption
105 * @author Nathan Fredrickson <nathan@silverorange.com>
106 * @author Michael Gauthier <mike@silverorange.com>
107 * @copyright 2005-2010 silverorange
108 * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
109 * @link http://pear.php.net/package/Crypt_GPG
110 * @link http://www.gnupg.org/
114 // {{{ class error constants
117 * Error code returned when there is no error.
119 const ERROR_NONE = 0;
122 * Error code returned when an unknown or unhandled error occurs.
124 const ERROR_UNKNOWN = 1;
127 * Error code returned when a bad passphrase is used.
129 const ERROR_BAD_PASSPHRASE = 2;
132 * Error code returned when a required passphrase is missing.
134 const ERROR_MISSING_PASSPHRASE = 3;
137 * Error code returned when a key that is already in the keyring is
140 const ERROR_DUPLICATE_KEY = 4;
143 * Error code returned the required data is missing for an operation.
145 * This could be missing key data, missing encrypted data or missing
148 const ERROR_NO_DATA = 5;
151 * Error code returned when an unsigned key is used.
153 const ERROR_UNSIGNED_KEY = 6;
156 * Error code returned when a key that is not self-signed is used.
158 const ERROR_NOT_SELF_SIGNED = 7;
161 * Error code returned when a public or private key that is not in the
164 const ERROR_KEY_NOT_FOUND = 8;
167 * Error code returned when an attempt to delete public key having a
168 * private key is made.
170 const ERROR_DELETE_PRIVATE_KEY = 9;
173 * Error code returned when one or more bad signatures are detected.
175 const ERROR_BAD_SIGNATURE = 10;
178 * Error code returned when there is a problem reading GnuPG data files.
180 const ERROR_FILE_PERMISSIONS = 11;
183 // {{{ class constants for data signing modes
186 * Signing mode for normal signing of data. The signed message will not
187 * be readable without special software.
189 * This is the default signing mode.
191 * @see Crypt_GPG::sign()
192 * @see Crypt_GPG::signFile()
194 const SIGN_MODE_NORMAL = 1;
197 * Signing mode for clearsigning data. Clearsigned signatures are ASCII
198 * armored data and are readable without special software. If the signed
199 * message is unencrypted, the message will still be readable. The message
200 * text will be in the original encoding.
202 * @see Crypt_GPG::sign()
203 * @see Crypt_GPG::signFile()
205 const SIGN_MODE_CLEAR = 2;
208 * Signing mode for creating a detached signature. When using detached
209 * signatures, only the signature data is returned. The original message
210 * text may be distributed separately from the signature data. This is
211 * useful for miltipart/signed email messages as per
212 * {@link http://www.ietf.org/rfc/rfc3156.txt RFC 3156}.
214 * @see Crypt_GPG::sign()
215 * @see Crypt_GPG::signFile()
217 const SIGN_MODE_DETACHED = 3;
220 // {{{ class constants for fingerprint formats
223 * No formatting is performed.
225 * Example: C3BC615AD9C766E5A85C1F2716D27458B1BBA1C4
227 * @see Crypt_GPG::getFingerprint()
229 const FORMAT_NONE = 1;
232 * Fingerprint is formatted in the format used by the GnuPG gpg command's
235 * Example: C3BC 615A D9C7 66E5 A85C 1F27 16D2 7458 B1BB A1C4
237 * @see Crypt_GPG::getFingerprint()
239 const FORMAT_CANONICAL = 2;
242 * Fingerprint is formatted in the format used when displaying X.509
245 * Example: C3:BC:61:5A:D9:C7:66:E5:A8:5C:1F:27:16:D2:74:58:B1:BB:A1:C4
247 * @see Crypt_GPG::getFingerprint()
249 const FORMAT_X509 = 3;
252 // {{{ other class constants
255 * URI at which package bugs may be reported.
257 const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG';
260 // {{{ protected class properties
263 * Engine used to control the GPG subprocess
265 * @var Crypt_GPG_Engine
267 * @see Crypt_GPG::setEngine()
269 protected $engine = null;
272 * Keys used to encrypt
274 * The array is of the form:
278 * 'fingerprint' => $fingerprint,
279 * 'passphrase' => null
285 * @see Crypt_GPG::addEncryptKey()
286 * @see Crypt_GPG::clearEncryptKeys()
288 protected $encryptKeys = array();
291 * Keys used to decrypt
293 * The array is of the form:
297 * 'fingerprint' => $fingerprint,
298 * 'passphrase' => $passphrase
304 * @see Crypt_GPG::addSignKey()
305 * @see Crypt_GPG::clearSignKeys()
307 protected $signKeys = array();
312 * The array is of the form:
316 * 'fingerprint' => $fingerprint,
317 * 'passphrase' => $passphrase
323 * @see Crypt_GPG::addDecryptKey()
324 * @see Crypt_GPG::clearDecryptKeys()
326 protected $decryptKeys = array();
332 * Creates a new GPG object
334 * Available options are:
336 * - <kbd>string homedir</kbd> - the directory where the GPG
337 * keyring files are stored. If not
338 * specified, Crypt_GPG uses the
339 * default of <kbd>~/.gnupg</kbd>.
340 * - <kbd>string publicKeyring</kbd> - the file path of the public
341 * keyring. Use this if the public
342 * keyring is not in the homedir, or
343 * if the keyring is in a directory
344 * not writable by the process
345 * invoking GPG (like Apache). Then
346 * you can specify the path to the
347 * keyring with this option
348 * (/foo/bar/pubring.gpg), and specify
349 * a writable directory (like /tmp)
350 * using the <i>homedir</i> option.
351 * - <kbd>string privateKeyring</kbd> - the file path of the private
352 * keyring. Use this if the private
353 * keyring is not in the homedir, or
354 * if the keyring is in a directory
355 * not writable by the process
356 * invoking GPG (like Apache). Then
357 * you can specify the path to the
358 * keyring with this option
359 * (/foo/bar/secring.gpg), and specify
360 * a writable directory (like /tmp)
361 * using the <i>homedir</i> option.
362 * - <kbd>string trustDb</kbd> - the file path of the web-of-trust
363 * database. Use this if the trust
364 * database is not in the homedir, or
365 * if the database is in a directory
366 * not writable by the process
367 * invoking GPG (like Apache). Then
368 * you can specify the path to the
369 * trust database with this option
370 * (/foo/bar/trustdb.gpg), and specify
371 * a writable directory (like /tmp)
372 * using the <i>homedir</i> option.
373 * - <kbd>string binary</kbd> - the location of the GPG binary. If
374 * not specified, the driver attempts
375 * to auto-detect the GPG binary
376 * location using a list of known
377 * default locations for the current
378 * operating system. The option
379 * <kbd>gpgBinary</kbd> is a
380 * deprecated alias for this option.
381 * - <kbd>boolean debug</kbd> - whether or not to use debug mode.
382 * When debug mode is on, all
383 * communication to and from the GPG
384 * subprocess is logged. This can be
386 * @param array $options optional. An array of options used to create the
387 * GPG object. All options are optional and are
388 * represented as key-value pairs.
390 * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist
391 * and cannot be created. This can happen if <kbd>homedir</kbd> is
392 * not specified, Crypt_GPG is run as the web user, and the web
393 * user has no home directory. This exception is also thrown if any
394 * of the options <kbd>publicKeyring</kbd>,
395 * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are
396 * specified but the files do not exist or are are not readable.
397 * This can happen if the user running the Crypt_GPG process (for
398 * example, the Apache user) does not have permission to read the
401 * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or
402 * if no <kbd>binary</kbd> is provided and no suitable binary could
405 public function __construct(array $options = array())
407 $this->setEngine(new Crypt_GPG_Engine($options));
414 * Imports a public or private key into the keyring
416 * Keys may be removed from the keyring using
417 * {@link Crypt_GPG::deletePublicKey()} or
418 * {@link Crypt_GPG::deletePrivateKey()}.
420 * @param string $data the key data to be imported.
422 * @return array an associative array containing the following elements:
423 * - <kbd>fingerprint</kbd> - the fingerprint of the
425 * - <kbd>public_imported</kbd> - the number of public
427 * - <kbd>public_unchanged</kbd> - the number of unchanged
429 * - <kbd>private_imported</kbd> - the number of private
431 * - <kbd>private_unchanged</kbd> - the number of unchanged
434 * @throws Crypt_GPG_NoDataException if the key data is missing or if the
435 * data is is not valid key data.
437 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
438 * Use the <kbd>debug</kbd> option and file a bug report if these
441 public function importKey($data)
443 return $this->_importKey($data, false);
447 // {{{ importKeyFile()
450 * Imports a public or private key file into the keyring
452 * Keys may be removed from the keyring using
453 * {@link Crypt_GPG::deletePublicKey()} or
454 * {@link Crypt_GPG::deletePrivateKey()}.
456 * @param string $filename the key file to be imported.
458 * @return array an associative array containing the following elements:
459 * - <kbd>fingerprint</kbd> - the fingerprint of the
461 * - <kbd>public_imported</kbd> - the number of public
463 * - <kbd>public_unchanged</kbd> - the number of unchanged
465 * - <kbd>private_imported</kbd> - the number of private
467 * - <kbd>private_unchanged</kbd> - the number of unchanged
471 * @throws Crypt_GPG_NoDataException if the key data is missing or if the
472 * data is is not valid key data.
474 * @throws Crypt_GPG_FileException if the key file is not readable.
476 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
477 * Use the <kbd>debug</kbd> option and file a bug report if these
480 public function importKeyFile($filename)
482 return $this->_importKey($filename, true);
486 // {{{ exportPublicKey()
489 * Exports a public key from the keyring
491 * The exported key remains on the keyring. To delete the public key, use
492 * {@link Crypt_GPG::deletePublicKey()}.
494 * If more than one key fingerprint is available for the specified
495 * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
496 * first public key is exported.
498 * @param string $keyId either the full uid of the public key, the email
499 * part of the uid of the public key or the key id of
500 * the public key. For example,
501 * "Test User (example) <test@example.com>",
502 * "test@example.com" or a hexadecimal string.
503 * @param boolean $armor optional. If true, ASCII armored data is returned;
504 * otherwise, binary data is returned. Defaults to
507 * @return string the public key data.
509 * @throws Crypt_GPG_KeyNotFoundException if a public key with the given
510 * <kbd>$keyId</kbd> is not found.
512 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
513 * Use the <kbd>debug</kbd> option and file a bug report if these
516 public function exportPublicKey($keyId, $armor = true)
518 $fingerprint = $this->getFingerprint($keyId);
520 if ($fingerprint === null) {
521 throw new Crypt_GPG_KeyNotFoundException(
522 'Public key not found: ' . $keyId,
523 Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
527 $operation = '--export ' . escapeshellarg($fingerprint);
528 $arguments = ($armor) ? array('--armor') : array();
530 $this->engine->reset();
531 $this->engine->setOutput($keyData);
532 $this->engine->setOperation($operation, $arguments);
533 $this->engine->run();
535 $code = $this->engine->getErrorCode();
537 if ($code !== Crypt_GPG::ERROR_NONE) {
538 throw new Crypt_GPG_Exception(
539 'Unknown error exporting public key. Please use the ' .
540 '\'debug\' option when creating the Crypt_GPG object, and ' .
541 'file a bug report at ' . self::BUG_URI, $code);
548 // {{{ deletePublicKey()
551 * Deletes a public key from the keyring
553 * If more than one key fingerprint is available for the specified
554 * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
555 * first public key is deleted.
557 * The private key must be deleted first or an exception will be thrown.
558 * See {@link Crypt_GPG::deletePrivateKey()}.
560 * @param string $keyId either the full uid of the public key, the email
561 * part of the uid of the public key or the key id of
562 * the public key. For example,
563 * "Test User (example) <test@example.com>",
564 * "test@example.com" or a hexadecimal string.
568 * @throws Crypt_GPG_KeyNotFoundException if a public key with the given
569 * <kbd>$keyId</kbd> is not found.
571 * @throws Crypt_GPG_DeletePrivateKeyException if the specified public key
572 * has an associated private key on the keyring. The private key
573 * must be deleted first.
575 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
576 * Use the <kbd>debug</kbd> option and file a bug report if these
579 public function deletePublicKey($keyId)
581 $fingerprint = $this->getFingerprint($keyId);
583 if ($fingerprint === null) {
584 throw new Crypt_GPG_KeyNotFoundException(
585 'Public key not found: ' . $keyId,
586 Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
589 $operation = '--delete-key ' . escapeshellarg($fingerprint);
595 $this->engine->reset();
596 $this->engine->setOperation($operation, $arguments);
597 $this->engine->run();
599 $code = $this->engine->getErrorCode();
602 case Crypt_GPG::ERROR_NONE:
604 case Crypt_GPG::ERROR_DELETE_PRIVATE_KEY:
605 throw new Crypt_GPG_DeletePrivateKeyException(
606 'Private key must be deleted before public key can be ' .
607 'deleted.', $code, $keyId);
609 throw new Crypt_GPG_Exception(
610 'Unknown error deleting public key. Please use the ' .
611 '\'debug\' option when creating the Crypt_GPG object, and ' .
612 'file a bug report at ' . self::BUG_URI, $code);
617 // {{{ deletePrivateKey()
620 * Deletes a private key from the keyring
622 * If more than one key fingerprint is available for the specified
623 * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
624 * first private key is deleted.
626 * Calls GPG with the <kbd>--delete-secret-key</kbd> command.
628 * @param string $keyId either the full uid of the private key, the email
629 * part of the uid of the private key or the key id of
630 * the private key. For example,
631 * "Test User (example) <test@example.com>",
632 * "test@example.com" or a hexadecimal string.
636 * @throws Crypt_GPG_KeyNotFoundException if a private key with the given
637 * <kbd>$keyId</kbd> is not found.
639 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
640 * Use the <kbd>debug</kbd> option and file a bug report if these
643 public function deletePrivateKey($keyId)
645 $fingerprint = $this->getFingerprint($keyId);
647 if ($fingerprint === null) {
648 throw new Crypt_GPG_KeyNotFoundException(
649 'Private key not found: ' . $keyId,
650 Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
653 $operation = '--delete-secret-key ' . escapeshellarg($fingerprint);
659 $this->engine->reset();
660 $this->engine->setOperation($operation, $arguments);
661 $this->engine->run();
663 $code = $this->engine->getErrorCode();
666 case Crypt_GPG::ERROR_NONE:
668 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
669 throw new Crypt_GPG_KeyNotFoundException(
670 'Private key not found: ' . $keyId,
673 throw new Crypt_GPG_Exception(
674 'Unknown error deleting private key. Please use the ' .
675 '\'debug\' option when creating the Crypt_GPG object, and ' .
676 'file a bug report at ' . self::BUG_URI, $code);
684 * Gets the available keys in the keyring
686 * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See
687 * the first section of <b>doc/DETAILS</b> in the
688 * {@link http://www.gnupg.org/download/ GPG package} for a detailed
689 * description of how the GPG command output is parsed.
691 * @param string $keyId optional. Only keys with that match the specified
692 * pattern are returned. The pattern may be part of
693 * a user id, a key id or a key fingerprint. If not
694 * specified, all keys are returned.
696 * @return array an array of {@link Crypt_GPG_Key} objects. If no keys
697 * match the specified <kbd>$keyId</kbd> an empty array is
700 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
701 * Use the <kbd>debug</kbd> option and file a bug report if these
706 public function getKeys($keyId = '')
708 // get private key fingerprints
710 $operation = '--list-secret-keys';
712 $operation = '--list-secret-keys ' . escapeshellarg($keyId);
715 // According to The file 'doc/DETAILS' in the GnuPG distribution, using
716 // double '--with-fingerprint' also prints the fingerprint for subkeys.
719 '--with-fingerprint',
720 '--with-fingerprint',
726 $this->engine->reset();
727 $this->engine->setOutput($output);
728 $this->engine->setOperation($operation, $arguments);
729 $this->engine->run();
731 $code = $this->engine->getErrorCode();
734 case Crypt_GPG::ERROR_NONE:
735 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
736 // ignore not found key errors
738 case Crypt_GPG::ERROR_FILE_PERMISSIONS:
739 $filename = $this->engine->getErrorFilename();
741 throw new Crypt_GPG_FileException(sprintf(
742 'Error reading GnuPG data file \'%s\'. Check to make ' .
743 'sure it is readable by the current user.', $filename),
746 throw new Crypt_GPG_FileException(
747 'Error reading GnuPG data file. Check to make GnuPG data ' .
748 'files are readable by the current user.', $code);
750 throw new Crypt_GPG_Exception(
751 'Unknown error getting keys. Please use the \'debug\' option ' .
752 'when creating the Crypt_GPG object, and file a bug report ' .
753 'at ' . self::BUG_URI, $code);
756 $privateKeyFingerprints = array();
758 $lines = explode(PHP_EOL, $output);
759 foreach ($lines as $line) {
760 $lineExp = explode(':', $line);
761 if ($lineExp[0] == 'fpr') {
762 $privateKeyFingerprints[] = $lineExp[9];
768 $operation = '--list-public-keys';
770 $operation = '--list-public-keys ' . escapeshellarg($keyId);
775 $this->engine->reset();
776 $this->engine->setOutput($output);
777 $this->engine->setOperation($operation, $arguments);
778 $this->engine->run();
780 $code = $this->engine->getErrorCode();
783 case Crypt_GPG::ERROR_NONE:
784 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
785 // ignore not found key errors
787 case Crypt_GPG::ERROR_FILE_PERMISSIONS:
788 $filename = $this->engine->getErrorFilename();
790 throw new Crypt_GPG_FileException(sprintf(
791 'Error reading GnuPG data file \'%s\'. Check to make ' .
792 'sure it is readable by the current user.', $filename),
795 throw new Crypt_GPG_FileException(
796 'Error reading GnuPG data file. Check to make GnuPG data ' .
797 'files are readable by the current user.', $code);
799 throw new Crypt_GPG_Exception(
800 'Unknown error getting keys. Please use the \'debug\' option ' .
801 'when creating the Crypt_GPG object, and file a bug report ' .
802 'at ' . self::BUG_URI, $code);
807 $key = null; // current key
808 $subKey = null; // current sub-key
810 $lines = explode(PHP_EOL, $output);
811 foreach ($lines as $line) {
812 $lineExp = explode(':', $line);
814 if ($lineExp[0] == 'pub') {
816 // new primary key means last key should be added to the array
821 $key = new Crypt_GPG_Key();
823 $subKey = Crypt_GPG_SubKey::parse($line);
824 $key->addSubKey($subKey);
826 } elseif ($lineExp[0] == 'sub') {
828 $subKey = Crypt_GPG_SubKey::parse($line);
829 $key->addSubKey($subKey);
831 } elseif ($lineExp[0] == 'fpr') {
833 $fingerprint = $lineExp[9];
835 // set current sub-key fingerprint
836 $subKey->setFingerprint($fingerprint);
838 // if private key exists, set has private to true
839 if (in_array($fingerprint, $privateKeyFingerprints)) {
840 $subKey->setHasPrivate(true);
843 } elseif ($lineExp[0] == 'uid') {
845 $string = stripcslashes($lineExp[9]); // as per documentation
846 $userId = new Crypt_GPG_UserId($string);
848 if ($lineExp[1] == 'r') {
849 $userId->setRevoked(true);
852 $key->addUserId($userId);
866 // {{{ getFingerprint()
869 * Gets a key fingerprint from the keyring
871 * If more than one key fingerprint is available (for example, if you use
872 * a non-unique user id) only the first key fingerprint is returned.
874 * Calls the GPG <kbd>--list-keys</kbd> command with the
875 * <kbd>--with-fingerprint</kbd> option to retrieve a public key
878 * @param string $keyId either the full user id of the key, the email
879 * part of the user id of the key, or the key id of
880 * the key. For example,
881 * "Test User (example) <test@example.com>",
882 * "test@example.com" or a hexadecimal string.
883 * @param integer $format optional. How the fingerprint should be formatted.
884 * Use {@link Crypt_GPG::FORMAT_X509} for X.509
885 * certificate format,
886 * {@link Crypt_GPG::FORMAT_CANONICAL} for the format
887 * used by GnuPG output and
888 * {@link Crypt_GPG::FORMAT_NONE} for no formatting.
889 * Defaults to <code>Crypt_GPG::FORMAT_NONE</code>.
891 * @return string the fingerprint of the key, or null if no fingerprint
892 * is found for the given <kbd>$keyId</kbd>.
894 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
895 * Use the <kbd>debug</kbd> option and file a bug report if these
898 public function getFingerprint($keyId, $format = Crypt_GPG::FORMAT_NONE)
901 $operation = '--list-keys ' . escapeshellarg($keyId);
907 $this->engine->reset();
908 $this->engine->setOutput($output);
909 $this->engine->setOperation($operation, $arguments);
910 $this->engine->run();
912 $code = $this->engine->getErrorCode();
915 case Crypt_GPG::ERROR_NONE:
916 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
917 // ignore not found key errors
920 throw new Crypt_GPG_Exception(
921 'Unknown error getting key fingerprint. Please use the ' .
922 '\'debug\' option when creating the Crypt_GPG object, and ' .
923 'file a bug report at ' . self::BUG_URI, $code);
928 $lines = explode(PHP_EOL, $output);
929 foreach ($lines as $line) {
930 if (substr($line, 0, 3) == 'fpr') {
931 $lineExp = explode(':', $line);
932 $fingerprint = $lineExp[9];
935 case Crypt_GPG::FORMAT_CANONICAL:
936 $fingerprintExp = str_split($fingerprint, 4);
937 $format = '%s %s %s %s %s %s %s %s %s %s';
938 $fingerprint = vsprintf($format, $fingerprintExp);
941 case Crypt_GPG::FORMAT_X509:
942 $fingerprintExp = str_split($fingerprint, 2);
943 $fingerprint = implode(':', $fingerprintExp);
958 * Encrypts string data
960 * Data is ASCII armored by default but may optionally be returned as
963 * @param string $data the data to be encrypted.
964 * @param boolean $armor optional. If true, ASCII armored data is returned;
965 * otherwise, binary data is returned. Defaults to
968 * @return string the encrypted data.
970 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
971 * See {@link Crypt_GPG::addEncryptKey()}.
973 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
974 * Use the <kbd>debug</kbd> option and file a bug report if these
979 public function encrypt($data, $armor = true)
981 return $this->_encrypt($data, false, null, $armor);
990 * Encrypted data is ASCII armored by default but may optionally be saved
993 * @param string $filename the filename of the file to encrypt.
994 * @param string $encryptedFile optional. The filename of the file in
995 * which to store the encrypted data. If null
996 * or unspecified, the encrypted data is
997 * returned as a string.
998 * @param boolean $armor optional. If true, ASCII armored data is
999 * returned; otherwise, binary data is
1000 * returned. Defaults to true.
1002 * @return void|string if the <kbd>$encryptedFile</kbd> parameter is null,
1003 * a string containing the encrypted data is returned.
1005 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
1006 * See {@link Crypt_GPG::addEncryptKey()}.
1008 * @throws Crypt_GPG_FileException if the output file is not writeable or
1009 * if the input file is not readable.
1011 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1012 * Use the <kbd>debug</kbd> option and file a bug report if these
1015 public function encryptFile($filename, $encryptedFile = null, $armor = true)
1017 return $this->_encrypt($filename, true, $encryptedFile, $armor);
1021 // {{{ encryptAndSign()
1024 * Encrypts and signs data
1026 * Data is encrypted and signed in a single pass.
1028 * NOTE: Until GnuPG version 1.4.10, it was not possible to verify
1029 * encrypted-signed data without decrypting it at the same time. If you try
1030 * to use {@link Crypt_GPG::verify()} method on encrypted-signed data with
1031 * earlier GnuPG versions, you will get an error. Please use
1032 * {@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data.
1034 * @param string $data the data to be encrypted and signed.
1035 * @param boolean $armor optional. If true, ASCII armored data is returned;
1036 * otherwise, binary data is returned. Defaults to
1039 * @return string the encrypted signed data.
1041 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
1042 * or if no signing key is specified. See
1043 * {@link Crypt_GPG::addEncryptKey()} and
1044 * {@link Crypt_GPG::addSignKey()}.
1046 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
1047 * incorrect or if a required passphrase is not specified.
1049 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1050 * Use the <kbd>debug</kbd> option and file a bug report if these
1053 * @see Crypt_GPG::decryptAndVerify()
1055 public function encryptAndSign($data, $armor = true)
1057 return $this->_encryptAndSign($data, false, null, $armor);
1061 // {{{ encryptAndSignFile()
1064 * Encrypts and signs a file
1066 * The file is encrypted and signed in a single pass.
1068 * NOTE: Until GnuPG version 1.4.10, it was not possible to verify
1069 * encrypted-signed files without decrypting them at the same time. If you
1070 * try to use {@link Crypt_GPG::verify()} method on encrypted-signed files
1071 * with earlier GnuPG versions, you will get an error. Please use
1072 * {@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed
1075 * @param string $filename the name of the file containing the data to
1076 * be encrypted and signed.
1077 * @param string $signedFile optional. The name of the file in which the
1078 * encrypted, signed data should be stored. If
1079 * null or unspecified, the encrypted, signed
1080 * data is returned as a string.
1081 * @param boolean $armor optional. If true, ASCII armored data is
1082 * returned; otherwise, binary data is returned.
1085 * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a
1086 * string containing the encrypted, signed data is
1089 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
1090 * or if no signing key is specified. See
1091 * {@link Crypt_GPG::addEncryptKey()} and
1092 * {@link Crypt_GPG::addSignKey()}.
1094 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
1095 * incorrect or if a required passphrase is not specified.
1097 * @throws Crypt_GPG_FileException if the output file is not writeable or
1098 * if the input file is not readable.
1100 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1101 * Use the <kbd>debug</kbd> option and file a bug report if these
1104 * @see Crypt_GPG::decryptAndVerifyFile()
1106 public function encryptAndSignFile($filename, $signedFile = null,
1109 return $this->_encryptAndSign($filename, true, $signedFile, $armor);
1116 * Decrypts string data
1118 * This method assumes the required private key is available in the keyring
1119 * and throws an exception if the private key is not available. To add a
1120 * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
1121 * {@link Crypt_GPG::importKeyFile()} methods.
1123 * @param string $encryptedData the data to be decrypted.
1125 * @return string the decrypted data.
1127 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
1128 * decrypt the data is not in the user's keyring.
1130 * @throws Crypt_GPG_NoDataException if specified data does not contain
1131 * GPG encrypted data.
1133 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
1134 * incorrect or if a required passphrase is not specified. See
1135 * {@link Crypt_GPG::addDecryptKey()}.
1137 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1138 * Use the <kbd>debug</kbd> option and file a bug report if these
1141 public function decrypt($encryptedData)
1143 return $this->_decrypt($encryptedData, false, null);
1147 // {{{ decryptFile()
1152 * This method assumes the required private key is available in the keyring
1153 * and throws an exception if the private key is not available. To add a
1154 * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
1155 * {@link Crypt_GPG::importKeyFile()} methods.
1157 * @param string $encryptedFile the name of the encrypted file data to
1159 * @param string $decryptedFile optional. The name of the file to which the
1160 * decrypted data should be written. If null
1161 * or unspecified, the decrypted data is
1162 * returned as a string.
1164 * @return void|string if the <kbd>$decryptedFile</kbd> parameter is null,
1165 * a string containing the decrypted data is returned.
1167 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
1168 * decrypt the data is not in the user's keyring.
1170 * @throws Crypt_GPG_NoDataException if specified data does not contain
1171 * GPG encrypted data.
1173 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
1174 * incorrect or if a required passphrase is not specified. See
1175 * {@link Crypt_GPG::addDecryptKey()}.
1177 * @throws Crypt_GPG_FileException if the output file is not writeable or
1178 * if the input file is not readable.
1180 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1181 * Use the <kbd>debug</kbd> option and file a bug report if these
1184 public function decryptFile($encryptedFile, $decryptedFile = null)
1186 return $this->_decrypt($encryptedFile, true, $decryptedFile);
1190 // {{{ decryptAndVerify()
1193 * Decrypts and verifies string data
1195 * This method assumes the required private key is available in the keyring
1196 * and throws an exception if the private key is not available. To add a
1197 * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
1198 * {@link Crypt_GPG::importKeyFile()} methods.
1200 * @param string $encryptedData the encrypted, signed data to be decrypted
1203 * @return array two element array. The array has an element 'data'
1204 * containing the decrypted data and an element
1205 * 'signatures' containing an array of
1206 * {@link Crypt_GPG_Signature} objects for the signed data.
1208 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
1209 * decrypt the data is not in the user's keyring.
1211 * @throws Crypt_GPG_NoDataException if specified data does not contain
1212 * GPG encrypted data.
1214 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
1215 * incorrect or if a required passphrase is not specified. See
1216 * {@link Crypt_GPG::addDecryptKey()}.
1218 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1219 * Use the <kbd>debug</kbd> option and file a bug report if these
1222 public function decryptAndVerify($encryptedData)
1224 return $this->_decryptAndVerify($encryptedData, false, null);
1228 // {{{ decryptAndVerifyFile()
1231 * Decrypts and verifies a signed, encrypted file
1233 * This method assumes the required private key is available in the keyring
1234 * and throws an exception if the private key is not available. To add a
1235 * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
1236 * {@link Crypt_GPG::importKeyFile()} methods.
1238 * @param string $encryptedFile the name of the signed, encrypted file to
1239 * to decrypt and verify.
1240 * @param string $decryptedFile optional. The name of the file to which the
1241 * decrypted data should be written. If null
1242 * or unspecified, the decrypted data is
1243 * returned in the results array.
1245 * @return array two element array. The array has an element 'data'
1246 * containing the decrypted data and an element
1247 * 'signatures' containing an array of
1248 * {@link Crypt_GPG_Signature} objects for the signed data.
1249 * If the decrypted data is written to a file, the 'data'
1252 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
1253 * decrypt the data is not in the user's keyring.
1255 * @throws Crypt_GPG_NoDataException if specified data does not contain
1256 * GPG encrypted data.
1258 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
1259 * incorrect or if a required passphrase is not specified. See
1260 * {@link Crypt_GPG::addDecryptKey()}.
1262 * @throws Crypt_GPG_FileException if the output file is not writeable or
1263 * if the input file is not readable.
1265 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1266 * Use the <kbd>debug</kbd> option and file a bug report if these
1269 public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null)
1271 return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile);
1280 * Data may be signed using any one of the three available signing modes:
1281 * - {@link Crypt_GPG::SIGN_MODE_NORMAL}
1282 * - {@link Crypt_GPG::SIGN_MODE_CLEAR}
1283 * - {@link Crypt_GPG::SIGN_MODE_DETACHED}
1285 * @param string $data the data to be signed.
1286 * @param boolean $mode optional. The data signing mode to use. Should
1287 * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL},
1288 * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
1289 * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not
1290 * specified, defaults to
1291 * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>.
1292 * @param boolean $armor optional. If true, ASCII armored data is
1293 * returned; otherwise, binary data is returned.
1294 * Defaults to true. This has no effect if the
1295 * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
1297 * @param boolean $textmode optional. If true, line-breaks in signed data
1298 * are normalized. Use this option when signing
1299 * e-mail, or for greater compatibility between
1300 * systems with different line-break formats.
1301 * Defaults to false. This has no effect if the
1302 * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
1303 * used as clear-signing always uses textmode.
1305 * @return string the signed data, or the signature data if a detached
1306 * signature is requested.
1308 * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
1309 * See {@link Crypt_GPG::addSignKey()}.
1311 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
1312 * incorrect or if a required passphrase is not specified.
1314 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1315 * Use the <kbd>debug</kbd> option and file a bug report if these
1318 public function sign($data, $mode = Crypt_GPG::SIGN_MODE_NORMAL,
1319 $armor = true, $textmode = false
1321 return $this->_sign($data, false, null, $mode, $armor, $textmode);
1330 * The file may be signed using any one of the three available signing
1332 * - {@link Crypt_GPG::SIGN_MODE_NORMAL}
1333 * - {@link Crypt_GPG::SIGN_MODE_CLEAR}
1334 * - {@link Crypt_GPG::SIGN_MODE_DETACHED}
1336 * @param string $filename the name of the file containing the data to
1338 * @param string $signedFile optional. The name of the file in which the
1339 * signed data should be stored. If null or
1340 * unspecified, the signed data is returned as a
1342 * @param boolean $mode optional. The data signing mode to use. Should
1343 * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL},
1344 * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
1345 * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not
1346 * specified, defaults to
1347 * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>.
1348 * @param boolean $armor optional. If true, ASCII armored data is
1349 * returned; otherwise, binary data is returned.
1350 * Defaults to true. This has no effect if the
1351 * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
1353 * @param boolean $textmode optional. If true, line-breaks in signed data
1354 * are normalized. Use this option when signing
1355 * e-mail, or for greater compatibility between
1356 * systems with different line-break formats.
1357 * Defaults to false. This has no effect if the
1358 * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
1359 * used as clear-signing always uses textmode.
1361 * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a
1362 * string containing the signed data (or the signature
1363 * data if a detached signature is requested) is
1366 * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
1367 * See {@link Crypt_GPG::addSignKey()}.
1369 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
1370 * incorrect or if a required passphrase is not specified.
1372 * @throws Crypt_GPG_FileException if the output file is not writeable or
1373 * if the input file is not readable.
1375 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1376 * Use the <kbd>debug</kbd> option and file a bug report if these
1379 public function signFile($filename, $signedFile = null,
1380 $mode = Crypt_GPG::SIGN_MODE_NORMAL, $armor = true, $textmode = false
1382 return $this->_sign(
1396 * Verifies signed data
1398 * The {@link Crypt_GPG::decrypt()} method may be used to get the original
1399 * message if the signed data is not clearsigned and does not use a
1400 * detached signature.
1402 * @param string $signedData the signed data to be verified.
1403 * @param string $signature optional. If verifying data signed using a
1404 * detached signature, this must be the detached
1405 * signature data. The data that was signed is
1406 * specified in <kbd>$signedData</kbd>.
1408 * @return array an array of {@link Crypt_GPG_Signature} objects for the
1409 * signed data. For each signature that is valid, the
1410 * {@link Crypt_GPG_Signature::isValid()} will return true.
1412 * @throws Crypt_GPG_NoDataException if the provided data is not signed
1415 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1416 * Use the <kbd>debug</kbd> option and file a bug report if these
1419 * @see Crypt_GPG_Signature
1421 public function verify($signedData, $signature = '')
1423 return $this->_verify($signedData, false, $signature);
1430 * Verifies a signed file
1432 * The {@link Crypt_GPG::decryptFile()} method may be used to get the
1433 * original message if the signed data is not clearsigned and does not use
1434 * a detached signature.
1436 * @param string $filename the signed file to be verified.
1437 * @param string $signature optional. If verifying a file signed using a
1438 * detached signature, this must be the detached
1439 * signature data. The file that was signed is
1440 * specified in <kbd>$filename</kbd>.
1442 * @return array an array of {@link Crypt_GPG_Signature} objects for the
1443 * signed data. For each signature that is valid, the
1444 * {@link Crypt_GPG_Signature::isValid()} will return true.
1446 * @throws Crypt_GPG_NoDataException if the provided data is not signed
1449 * @throws Crypt_GPG_FileException if the input file is not readable.
1451 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1452 * Use the <kbd>debug</kbd> option and file a bug report if these
1455 * @see Crypt_GPG_Signature
1457 public function verifyFile($filename, $signature = '')
1459 return $this->_verify($filename, true, $signature);
1463 // {{{ addDecryptKey()
1466 * Adds a key to use for decryption
1468 * @param mixed $key the key to use. This may be a key identifier,
1469 * user id, fingerprint, {@link Crypt_GPG_Key} or
1470 * {@link Crypt_GPG_SubKey}. The key must be able
1472 * @param string $passphrase optional. The passphrase of the key required
1477 * @see Crypt_GPG::decrypt()
1478 * @see Crypt_GPG::decryptFile()
1479 * @see Crypt_GPG::clearDecryptKeys()
1480 * @see Crypt_GPG::_addKey()
1481 * @see Crypt_GPG_DecryptStatusHandler
1483 * @sensitive $passphrase
1485 public function addDecryptKey($key, $passphrase = null)
1487 $this->_addKey($this->decryptKeys, true, false, $key, $passphrase);
1491 // {{{ addEncryptKey()
1494 * Adds a key to use for encryption
1496 * @param mixed $key the key to use. This may be a key identifier, user id
1497 * user id, fingerprint, {@link Crypt_GPG_Key} or
1498 * {@link Crypt_GPG_SubKey}. The key must be able to
1503 * @see Crypt_GPG::encrypt()
1504 * @see Crypt_GPG::encryptFile()
1505 * @see Crypt_GPG::clearEncryptKeys()
1506 * @see Crypt_GPG::_addKey()
1508 public function addEncryptKey($key)
1510 $this->_addKey($this->encryptKeys, true, false, $key);
1517 * Adds a key to use for signing
1519 * @param mixed $key the key to use. This may be a key identifier,
1520 * user id, fingerprint, {@link Crypt_GPG_Key} or
1521 * {@link Crypt_GPG_SubKey}. The key must be able
1523 * @param string $passphrase optional. The passphrase of the key required
1528 * @see Crypt_GPG::sign()
1529 * @see Crypt_GPG::signFile()
1530 * @see Crypt_GPG::clearSignKeys()
1531 * @see Crypt_GPG::handleSignStatus()
1532 * @see Crypt_GPG::_addKey()
1534 * @sensitive $passphrase
1536 public function addSignKey($key, $passphrase = null)
1538 $this->_addKey($this->signKeys, false, true, $key, $passphrase);
1542 // {{{ clearDecryptKeys()
1545 * Clears all decryption keys
1549 * @see Crypt_GPG::decrypt()
1550 * @see Crypt_GPG::addDecryptKey()
1552 public function clearDecryptKeys()
1554 $this->decryptKeys = array();
1558 // {{{ clearEncryptKeys()
1561 * Clears all encryption keys
1565 * @see Crypt_GPG::encrypt()
1566 * @see Crypt_GPG::addEncryptKey()
1568 public function clearEncryptKeys()
1570 $this->encryptKeys = array();
1574 // {{{ clearSignKeys()
1577 * Clears all signing keys
1581 * @see Crypt_GPG::sign()
1582 * @see Crypt_GPG::addSignKey()
1584 public function clearSignKeys()
1586 $this->signKeys = array();
1590 // {{{ handleSignStatus()
1593 * Handles the status output from GPG for the sign operation
1595 * This method is responsible for sending the passphrase commands when
1596 * required by the {@link Crypt_GPG::sign()} method. See <b>doc/DETAILS</b>
1597 * in the {@link http://www.gnupg.org/download/ GPG distribution} for
1598 * detailed information on GPG's status output.
1600 * @param string $line the status line to handle.
1604 * @see Crypt_GPG::sign()
1606 public function handleSignStatus($line)
1608 $tokens = explode(' ', $line);
1609 switch ($tokens[0]) {
1610 case 'NEED_PASSPHRASE':
1611 $subKeyId = $tokens[1];
1612 if (array_key_exists($subKeyId, $this->signKeys)) {
1613 $passphrase = $this->signKeys[$subKeyId]['passphrase'];
1614 $this->engine->sendCommand($passphrase);
1616 $this->engine->sendCommand('');
1623 // {{{ handleImportKeyStatus()
1626 * Handles the status output from GPG for the import operation
1628 * This method is responsible for building the result array that is
1629 * returned from the {@link Crypt_GPG::importKey()} method. See
1630 * <b>doc/DETAILS</b> in the
1631 * {@link http://www.gnupg.org/download/ GPG distribution} for detailed
1632 * information on GPG's status output.
1634 * @param string $line the status line to handle.
1635 * @param array &$result the current result array being processed.
1639 * @see Crypt_GPG::importKey()
1640 * @see Crypt_GPG::importKeyFile()
1641 * @see Crypt_GPG_Engine::addStatusHandler()
1643 public function handleImportKeyStatus($line, array &$result)
1645 $tokens = explode(' ', $line);
1646 switch ($tokens[0]) {
1648 $result['fingerprint'] = $tokens[2];
1652 $result['public_imported'] = intval($tokens[3]);
1653 $result['public_unchanged'] = intval($tokens[5]);
1654 $result['private_imported'] = intval($tokens[11]);
1655 $result['private_unchanged'] = intval($tokens[12]);
1664 * Sets the I/O engine to use for GnuPG operations
1666 * Normally this method does not need to be used. It provides a means for
1667 * dependency injection.
1669 * @param Crypt_GPG_Engine $engine the engine to use.
1673 public function setEngine(Crypt_GPG_Engine $engine)
1675 $this->engine = $engine;
1682 * Adds a key to one of the internal key arrays
1684 * This handles resolving full key objects from the provided
1685 * <kbd>$key</kbd> value.
1687 * @param array &$array the array to which the key should be added.
1688 * @param boolean $encrypt whether or not the key must be able to
1690 * @param boolean $sign whether or not the key must be able to sign.
1691 * @param mixed $key the key to add. This may be a key identifier,
1692 * user id, fingerprint, {@link Crypt_GPG_Key} or
1693 * {@link Crypt_GPG_SubKey}.
1694 * @param string $passphrase optional. The passphrase associated with the
1699 * @sensitive $passphrase
1701 private function _addKey(array &$array, $encrypt, $sign, $key,
1706 if (is_scalar($key)) {
1707 $keys = $this->getKeys($key);
1708 if (count($keys) == 0) {
1709 throw new Crypt_GPG_KeyNotFoundException(
1710 'Key "' . $key . '" not found.', 0, $key);
1715 if ($key instanceof Crypt_GPG_Key) {
1716 if ($encrypt && !$key->canEncrypt()) {
1717 throw new InvalidArgumentException(
1718 'Key "' . $key . '" cannot encrypt.');
1721 if ($sign && !$key->canSign()) {
1722 throw new InvalidArgumentException(
1723 'Key "' . $key . '" cannot sign.');
1726 foreach ($key->getSubKeys() as $subKey) {
1727 $canEncrypt = $subKey->canEncrypt();
1728 $canSign = $subKey->canSign();
1729 if ( ($encrypt && $sign && $canEncrypt && $canSign)
1730 || ($encrypt && !$sign && $canEncrypt)
1731 || (!$encrypt && $sign && $canSign)
1733 // We add all subkeys that meet the requirements because we
1734 // were not told which subkey is required.
1735 $subKeys[] = $subKey;
1738 } elseif ($key instanceof Crypt_GPG_SubKey) {
1742 if (count($subKeys) === 0) {
1743 throw new InvalidArgumentException(
1744 'Key "' . $key . '" is not in a recognized format.');
1747 foreach ($subKeys as $subKey) {
1748 if ($encrypt && !$subKey->canEncrypt()) {
1749 throw new InvalidArgumentException(
1750 'Key "' . $key . '" cannot encrypt.');
1753 if ($sign && !$subKey->canSign()) {
1754 throw new InvalidArgumentException(
1755 'Key "' . $key . '" cannot sign.');
1758 $array[$subKey->getId()] = array(
1759 'fingerprint' => $subKey->getFingerprint(),
1760 'passphrase' => $passphrase
1769 * Imports a public or private key into the keyring
1771 * @param string $key the key to be imported.
1772 * @param boolean $isFile whether or not the input is a filename.
1774 * @return array an associative array containing the following elements:
1775 * - <kbd>fingerprint</kbd> - the fingerprint of the
1777 * - <kbd>public_imported</kbd> - the number of public
1779 * - <kbd>public_unchanged</kbd> - the number of unchanged
1781 * - <kbd>private_imported</kbd> - the number of private
1783 * - <kbd>private_unchanged</kbd> - the number of unchanged
1786 * @throws Crypt_GPG_NoDataException if the key data is missing or if the
1787 * data is is not valid key data.
1789 * @throws Crypt_GPG_FileException if the key file is not readable.
1791 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1792 * Use the <kbd>debug</kbd> option and file a bug report if these
1795 private function _importKey($key, $isFile)
1800 $input = @fopen($key, 'rb');
1801 if ($input === false) {
1802 throw new Crypt_GPG_FileException('Could not open key file "' .
1803 $key . '" for importing.', 0, $key);
1806 $input = strval($key);
1808 throw new Crypt_GPG_NoDataException(
1809 'No valid GPG key data found.', Crypt_GPG::ERROR_NO_DATA);
1813 $arguments = array();
1814 $version = $this->engine->getVersion();
1816 if ( version_compare($version, '1.0.5', 'ge')
1817 && version_compare($version, '1.0.7', 'lt')
1819 $arguments[] = '--allow-secret-key-import';
1822 $this->engine->reset();
1823 $this->engine->addStatusHandler(
1824 array($this, 'handleImportKeyStatus'),
1828 $this->engine->setOperation('--import', $arguments);
1829 $this->engine->setInput($input);
1830 $this->engine->run();
1836 $code = $this->engine->getErrorCode();
1839 case Crypt_GPG::ERROR_DUPLICATE_KEY:
1840 case Crypt_GPG::ERROR_NONE:
1841 // ignore duplicate key import errors
1843 case Crypt_GPG::ERROR_NO_DATA:
1844 throw new Crypt_GPG_NoDataException(
1845 'No valid GPG key data found.', $code);
1847 throw new Crypt_GPG_Exception(
1848 'Unknown error importing GPG key. Please use the \'debug\' ' .
1849 'option when creating the Crypt_GPG object, and file a bug ' .
1850 'report at ' . self::BUG_URI, $code);
1862 * @param string $data the data to encrypt.
1863 * @param boolean $isFile whether or not the data is a filename.
1864 * @param string $outputFile the filename of the file in which to store
1865 * the encrypted data. If null, the encrypted
1866 * data is returned as a string.
1867 * @param boolean $armor if true, ASCII armored data is returned;
1868 * otherwise, binary data is returned.
1870 * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
1871 * string containing the encrypted data is returned.
1873 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
1874 * See {@link Crypt_GPG::addEncryptKey()}.
1876 * @throws Crypt_GPG_FileException if the output file is not writeable or
1877 * if the input file is not readable.
1879 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1880 * Use the <kbd>debug</kbd> option and file a bug report if these
1883 private function _encrypt($data, $isFile, $outputFile, $armor)
1885 if (count($this->encryptKeys) === 0) {
1886 throw new Crypt_GPG_KeyNotFoundException(
1887 'No encryption keys specified.');
1891 $input = @fopen($data, 'rb');
1892 if ($input === false) {
1893 throw new Crypt_GPG_FileException('Could not open input file "' .
1894 $data . '" for encryption.', 0, $data);
1897 $input = strval($data);
1900 if ($outputFile === null) {
1903 $output = @fopen($outputFile, 'wb');
1904 if ($output === false) {
1908 throw new Crypt_GPG_FileException('Could not open output ' .
1909 'file "' . $outputFile . '" for storing encrypted data.',
1914 $arguments = ($armor) ? array('--armor') : array();
1915 foreach ($this->encryptKeys as $key) {
1916 $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']);
1919 $this->engine->reset();
1920 $this->engine->setInput($input);
1921 $this->engine->setOutput($output);
1922 $this->engine->setOperation('--encrypt', $arguments);
1923 $this->engine->run();
1929 if ($outputFile !== null) {
1933 $code = $this->engine->getErrorCode();
1935 if ($code !== Crypt_GPG::ERROR_NONE) {
1936 throw new Crypt_GPG_Exception(
1937 'Unknown error encrypting data. Please use the \'debug\' ' .
1938 'option when creating the Crypt_GPG object, and file a bug ' .
1939 'report at ' . self::BUG_URI, $code);
1942 if ($outputFile === null) {
1953 * @param string $data the data to be decrypted.
1954 * @param boolean $isFile whether or not the data is a filename.
1955 * @param string $outputFile the name of the file to which the decrypted
1956 * data should be written. If null, the decrypted
1957 * data is returned as a string.
1959 * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
1960 * string containing the decrypted data is returned.
1962 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
1963 * decrypt the data is not in the user's keyring.
1965 * @throws Crypt_GPG_NoDataException if specified data does not contain
1966 * GPG encrypted data.
1968 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
1969 * incorrect or if a required passphrase is not specified. See
1970 * {@link Crypt_GPG::addDecryptKey()}.
1972 * @throws Crypt_GPG_FileException if the output file is not writeable or
1973 * if the input file is not readable.
1975 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
1976 * Use the <kbd>debug</kbd> option and file a bug report if these
1979 private function _decrypt($data, $isFile, $outputFile)
1982 $input = @fopen($data, 'rb');
1983 if ($input === false) {
1984 throw new Crypt_GPG_FileException('Could not open input file "' .
1985 $data . '" for decryption.', 0, $data);
1988 $input = strval($data);
1990 throw new Crypt_GPG_NoDataException(
1991 'Cannot decrypt data. No PGP encrypted data was found in '.
1992 'the provided data.', Crypt_GPG::ERROR_NO_DATA);
1996 if ($outputFile === null) {
1999 $output = @fopen($outputFile, 'wb');
2000 if ($output === false) {
2004 throw new Crypt_GPG_FileException('Could not open output ' .
2005 'file "' . $outputFile . '" for storing decrypted data.',
2010 $handler = new Crypt_GPG_DecryptStatusHandler($this->engine,
2011 $this->decryptKeys);
2013 $this->engine->reset();
2014 $this->engine->addStatusHandler(array($handler, 'handle'));
2015 $this->engine->setOperation('--decrypt');
2016 $this->engine->setInput($input);
2017 $this->engine->setOutput($output);
2018 $this->engine->run();
2024 if ($outputFile !== null) {
2028 // if there was any problem decrypting the data, the handler will
2029 // deal with it here.
2030 $handler->throwException();
2032 if ($outputFile === null) {
2043 * @param string $data the data to be signed.
2044 * @param boolean $isFile whether or not the data is a filename.
2045 * @param string $outputFile the name of the file in which the signed data
2046 * should be stored. If null, the signed data is
2047 * returned as a string.
2048 * @param boolean $mode the data signing mode to use. Should be one of
2049 * {@link Crypt_GPG::SIGN_MODE_NORMAL},
2050 * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
2051 * {@link Crypt_GPG::SIGN_MODE_DETACHED}.
2052 * @param boolean $armor if true, ASCII armored data is returned;
2053 * otherwise, binary data is returned. This has
2054 * no effect if the mode
2055 * <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
2057 * @param boolean $textmode if true, line-breaks in signed data be
2058 * normalized. Use this option when signing
2059 * e-mail, or for greater compatibility between
2060 * systems with different line-break formats.
2061 * Defaults to false. This has no effect if the
2062 * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
2063 * used as clear-signing always uses textmode.
2065 * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
2066 * string containing the signed data (or the signature
2067 * data if a detached signature is requested) is
2070 * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
2071 * See {@link Crypt_GPG::addSignKey()}.
2073 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
2074 * incorrect or if a required passphrase is not specified.
2076 * @throws Crypt_GPG_FileException if the output file is not writeable or
2077 * if the input file is not readable.
2079 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
2080 * Use the <kbd>debug</kbd> option and file a bug report if these
2083 private function _sign($data, $isFile, $outputFile, $mode, $armor,
2086 if (count($this->signKeys) === 0) {
2087 throw new Crypt_GPG_KeyNotFoundException(
2088 'No signing keys specified.');
2092 $input = @fopen($data, 'rb');
2093 if ($input === false) {
2094 throw new Crypt_GPG_FileException('Could not open input ' .
2095 'file "' . $data . '" for signing.', 0, $data);
2098 $input = strval($data);
2101 if ($outputFile === null) {
2104 $output = @fopen($outputFile, 'wb');
2105 if ($output === false) {
2109 throw new Crypt_GPG_FileException('Could not open output ' .
2110 'file "' . $outputFile . '" for storing signed ' .
2111 'data.', 0, $outputFile);
2116 case Crypt_GPG::SIGN_MODE_DETACHED:
2117 $operation = '--detach-sign';
2119 case Crypt_GPG::SIGN_MODE_CLEAR:
2120 $operation = '--clearsign';
2122 case Crypt_GPG::SIGN_MODE_NORMAL:
2124 $operation = '--sign';
2128 $arguments = array();
2131 $arguments[] = '--armor';
2134 $arguments[] = '--textmode';
2137 foreach ($this->signKeys as $key) {
2138 $arguments[] = '--local-user ' .
2139 escapeshellarg($key['fingerprint']);
2142 $this->engine->reset();
2143 $this->engine->addStatusHandler(array($this, 'handleSignStatus'));
2144 $this->engine->setInput($input);
2145 $this->engine->setOutput($output);
2146 $this->engine->setOperation($operation, $arguments);
2147 $this->engine->run();
2153 if ($outputFile !== null) {
2157 $code = $this->engine->getErrorCode();
2160 case Crypt_GPG::ERROR_NONE:
2162 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
2163 throw new Crypt_GPG_KeyNotFoundException(
2164 'Cannot sign data. Private key not found. Import the '.
2165 'private key before trying to sign data.', $code,
2166 $this->engine->getErrorKeyId());
2167 case Crypt_GPG::ERROR_BAD_PASSPHRASE:
2168 throw new Crypt_GPG_BadPassphraseException(
2169 'Cannot sign data. Incorrect passphrase provided.', $code);
2170 case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
2171 throw new Crypt_GPG_BadPassphraseException(
2172 'Cannot sign data. No passphrase provided.', $code);
2174 throw new Crypt_GPG_Exception(
2175 'Unknown error signing data. Please use the \'debug\' option ' .
2176 'when creating the Crypt_GPG object, and file a bug report ' .
2177 'at ' . self::BUG_URI, $code);
2180 if ($outputFile === null) {
2186 // {{{ _encryptAndSign()
2189 * Encrypts and signs data
2191 * @param string $data the data to be encrypted and signed.
2192 * @param boolean $isFile whether or not the data is a filename.
2193 * @param string $outputFile the name of the file in which the encrypted,
2194 * signed data should be stored. If null, the
2195 * encrypted, signed data is returned as a
2197 * @param boolean $armor if true, ASCII armored data is returned;
2198 * otherwise, binary data is returned.
2200 * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
2201 * string containing the encrypted, signed data is
2204 * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
2205 * or if no signing key is specified. See
2206 * {@link Crypt_GPG::addEncryptKey()} and
2207 * {@link Crypt_GPG::addSignKey()}.
2209 * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
2210 * incorrect or if a required passphrase is not specified.
2212 * @throws Crypt_GPG_FileException if the output file is not writeable or
2213 * if the input file is not readable.
2215 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
2216 * Use the <kbd>debug</kbd> option and file a bug report if these
2219 private function _encryptAndSign($data, $isFile, $outputFile, $armor)
2221 if (count($this->signKeys) === 0) {
2222 throw new Crypt_GPG_KeyNotFoundException(
2223 'No signing keys specified.');
2226 if (count($this->encryptKeys) === 0) {
2227 throw new Crypt_GPG_KeyNotFoundException(
2228 'No encryption keys specified.');
2233 $input = @fopen($data, 'rb');
2234 if ($input === false) {
2235 throw new Crypt_GPG_FileException('Could not open input ' .
2236 'file "' . $data . '" for encrypting and signing.', 0,
2240 $input = strval($data);
2243 if ($outputFile === null) {
2246 $output = @fopen($outputFile, 'wb');
2247 if ($output === false) {
2251 throw new Crypt_GPG_FileException('Could not open output ' .
2252 'file "' . $outputFile . '" for storing encrypted, ' .
2253 'signed data.', 0, $outputFile);
2257 $arguments = ($armor) ? array('--armor') : array();
2259 foreach ($this->signKeys as $key) {
2260 $arguments[] = '--local-user ' .
2261 escapeshellarg($key['fingerprint']);
2264 foreach ($this->encryptKeys as $key) {
2265 $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']);
2268 $this->engine->reset();
2269 $this->engine->addStatusHandler(array($this, 'handleSignStatus'));
2270 $this->engine->setInput($input);
2271 $this->engine->setOutput($output);
2272 $this->engine->setOperation('--encrypt --sign', $arguments);
2273 $this->engine->run();
2279 if ($outputFile !== null) {
2283 $code = $this->engine->getErrorCode();
2286 case Crypt_GPG::ERROR_NONE:
2288 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
2289 throw new Crypt_GPG_KeyNotFoundException(
2290 'Cannot sign encrypted data. Private key not found. Import '.
2291 'the private key before trying to sign the encrypted data.',
2292 $code, $this->engine->getErrorKeyId());
2293 case Crypt_GPG::ERROR_BAD_PASSPHRASE:
2294 throw new Crypt_GPG_BadPassphraseException(
2295 'Cannot sign encrypted data. Incorrect passphrase provided.',
2297 case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
2298 throw new Crypt_GPG_BadPassphraseException(
2299 'Cannot sign encrypted data. No passphrase provided.', $code);
2301 throw new Crypt_GPG_Exception(
2302 'Unknown error encrypting and signing data. Please use the ' .
2303 '\'debug\' option when creating the Crypt_GPG object, and ' .
2304 'file a bug report at ' . self::BUG_URI, $code);
2307 if ($outputFile === null) {
2318 * @param string $data the signed data to be verified.
2319 * @param boolean $isFile whether or not the data is a filename.
2320 * @param string $signature if verifying a file signed using a detached
2321 * signature, this must be the detached signature
2322 * data. Otherwise, specify ''.
2324 * @return array an array of {@link Crypt_GPG_Signature} objects for the
2327 * @throws Crypt_GPG_NoDataException if the provided data is not signed
2330 * @throws Crypt_GPG_FileException if the input file is not readable.
2332 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
2333 * Use the <kbd>debug</kbd> option and file a bug report if these
2336 * @see Crypt_GPG_Signature
2338 private function _verify($data, $isFile, $signature)
2340 if ($signature == '') {
2341 $operation = '--verify';
2342 $arguments = array();
2344 // Signed data goes in FD_MESSAGE, detached signature data goes in
2346 $operation = '--verify - "-&' . Crypt_GPG_Engine::FD_MESSAGE. '"';
2347 $arguments = array('--enable-special-filenames');
2350 $handler = new Crypt_GPG_VerifyStatusHandler();
2353 $input = @fopen($data, 'rb');
2354 if ($input === false) {
2355 throw new Crypt_GPG_FileException('Could not open input ' .
2356 'file "' . $data . '" for verifying.', 0, $data);
2359 $input = strval($data);
2361 throw new Crypt_GPG_NoDataException(
2362 'No valid signature data found.', Crypt_GPG::ERROR_NO_DATA);
2366 $this->engine->reset();
2367 $this->engine->addStatusHandler(array($handler, 'handle'));
2369 if ($signature == '') {
2370 // signed or clearsigned data
2371 $this->engine->setInput($input);
2373 // detached signature
2374 $this->engine->setInput($signature);
2375 $this->engine->setMessage($input);
2378 $this->engine->setOperation($operation, $arguments);
2379 $this->engine->run();
2385 $code = $this->engine->getErrorCode();
2388 case Crypt_GPG::ERROR_NONE:
2389 case Crypt_GPG::ERROR_BAD_SIGNATURE:
2391 case Crypt_GPG::ERROR_NO_DATA:
2392 throw new Crypt_GPG_NoDataException(
2393 'No valid signature data found.', $code);
2394 case Crypt_GPG::ERROR_KEY_NOT_FOUND:
2395 throw new Crypt_GPG_KeyNotFoundException(
2396 'Public key required for data verification not in keyring.',
2397 $code, $this->engine->getErrorKeyId());
2399 throw new Crypt_GPG_Exception(
2400 'Unknown error validating signature details. Please use the ' .
2401 '\'debug\' option when creating the Crypt_GPG object, and ' .
2402 'file a bug report at ' . self::BUG_URI, $code);
2405 return $handler->getSignatures();
2409 // {{{ _decryptAndVerify()
2412 * Decrypts and verifies encrypted, signed data
2414 * @param string $data the encrypted signed data to be decrypted and
2416 * @param boolean $isFile whether or not the data is a filename.
2417 * @param string $outputFile the name of the file to which the decrypted
2418 * data should be written. If null, the decrypted
2419 * data is returned in the results array.
2421 * @return array two element array. The array has an element 'data'
2422 * containing the decrypted data and an element
2423 * 'signatures' containing an array of
2424 * {@link Crypt_GPG_Signature} objects for the signed data.
2425 * If the decrypted data is written to a file, the 'data'
2428 * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
2429 * decrypt the data is not in the user's keyring or it the public
2430 * key needed for verification is not in the user's keyring.
2432 * @throws Crypt_GPG_NoDataException if specified data does not contain
2433 * GPG signed, encrypted data.
2435 * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
2436 * incorrect or if a required passphrase is not specified. See
2437 * {@link Crypt_GPG::addDecryptKey()}.
2439 * @throws Crypt_GPG_FileException if the output file is not writeable or
2440 * if the input file is not readable.
2442 * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
2443 * Use the <kbd>debug</kbd> option and file a bug report if these
2446 * @see Crypt_GPG_Signature
2448 private function _decryptAndVerify($data, $isFile, $outputFile)
2451 $input = @fopen($data, 'rb');
2452 if ($input === false) {
2453 throw new Crypt_GPG_FileException('Could not open input ' .
2454 'file "' . $data . '" for decrypting and verifying.', 0,
2458 $input = strval($data);
2460 throw new Crypt_GPG_NoDataException(
2461 'No valid encrypted signed data found.',
2462 Crypt_GPG::ERROR_NO_DATA);
2466 if ($outputFile === null) {
2469 $output = @fopen($outputFile, 'wb');
2470 if ($output === false) {
2474 throw new Crypt_GPG_FileException('Could not open output ' .
2475 'file "' . $outputFile . '" for storing decrypted data.',
2480 $verifyHandler = new Crypt_GPG_VerifyStatusHandler();
2482 $decryptHandler = new Crypt_GPG_DecryptStatusHandler($this->engine,
2483 $this->decryptKeys);
2485 $this->engine->reset();
2486 $this->engine->addStatusHandler(array($verifyHandler, 'handle'));
2487 $this->engine->addStatusHandler(array($decryptHandler, 'handle'));
2488 $this->engine->setInput($input);
2489 $this->engine->setOutput($output);
2490 $this->engine->setOperation('--decrypt');
2491 $this->engine->run();
2497 if ($outputFile !== null) {
2503 'signatures' => $verifyHandler->getSignatures()
2506 // if there was any problem decrypting the data, the handler will
2507 // deal with it here.
2509 $decryptHandler->throwException();
2510 } catch (Exception $e) {
2511 if ($e instanceof Crypt_GPG_KeyNotFoundException) {
2512 throw new Crypt_GPG_KeyNotFoundException(
2513 'Public key required for data verification not in ',
2514 'the keyring. Either no suitable private decryption key ' .
2515 'is in the keyring or the public key required for data ' .
2516 'verification is not in the keyring. Import a suitable ' .
2517 'key before trying to decrypt and verify this data.',
2518 self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId());
2521 if ($e instanceof Crypt_GPG_NoDataException) {
2522 throw new Crypt_GPG_NoDataException(
2523 'Cannot decrypt and verify data. No PGP encrypted data ' .
2524 'was found in the provided data.', self::ERROR_NO_DATA);
2530 if ($outputFile === null) {
2531 $return['data'] = $output;