PageRenderTime 59ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/mail/plugins/enigma/lib/Crypt/GPG.php

https://bitbucket.org/alisher/itworks
PHP | 2542 lines | 913 code | 252 blank | 1377 comment | 147 complexity | fb0d02b23b92e09fc096e5e5f8b39f24 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. /**
  4. * Crypt_GPG is a package to use GPG from PHP
  5. *
  6. * This package provides an object oriented interface to GNU Privacy
  7. * Guard (GPG). It requires the GPG executable to be on the system.
  8. *
  9. * Though GPG can support symmetric-key cryptography, this package is intended
  10. * only to facilitate public-key cryptography.
  11. *
  12. * This file contains the main GPG class. The class in this file lets you
  13. * encrypt, decrypt, sign and verify data; import and delete keys; and perform
  14. * other useful GPG tasks.
  15. *
  16. * Example usage:
  17. * <code>
  18. * <?php
  19. * // encrypt some data
  20. * $gpg = new Crypt_GPG();
  21. * $gpg->addEncryptKey($mySecretKeyId);
  22. * $encryptedData = $gpg->encrypt($data);
  23. * ?>
  24. * </code>
  25. *
  26. * PHP version 5
  27. *
  28. * LICENSE:
  29. *
  30. * This library is free software; you can redistribute it and/or modify
  31. * it under the terms of the GNU Lesser General Public License as
  32. * published by the Free Software Foundation; either version 2.1 of the
  33. * License, or (at your option) any later version.
  34. *
  35. * This library is distributed in the hope that it will be useful,
  36. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  37. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  38. * Lesser General Public License for more details.
  39. *
  40. * You should have received a copy of the GNU Lesser General Public
  41. * License along with this library; if not, write to the Free Software
  42. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  43. *
  44. * @category Encryption
  45. * @package Crypt_GPG
  46. * @author Nathan Fredrickson <nathan@silverorange.com>
  47. * @author Michael Gauthier <mike@silverorange.com>
  48. * @copyright 2005-2010 silverorange
  49. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  50. * @version CVS: $Id: GPG.php 302814 2010-08-26 15:43:07Z gauthierm $
  51. * @link http://pear.php.net/package/Crypt_GPG
  52. * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php
  53. * @link http://www.gnupg.org/
  54. */
  55. /**
  56. * Signature handler class
  57. */
  58. require_once 'Crypt/GPG/VerifyStatusHandler.php';
  59. /**
  60. * Decryption handler class
  61. */
  62. require_once 'Crypt/GPG/DecryptStatusHandler.php';
  63. /**
  64. * GPG key class
  65. */
  66. require_once 'Crypt/GPG/Key.php';
  67. /**
  68. * GPG sub-key class
  69. */
  70. require_once 'Crypt/GPG/SubKey.php';
  71. /**
  72. * GPG user id class
  73. */
  74. require_once 'Crypt/GPG/UserId.php';
  75. /**
  76. * GPG process and I/O engine class
  77. */
  78. require_once 'Crypt/GPG/Engine.php';
  79. /**
  80. * GPG exception classes
  81. */
  82. require_once 'Crypt/GPG/Exceptions.php';
  83. // {{{ class Crypt_GPG
  84. /**
  85. * A class to use GPG from PHP
  86. *
  87. * This class provides an object oriented interface to GNU Privacy Guard (GPG).
  88. *
  89. * Though GPG can support symmetric-key cryptography, this class is intended
  90. * only to facilitate public-key cryptography.
  91. *
  92. * @category Encryption
  93. * @package Crypt_GPG
  94. * @author Nathan Fredrickson <nathan@silverorange.com>
  95. * @author Michael Gauthier <mike@silverorange.com>
  96. * @copyright 2005-2010 silverorange
  97. * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  98. * @link http://pear.php.net/package/Crypt_GPG
  99. * @link http://www.gnupg.org/
  100. */
  101. class Crypt_GPG
  102. {
  103. // {{{ class error constants
  104. /**
  105. * Error code returned when there is no error.
  106. */
  107. const ERROR_NONE = 0;
  108. /**
  109. * Error code returned when an unknown or unhandled error occurs.
  110. */
  111. const ERROR_UNKNOWN = 1;
  112. /**
  113. * Error code returned when a bad passphrase is used.
  114. */
  115. const ERROR_BAD_PASSPHRASE = 2;
  116. /**
  117. * Error code returned when a required passphrase is missing.
  118. */
  119. const ERROR_MISSING_PASSPHRASE = 3;
  120. /**
  121. * Error code returned when a key that is already in the keyring is
  122. * imported.
  123. */
  124. const ERROR_DUPLICATE_KEY = 4;
  125. /**
  126. * Error code returned the required data is missing for an operation.
  127. *
  128. * This could be missing key data, missing encrypted data or missing
  129. * signature data.
  130. */
  131. const ERROR_NO_DATA = 5;
  132. /**
  133. * Error code returned when an unsigned key is used.
  134. */
  135. const ERROR_UNSIGNED_KEY = 6;
  136. /**
  137. * Error code returned when a key that is not self-signed is used.
  138. */
  139. const ERROR_NOT_SELF_SIGNED = 7;
  140. /**
  141. * Error code returned when a public or private key that is not in the
  142. * keyring is used.
  143. */
  144. const ERROR_KEY_NOT_FOUND = 8;
  145. /**
  146. * Error code returned when an attempt to delete public key having a
  147. * private key is made.
  148. */
  149. const ERROR_DELETE_PRIVATE_KEY = 9;
  150. /**
  151. * Error code returned when one or more bad signatures are detected.
  152. */
  153. const ERROR_BAD_SIGNATURE = 10;
  154. /**
  155. * Error code returned when there is a problem reading GnuPG data files.
  156. */
  157. const ERROR_FILE_PERMISSIONS = 11;
  158. // }}}
  159. // {{{ class constants for data signing modes
  160. /**
  161. * Signing mode for normal signing of data. The signed message will not
  162. * be readable without special software.
  163. *
  164. * This is the default signing mode.
  165. *
  166. * @see Crypt_GPG::sign()
  167. * @see Crypt_GPG::signFile()
  168. */
  169. const SIGN_MODE_NORMAL = 1;
  170. /**
  171. * Signing mode for clearsigning data. Clearsigned signatures are ASCII
  172. * armored data and are readable without special software. If the signed
  173. * message is unencrypted, the message will still be readable. The message
  174. * text will be in the original encoding.
  175. *
  176. * @see Crypt_GPG::sign()
  177. * @see Crypt_GPG::signFile()
  178. */
  179. const SIGN_MODE_CLEAR = 2;
  180. /**
  181. * Signing mode for creating a detached signature. When using detached
  182. * signatures, only the signature data is returned. The original message
  183. * text may be distributed separately from the signature data. This is
  184. * useful for miltipart/signed email messages as per
  185. * {@link http://www.ietf.org/rfc/rfc3156.txt RFC 3156}.
  186. *
  187. * @see Crypt_GPG::sign()
  188. * @see Crypt_GPG::signFile()
  189. */
  190. const SIGN_MODE_DETACHED = 3;
  191. // }}}
  192. // {{{ class constants for fingerprint formats
  193. /**
  194. * No formatting is performed.
  195. *
  196. * Example: C3BC615AD9C766E5A85C1F2716D27458B1BBA1C4
  197. *
  198. * @see Crypt_GPG::getFingerprint()
  199. */
  200. const FORMAT_NONE = 1;
  201. /**
  202. * Fingerprint is formatted in the format used by the GnuPG gpg command's
  203. * default output.
  204. *
  205. * Example: C3BC 615A D9C7 66E5 A85C 1F27 16D2 7458 B1BB A1C4
  206. *
  207. * @see Crypt_GPG::getFingerprint()
  208. */
  209. const FORMAT_CANONICAL = 2;
  210. /**
  211. * Fingerprint is formatted in the format used when displaying X.509
  212. * certificates
  213. *
  214. * Example: C3:BC:61:5A:D9:C7:66:E5:A8:5C:1F:27:16:D2:74:58:B1:BB:A1:C4
  215. *
  216. * @see Crypt_GPG::getFingerprint()
  217. */
  218. const FORMAT_X509 = 3;
  219. // }}}
  220. // {{{ other class constants
  221. /**
  222. * URI at which package bugs may be reported.
  223. */
  224. const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG';
  225. // }}}
  226. // {{{ protected class properties
  227. /**
  228. * Engine used to control the GPG subprocess
  229. *
  230. * @var Crypt_GPG_Engine
  231. *
  232. * @see Crypt_GPG::setEngine()
  233. */
  234. protected $engine = null;
  235. /**
  236. * Keys used to encrypt
  237. *
  238. * The array is of the form:
  239. * <code>
  240. * array(
  241. * $key_id => array(
  242. * 'fingerprint' => $fingerprint,
  243. * 'passphrase' => null
  244. * )
  245. * );
  246. * </code>
  247. *
  248. * @var array
  249. * @see Crypt_GPG::addEncryptKey()
  250. * @see Crypt_GPG::clearEncryptKeys()
  251. */
  252. protected $encryptKeys = array();
  253. /**
  254. * Keys used to decrypt
  255. *
  256. * The array is of the form:
  257. * <code>
  258. * array(
  259. * $key_id => array(
  260. * 'fingerprint' => $fingerprint,
  261. * 'passphrase' => $passphrase
  262. * )
  263. * );
  264. * </code>
  265. *
  266. * @var array
  267. * @see Crypt_GPG::addSignKey()
  268. * @see Crypt_GPG::clearSignKeys()
  269. */
  270. protected $signKeys = array();
  271. /**
  272. * Keys used to sign
  273. *
  274. * The array is of the form:
  275. * <code>
  276. * array(
  277. * $key_id => array(
  278. * 'fingerprint' => $fingerprint,
  279. * 'passphrase' => $passphrase
  280. * )
  281. * );
  282. * </code>
  283. *
  284. * @var array
  285. * @see Crypt_GPG::addDecryptKey()
  286. * @see Crypt_GPG::clearDecryptKeys()
  287. */
  288. protected $decryptKeys = array();
  289. // }}}
  290. // {{{ __construct()
  291. /**
  292. * Creates a new GPG object
  293. *
  294. * Available options are:
  295. *
  296. * - <kbd>string homedir</kbd> - the directory where the GPG
  297. * keyring files are stored. If not
  298. * specified, Crypt_GPG uses the
  299. * default of <kbd>~/.gnupg</kbd>.
  300. * - <kbd>string publicKeyring</kbd> - the file path of the public
  301. * keyring. Use this if the public
  302. * keyring is not in the homedir, or
  303. * if the keyring is in a directory
  304. * not writable by the process
  305. * invoking GPG (like Apache). Then
  306. * you can specify the path to the
  307. * keyring with this option
  308. * (/foo/bar/pubring.gpg), and specify
  309. * a writable directory (like /tmp)
  310. * using the <i>homedir</i> option.
  311. * - <kbd>string privateKeyring</kbd> - the file path of the private
  312. * keyring. Use this if the private
  313. * keyring is not in the homedir, or
  314. * if the keyring is in a directory
  315. * not writable by the process
  316. * invoking GPG (like Apache). Then
  317. * you can specify the path to the
  318. * keyring with this option
  319. * (/foo/bar/secring.gpg), and specify
  320. * a writable directory (like /tmp)
  321. * using the <i>homedir</i> option.
  322. * - <kbd>string trustDb</kbd> - the file path of the web-of-trust
  323. * database. Use this if the trust
  324. * database is not in the homedir, or
  325. * if the database is in a directory
  326. * not writable by the process
  327. * invoking GPG (like Apache). Then
  328. * you can specify the path to the
  329. * trust database with this option
  330. * (/foo/bar/trustdb.gpg), and specify
  331. * a writable directory (like /tmp)
  332. * using the <i>homedir</i> option.
  333. * - <kbd>string binary</kbd> - the location of the GPG binary. If
  334. * not specified, the driver attempts
  335. * to auto-detect the GPG binary
  336. * location using a list of known
  337. * default locations for the current
  338. * operating system. The option
  339. * <kbd>gpgBinary</kbd> is a
  340. * deprecated alias for this option.
  341. * - <kbd>boolean debug</kbd> - whether or not to use debug mode.
  342. * When debug mode is on, all
  343. * communication to and from the GPG
  344. * subprocess is logged. This can be
  345. *
  346. * @param array $options optional. An array of options used to create the
  347. * GPG object. All options are optional and are
  348. * represented as key-value pairs.
  349. *
  350. * @throws Crypt_GPG_FileException if the <kbd>homedir</kbd> does not exist
  351. * and cannot be created. This can happen if <kbd>homedir</kbd> is
  352. * not specified, Crypt_GPG is run as the web user, and the web
  353. * user has no home directory. This exception is also thrown if any
  354. * of the options <kbd>publicKeyring</kbd>,
  355. * <kbd>privateKeyring</kbd> or <kbd>trustDb</kbd> options are
  356. * specified but the files do not exist or are are not readable.
  357. * This can happen if the user running the Crypt_GPG process (for
  358. * example, the Apache user) does not have permission to read the
  359. * files.
  360. *
  361. * @throws PEAR_Exception if the provided <kbd>binary</kbd> is invalid, or
  362. * if no <kbd>binary</kbd> is provided and no suitable binary could
  363. * be found.
  364. */
  365. public function __construct(array $options = array())
  366. {
  367. $this->setEngine(new Crypt_GPG_Engine($options));
  368. }
  369. // }}}
  370. // {{{ importKey()
  371. /**
  372. * Imports a public or private key into the keyring
  373. *
  374. * Keys may be removed from the keyring using
  375. * {@link Crypt_GPG::deletePublicKey()} or
  376. * {@link Crypt_GPG::deletePrivateKey()}.
  377. *
  378. * @param string $data the key data to be imported.
  379. *
  380. * @return array an associative array containing the following elements:
  381. * - <kbd>fingerprint</kbd> - the fingerprint of the
  382. * imported key,
  383. * - <kbd>public_imported</kbd> - the number of public
  384. * keys imported,
  385. * - <kbd>public_unchanged</kbd> - the number of unchanged
  386. * public keys,
  387. * - <kbd>private_imported</kbd> - the number of private
  388. * keys imported,
  389. * - <kbd>private_unchanged</kbd> - the number of unchanged
  390. * private keys.
  391. *
  392. * @throws Crypt_GPG_NoDataException if the key data is missing or if the
  393. * data is is not valid key data.
  394. *
  395. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  396. * Use the <kbd>debug</kbd> option and file a bug report if these
  397. * exceptions occur.
  398. */
  399. public function importKey($data)
  400. {
  401. return $this->_importKey($data, false);
  402. }
  403. // }}}
  404. // {{{ importKeyFile()
  405. /**
  406. * Imports a public or private key file into the keyring
  407. *
  408. * Keys may be removed from the keyring using
  409. * {@link Crypt_GPG::deletePublicKey()} or
  410. * {@link Crypt_GPG::deletePrivateKey()}.
  411. *
  412. * @param string $filename the key file to be imported.
  413. *
  414. * @return array an associative array containing the following elements:
  415. * - <kbd>fingerprint</kbd> - the fingerprint of the
  416. * imported key,
  417. * - <kbd>public_imported</kbd> - the number of public
  418. * keys imported,
  419. * - <kbd>public_unchanged</kbd> - the number of unchanged
  420. * public keys,
  421. * - <kbd>private_imported</kbd> - the number of private
  422. * keys imported,
  423. * - <kbd>private_unchanged</kbd> - the number of unchanged
  424. * private keys.
  425. * private keys.
  426. *
  427. * @throws Crypt_GPG_NoDataException if the key data is missing or if the
  428. * data is is not valid key data.
  429. *
  430. * @throws Crypt_GPG_FileException if the key file is not readable.
  431. *
  432. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  433. * Use the <kbd>debug</kbd> option and file a bug report if these
  434. * exceptions occur.
  435. */
  436. public function importKeyFile($filename)
  437. {
  438. return $this->_importKey($filename, true);
  439. }
  440. // }}}
  441. // {{{ exportPublicKey()
  442. /**
  443. * Exports a public key from the keyring
  444. *
  445. * The exported key remains on the keyring. To delete the public key, use
  446. * {@link Crypt_GPG::deletePublicKey()}.
  447. *
  448. * If more than one key fingerprint is available for the specified
  449. * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
  450. * first public key is exported.
  451. *
  452. * @param string $keyId either the full uid of the public key, the email
  453. * part of the uid of the public key or the key id of
  454. * the public key. For example,
  455. * "Test User (example) <test@example.com>",
  456. * "test@example.com" or a hexadecimal string.
  457. * @param boolean $armor optional. If true, ASCII armored data is returned;
  458. * otherwise, binary data is returned. Defaults to
  459. * true.
  460. *
  461. * @return string the public key data.
  462. *
  463. * @throws Crypt_GPG_KeyNotFoundException if a public key with the given
  464. * <kbd>$keyId</kbd> is not found.
  465. *
  466. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  467. * Use the <kbd>debug</kbd> option and file a bug report if these
  468. * exceptions occur.
  469. */
  470. public function exportPublicKey($keyId, $armor = true)
  471. {
  472. $fingerprint = $this->getFingerprint($keyId);
  473. if ($fingerprint === null) {
  474. throw new Crypt_GPG_KeyNotFoundException(
  475. 'Public key not found: ' . $keyId,
  476. Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
  477. }
  478. $keyData = '';
  479. $operation = '--export ' . escapeshellarg($fingerprint);
  480. $arguments = ($armor) ? array('--armor') : array();
  481. $this->engine->reset();
  482. $this->engine->setOutput($keyData);
  483. $this->engine->setOperation($operation, $arguments);
  484. $this->engine->run();
  485. $code = $this->engine->getErrorCode();
  486. if ($code !== Crypt_GPG::ERROR_NONE) {
  487. throw new Crypt_GPG_Exception(
  488. 'Unknown error exporting public key. Please use the ' .
  489. '\'debug\' option when creating the Crypt_GPG object, and ' .
  490. 'file a bug report at ' . self::BUG_URI, $code);
  491. }
  492. return $keyData;
  493. }
  494. // }}}
  495. // {{{ deletePublicKey()
  496. /**
  497. * Deletes a public key from the keyring
  498. *
  499. * If more than one key fingerprint is available for the specified
  500. * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
  501. * first public key is deleted.
  502. *
  503. * The private key must be deleted first or an exception will be thrown.
  504. * See {@link Crypt_GPG::deletePrivateKey()}.
  505. *
  506. * @param string $keyId either the full uid of the public key, the email
  507. * part of the uid of the public key or the key id of
  508. * the public key. For example,
  509. * "Test User (example) <test@example.com>",
  510. * "test@example.com" or a hexadecimal string.
  511. *
  512. * @return void
  513. *
  514. * @throws Crypt_GPG_KeyNotFoundException if a public key with the given
  515. * <kbd>$keyId</kbd> is not found.
  516. *
  517. * @throws Crypt_GPG_DeletePrivateKeyException if the specified public key
  518. * has an associated private key on the keyring. The private key
  519. * must be deleted first.
  520. *
  521. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  522. * Use the <kbd>debug</kbd> option and file a bug report if these
  523. * exceptions occur.
  524. */
  525. public function deletePublicKey($keyId)
  526. {
  527. $fingerprint = $this->getFingerprint($keyId);
  528. if ($fingerprint === null) {
  529. throw new Crypt_GPG_KeyNotFoundException(
  530. 'Public key not found: ' . $keyId,
  531. Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
  532. }
  533. $operation = '--delete-key ' . escapeshellarg($fingerprint);
  534. $arguments = array(
  535. '--batch',
  536. '--yes'
  537. );
  538. $this->engine->reset();
  539. $this->engine->setOperation($operation, $arguments);
  540. $this->engine->run();
  541. $code = $this->engine->getErrorCode();
  542. switch ($code) {
  543. case Crypt_GPG::ERROR_NONE:
  544. break;
  545. case Crypt_GPG::ERROR_DELETE_PRIVATE_KEY:
  546. throw new Crypt_GPG_DeletePrivateKeyException(
  547. 'Private key must be deleted before public key can be ' .
  548. 'deleted.', $code, $keyId);
  549. default:
  550. throw new Crypt_GPG_Exception(
  551. 'Unknown error deleting public key. Please use the ' .
  552. '\'debug\' option when creating the Crypt_GPG object, and ' .
  553. 'file a bug report at ' . self::BUG_URI, $code);
  554. }
  555. }
  556. // }}}
  557. // {{{ deletePrivateKey()
  558. /**
  559. * Deletes a private key from the keyring
  560. *
  561. * If more than one key fingerprint is available for the specified
  562. * <kbd>$keyId</kbd> (for example, if you use a non-unique uid) only the
  563. * first private key is deleted.
  564. *
  565. * Calls GPG with the <kbd>--delete-secret-key</kbd> command.
  566. *
  567. * @param string $keyId either the full uid of the private key, the email
  568. * part of the uid of the private key or the key id of
  569. * the private key. For example,
  570. * "Test User (example) <test@example.com>",
  571. * "test@example.com" or a hexadecimal string.
  572. *
  573. * @return void
  574. *
  575. * @throws Crypt_GPG_KeyNotFoundException if a private key with the given
  576. * <kbd>$keyId</kbd> is not found.
  577. *
  578. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  579. * Use the <kbd>debug</kbd> option and file a bug report if these
  580. * exceptions occur.
  581. */
  582. public function deletePrivateKey($keyId)
  583. {
  584. $fingerprint = $this->getFingerprint($keyId);
  585. if ($fingerprint === null) {
  586. throw new Crypt_GPG_KeyNotFoundException(
  587. 'Private key not found: ' . $keyId,
  588. Crypt_GPG::ERROR_KEY_NOT_FOUND, $keyId);
  589. }
  590. $operation = '--delete-secret-key ' . escapeshellarg($fingerprint);
  591. $arguments = array(
  592. '--batch',
  593. '--yes'
  594. );
  595. $this->engine->reset();
  596. $this->engine->setOperation($operation, $arguments);
  597. $this->engine->run();
  598. $code = $this->engine->getErrorCode();
  599. switch ($code) {
  600. case Crypt_GPG::ERROR_NONE:
  601. break;
  602. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  603. throw new Crypt_GPG_KeyNotFoundException(
  604. 'Private key not found: ' . $keyId,
  605. $code, $keyId);
  606. default:
  607. throw new Crypt_GPG_Exception(
  608. 'Unknown error deleting private key. Please use the ' .
  609. '\'debug\' option when creating the Crypt_GPG object, and ' .
  610. 'file a bug report at ' . self::BUG_URI, $code);
  611. }
  612. }
  613. // }}}
  614. // {{{ getKeys()
  615. /**
  616. * Gets the available keys in the keyring
  617. *
  618. * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See
  619. * the first section of <b>doc/DETAILS</b> in the
  620. * {@link http://www.gnupg.org/download/ GPG package} for a detailed
  621. * description of how the GPG command output is parsed.
  622. *
  623. * @param string $keyId optional. Only keys with that match the specified
  624. * pattern are returned. The pattern may be part of
  625. * a user id, a key id or a key fingerprint. If not
  626. * specified, all keys are returned.
  627. *
  628. * @return array an array of {@link Crypt_GPG_Key} objects. If no keys
  629. * match the specified <kbd>$keyId</kbd> an empty array is
  630. * returned.
  631. *
  632. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  633. * Use the <kbd>debug</kbd> option and file a bug report if these
  634. * exceptions occur.
  635. *
  636. * @see Crypt_GPG_Key
  637. */
  638. public function getKeys($keyId = '')
  639. {
  640. // get private key fingerprints
  641. if ($keyId == '') {
  642. $operation = '--list-secret-keys';
  643. } else {
  644. $operation = '--list-secret-keys ' . escapeshellarg($keyId);
  645. }
  646. // According to The file 'doc/DETAILS' in the GnuPG distribution, using
  647. // double '--with-fingerprint' also prints the fingerprint for subkeys.
  648. $arguments = array(
  649. '--with-colons',
  650. '--with-fingerprint',
  651. '--with-fingerprint',
  652. '--fixed-list-mode'
  653. );
  654. $output = '';
  655. $this->engine->reset();
  656. $this->engine->setOutput($output);
  657. $this->engine->setOperation($operation, $arguments);
  658. $this->engine->run();
  659. $code = $this->engine->getErrorCode();
  660. switch ($code) {
  661. case Crypt_GPG::ERROR_NONE:
  662. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  663. // ignore not found key errors
  664. break;
  665. case Crypt_GPG::ERROR_FILE_PERMISSIONS:
  666. $filename = $this->engine->getErrorFilename();
  667. if ($filename) {
  668. throw new Crypt_GPG_FileException(sprintf(
  669. 'Error reading GnuPG data file \'%s\'. Check to make ' .
  670. 'sure it is readable by the current user.', $filename),
  671. $code, $filename);
  672. }
  673. throw new Crypt_GPG_FileException(
  674. 'Error reading GnuPG data file. Check to make GnuPG data ' .
  675. 'files are readable by the current user.', $code);
  676. default:
  677. throw new Crypt_GPG_Exception(
  678. 'Unknown error getting keys. Please use the \'debug\' option ' .
  679. 'when creating the Crypt_GPG object, and file a bug report ' .
  680. 'at ' . self::BUG_URI, $code);
  681. }
  682. $privateKeyFingerprints = array();
  683. $lines = explode(PHP_EOL, $output);
  684. foreach ($lines as $line) {
  685. $lineExp = explode(':', $line);
  686. if ($lineExp[0] == 'fpr') {
  687. $privateKeyFingerprints[] = $lineExp[9];
  688. }
  689. }
  690. // get public keys
  691. if ($keyId == '') {
  692. $operation = '--list-public-keys';
  693. } else {
  694. $operation = '--list-public-keys ' . escapeshellarg($keyId);
  695. }
  696. $output = '';
  697. $this->engine->reset();
  698. $this->engine->setOutput($output);
  699. $this->engine->setOperation($operation, $arguments);
  700. $this->engine->run();
  701. $code = $this->engine->getErrorCode();
  702. switch ($code) {
  703. case Crypt_GPG::ERROR_NONE:
  704. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  705. // ignore not found key errors
  706. break;
  707. case Crypt_GPG::ERROR_FILE_PERMISSIONS:
  708. $filename = $this->engine->getErrorFilename();
  709. if ($filename) {
  710. throw new Crypt_GPG_FileException(sprintf(
  711. 'Error reading GnuPG data file \'%s\'. Check to make ' .
  712. 'sure it is readable by the current user.', $filename),
  713. $code, $filename);
  714. }
  715. throw new Crypt_GPG_FileException(
  716. 'Error reading GnuPG data file. Check to make GnuPG data ' .
  717. 'files are readable by the current user.', $code);
  718. default:
  719. throw new Crypt_GPG_Exception(
  720. 'Unknown error getting keys. Please use the \'debug\' option ' .
  721. 'when creating the Crypt_GPG object, and file a bug report ' .
  722. 'at ' . self::BUG_URI, $code);
  723. }
  724. $keys = array();
  725. $key = null; // current key
  726. $subKey = null; // current sub-key
  727. $lines = explode(PHP_EOL, $output);
  728. foreach ($lines as $line) {
  729. $lineExp = explode(':', $line);
  730. if ($lineExp[0] == 'pub') {
  731. // new primary key means last key should be added to the array
  732. if ($key !== null) {
  733. $keys[] = $key;
  734. }
  735. $key = new Crypt_GPG_Key();
  736. $subKey = Crypt_GPG_SubKey::parse($line);
  737. $key->addSubKey($subKey);
  738. } elseif ($lineExp[0] == 'sub') {
  739. $subKey = Crypt_GPG_SubKey::parse($line);
  740. $key->addSubKey($subKey);
  741. } elseif ($lineExp[0] == 'fpr') {
  742. $fingerprint = $lineExp[9];
  743. // set current sub-key fingerprint
  744. $subKey->setFingerprint($fingerprint);
  745. // if private key exists, set has private to true
  746. if (in_array($fingerprint, $privateKeyFingerprints)) {
  747. $subKey->setHasPrivate(true);
  748. }
  749. } elseif ($lineExp[0] == 'uid') {
  750. $string = stripcslashes($lineExp[9]); // as per documentation
  751. $userId = new Crypt_GPG_UserId($string);
  752. if ($lineExp[1] == 'r') {
  753. $userId->setRevoked(true);
  754. }
  755. $key->addUserId($userId);
  756. }
  757. }
  758. // add last key
  759. if ($key !== null) {
  760. $keys[] = $key;
  761. }
  762. return $keys;
  763. }
  764. // }}}
  765. // {{{ getFingerprint()
  766. /**
  767. * Gets a key fingerprint from the keyring
  768. *
  769. * If more than one key fingerprint is available (for example, if you use
  770. * a non-unique user id) only the first key fingerprint is returned.
  771. *
  772. * Calls the GPG <kbd>--list-keys</kbd> command with the
  773. * <kbd>--with-fingerprint</kbd> option to retrieve a public key
  774. * fingerprint.
  775. *
  776. * @param string $keyId either the full user id of the key, the email
  777. * part of the user id of the key, or the key id of
  778. * the key. For example,
  779. * "Test User (example) <test@example.com>",
  780. * "test@example.com" or a hexadecimal string.
  781. * @param integer $format optional. How the fingerprint should be formatted.
  782. * Use {@link Crypt_GPG::FORMAT_X509} for X.509
  783. * certificate format,
  784. * {@link Crypt_GPG::FORMAT_CANONICAL} for the format
  785. * used by GnuPG output and
  786. * {@link Crypt_GPG::FORMAT_NONE} for no formatting.
  787. * Defaults to <code>Crypt_GPG::FORMAT_NONE</code>.
  788. *
  789. * @return string the fingerprint of the key, or null if no fingerprint
  790. * is found for the given <kbd>$keyId</kbd>.
  791. *
  792. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  793. * Use the <kbd>debug</kbd> option and file a bug report if these
  794. * exceptions occur.
  795. */
  796. public function getFingerprint($keyId, $format = Crypt_GPG::FORMAT_NONE)
  797. {
  798. $output = '';
  799. $operation = '--list-keys ' . escapeshellarg($keyId);
  800. $arguments = array(
  801. '--with-colons',
  802. '--with-fingerprint'
  803. );
  804. $this->engine->reset();
  805. $this->engine->setOutput($output);
  806. $this->engine->setOperation($operation, $arguments);
  807. $this->engine->run();
  808. $code = $this->engine->getErrorCode();
  809. switch ($code) {
  810. case Crypt_GPG::ERROR_NONE:
  811. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  812. // ignore not found key errors
  813. break;
  814. default:
  815. throw new Crypt_GPG_Exception(
  816. 'Unknown error getting key fingerprint. Please use the ' .
  817. '\'debug\' option when creating the Crypt_GPG object, and ' .
  818. 'file a bug report at ' . self::BUG_URI, $code);
  819. }
  820. $fingerprint = null;
  821. $lines = explode(PHP_EOL, $output);
  822. foreach ($lines as $line) {
  823. if (substr($line, 0, 3) == 'fpr') {
  824. $lineExp = explode(':', $line);
  825. $fingerprint = $lineExp[9];
  826. switch ($format) {
  827. case Crypt_GPG::FORMAT_CANONICAL:
  828. $fingerprintExp = str_split($fingerprint, 4);
  829. $format = '%s %s %s %s %s %s %s %s %s %s';
  830. $fingerprint = vsprintf($format, $fingerprintExp);
  831. break;
  832. case Crypt_GPG::FORMAT_X509:
  833. $fingerprintExp = str_split($fingerprint, 2);
  834. $fingerprint = implode(':', $fingerprintExp);
  835. break;
  836. }
  837. break;
  838. }
  839. }
  840. return $fingerprint;
  841. }
  842. // }}}
  843. // {{{ encrypt()
  844. /**
  845. * Encrypts string data
  846. *
  847. * Data is ASCII armored by default but may optionally be returned as
  848. * binary.
  849. *
  850. * @param string $data the data to be encrypted.
  851. * @param boolean $armor optional. If true, ASCII armored data is returned;
  852. * otherwise, binary data is returned. Defaults to
  853. * true.
  854. *
  855. * @return string the encrypted data.
  856. *
  857. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
  858. * See {@link Crypt_GPG::addEncryptKey()}.
  859. *
  860. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  861. * Use the <kbd>debug</kbd> option and file a bug report if these
  862. * exceptions occur.
  863. *
  864. * @sensitive $data
  865. */
  866. public function encrypt($data, $armor = true)
  867. {
  868. return $this->_encrypt($data, false, null, $armor);
  869. }
  870. // }}}
  871. // {{{ encryptFile()
  872. /**
  873. * Encrypts a file
  874. *
  875. * Encrypted data is ASCII armored by default but may optionally be saved
  876. * as binary.
  877. *
  878. * @param string $filename the filename of the file to encrypt.
  879. * @param string $encryptedFile optional. The filename of the file in
  880. * which to store the encrypted data. If null
  881. * or unspecified, the encrypted data is
  882. * returned as a string.
  883. * @param boolean $armor optional. If true, ASCII armored data is
  884. * returned; otherwise, binary data is
  885. * returned. Defaults to true.
  886. *
  887. * @return void|string if the <kbd>$encryptedFile</kbd> parameter is null,
  888. * a string containing the encrypted data is returned.
  889. *
  890. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
  891. * See {@link Crypt_GPG::addEncryptKey()}.
  892. *
  893. * @throws Crypt_GPG_FileException if the output file is not writeable or
  894. * if the input file is not readable.
  895. *
  896. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  897. * Use the <kbd>debug</kbd> option and file a bug report if these
  898. * exceptions occur.
  899. */
  900. public function encryptFile($filename, $encryptedFile = null, $armor = true)
  901. {
  902. return $this->_encrypt($filename, true, $encryptedFile, $armor);
  903. }
  904. // }}}
  905. // {{{ encryptAndSign()
  906. /**
  907. * Encrypts and signs data
  908. *
  909. * Data is encrypted and signed in a single pass.
  910. *
  911. * NOTE: Until GnuPG version 1.4.10, it was not possible to verify
  912. * encrypted-signed data without decrypting it at the same time. If you try
  913. * to use {@link Crypt_GPG::verify()} method on encrypted-signed data with
  914. * earlier GnuPG versions, you will get an error. Please use
  915. * {@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data.
  916. *
  917. * @param string $data the data to be encrypted and signed.
  918. * @param boolean $armor optional. If true, ASCII armored data is returned;
  919. * otherwise, binary data is returned. Defaults to
  920. * true.
  921. *
  922. * @return string the encrypted signed data.
  923. *
  924. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
  925. * or if no signing key is specified. See
  926. * {@link Crypt_GPG::addEncryptKey()} and
  927. * {@link Crypt_GPG::addSignKey()}.
  928. *
  929. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  930. * incorrect or if a required passphrase is not specified.
  931. *
  932. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  933. * Use the <kbd>debug</kbd> option and file a bug report if these
  934. * exceptions occur.
  935. *
  936. * @see Crypt_GPG::decryptAndVerify()
  937. */
  938. public function encryptAndSign($data, $armor = true)
  939. {
  940. return $this->_encryptAndSign($data, false, null, $armor);
  941. }
  942. // }}}
  943. // {{{ encryptAndSignFile()
  944. /**
  945. * Encrypts and signs a file
  946. *
  947. * The file is encrypted and signed in a single pass.
  948. *
  949. * NOTE: Until GnuPG version 1.4.10, it was not possible to verify
  950. * encrypted-signed files without decrypting them at the same time. If you
  951. * try to use {@link Crypt_GPG::verify()} method on encrypted-signed files
  952. * with earlier GnuPG versions, you will get an error. Please use
  953. * {@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed
  954. * files.
  955. *
  956. * @param string $filename the name of the file containing the data to
  957. * be encrypted and signed.
  958. * @param string $signedFile optional. The name of the file in which the
  959. * encrypted, signed data should be stored. If
  960. * null or unspecified, the encrypted, signed
  961. * data is returned as a string.
  962. * @param boolean $armor optional. If true, ASCII armored data is
  963. * returned; otherwise, binary data is returned.
  964. * Defaults to true.
  965. *
  966. * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a
  967. * string containing the encrypted, signed data is
  968. * returned.
  969. *
  970. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
  971. * or if no signing key is specified. See
  972. * {@link Crypt_GPG::addEncryptKey()} and
  973. * {@link Crypt_GPG::addSignKey()}.
  974. *
  975. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  976. * incorrect or if a required passphrase is not specified.
  977. *
  978. * @throws Crypt_GPG_FileException if the output file is not writeable or
  979. * if the input file is not readable.
  980. *
  981. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  982. * Use the <kbd>debug</kbd> option and file a bug report if these
  983. * exceptions occur.
  984. *
  985. * @see Crypt_GPG::decryptAndVerifyFile()
  986. */
  987. public function encryptAndSignFile($filename, $signedFile = null,
  988. $armor = true
  989. ) {
  990. return $this->_encryptAndSign($filename, true, $signedFile, $armor);
  991. }
  992. // }}}
  993. // {{{ decrypt()
  994. /**
  995. * Decrypts string data
  996. *
  997. * This method assumes the required private key is available in the keyring
  998. * and throws an exception if the private key is not available. To add a
  999. * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
  1000. * {@link Crypt_GPG::importKeyFile()} methods.
  1001. *
  1002. * @param string $encryptedData the data to be decrypted.
  1003. *
  1004. * @return string the decrypted data.
  1005. *
  1006. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  1007. * decrypt the data is not in the user's keyring.
  1008. *
  1009. * @throws Crypt_GPG_NoDataException if specified data does not contain
  1010. * GPG encrypted data.
  1011. *
  1012. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  1013. * incorrect or if a required passphrase is not specified. See
  1014. * {@link Crypt_GPG::addDecryptKey()}.
  1015. *
  1016. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1017. * Use the <kbd>debug</kbd> option and file a bug report if these
  1018. * exceptions occur.
  1019. */
  1020. public function decrypt($encryptedData)
  1021. {
  1022. return $this->_decrypt($encryptedData, false, null);
  1023. }
  1024. // }}}
  1025. // {{{ decryptFile()
  1026. /**
  1027. * Decrypts a file
  1028. *
  1029. * This method assumes the required private key is available in the keyring
  1030. * and throws an exception if the private key is not available. To add a
  1031. * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
  1032. * {@link Crypt_GPG::importKeyFile()} methods.
  1033. *
  1034. * @param string $encryptedFile the name of the encrypted file data to
  1035. * decrypt.
  1036. * @param string $decryptedFile optional. The name of the file to which the
  1037. * decrypted data should be written. If null
  1038. * or unspecified, the decrypted data is
  1039. * returned as a string.
  1040. *
  1041. * @return void|string if the <kbd>$decryptedFile</kbd> parameter is null,
  1042. * a string containing the decrypted data is returned.
  1043. *
  1044. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  1045. * decrypt the data is not in the user's keyring.
  1046. *
  1047. * @throws Crypt_GPG_NoDataException if specified data does not contain
  1048. * GPG encrypted data.
  1049. *
  1050. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  1051. * incorrect or if a required passphrase is not specified. See
  1052. * {@link Crypt_GPG::addDecryptKey()}.
  1053. *
  1054. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1055. * if the input file is not readable.
  1056. *
  1057. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1058. * Use the <kbd>debug</kbd> option and file a bug report if these
  1059. * exceptions occur.
  1060. */
  1061. public function decryptFile($encryptedFile, $decryptedFile = null)
  1062. {
  1063. return $this->_decrypt($encryptedFile, true, $decryptedFile);
  1064. }
  1065. // }}}
  1066. // {{{ decryptAndVerify()
  1067. /**
  1068. * Decrypts and verifies string data
  1069. *
  1070. * This method assumes the required private key is available in the keyring
  1071. * and throws an exception if the private key is not available. To add a
  1072. * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
  1073. * {@link Crypt_GPG::importKeyFile()} methods.
  1074. *
  1075. * @param string $encryptedData the encrypted, signed data to be decrypted
  1076. * and verified.
  1077. *
  1078. * @return array two element array. The array has an element 'data'
  1079. * containing the decrypted data and an element
  1080. * 'signatures' containing an array of
  1081. * {@link Crypt_GPG_Signature} objects for the signed data.
  1082. *
  1083. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  1084. * decrypt the data is not in the user's keyring.
  1085. *
  1086. * @throws Crypt_GPG_NoDataException if specified data does not contain
  1087. * GPG encrypted data.
  1088. *
  1089. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  1090. * incorrect or if a required passphrase is not specified. See
  1091. * {@link Crypt_GPG::addDecryptKey()}.
  1092. *
  1093. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1094. * Use the <kbd>debug</kbd> option and file a bug report if these
  1095. * exceptions occur.
  1096. */
  1097. public function decryptAndVerify($encryptedData)
  1098. {
  1099. return $this->_decryptAndVerify($encryptedData, false, null);
  1100. }
  1101. // }}}
  1102. // {{{ decryptAndVerifyFile()
  1103. /**
  1104. * Decrypts and verifies a signed, encrypted file
  1105. *
  1106. * This method assumes the required private key is available in the keyring
  1107. * and throws an exception if the private key is not available. To add a
  1108. * private key to the keyring, use the {@link Crypt_GPG::importKey()} or
  1109. * {@link Crypt_GPG::importKeyFile()} methods.
  1110. *
  1111. * @param string $encryptedFile the name of the signed, encrypted file to
  1112. * to decrypt and verify.
  1113. * @param string $decryptedFile optional. The name of the file to which the
  1114. * decrypted data should be written. If null
  1115. * or unspecified, the decrypted data is
  1116. * returned in the results array.
  1117. *
  1118. * @return array two element array. The array has an element 'data'
  1119. * containing the decrypted data and an element
  1120. * 'signatures' containing an array of
  1121. * {@link Crypt_GPG_Signature} objects for the signed data.
  1122. * If the decrypted data is written to a file, the 'data'
  1123. * element is null.
  1124. *
  1125. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  1126. * decrypt the data is not in the user's keyring.
  1127. *
  1128. * @throws Crypt_GPG_NoDataException if specified data does not contain
  1129. * GPG encrypted data.
  1130. *
  1131. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  1132. * incorrect or if a required passphrase is not specified. See
  1133. * {@link Crypt_GPG::addDecryptKey()}.
  1134. *
  1135. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1136. * if the input file is not readable.
  1137. *
  1138. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1139. * Use the <kbd>debug</kbd> option and file a bug report if these
  1140. * exceptions occur.
  1141. */
  1142. public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null)
  1143. {
  1144. return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile);
  1145. }
  1146. // }}}
  1147. // {{{ sign()
  1148. /**
  1149. * Signs data
  1150. *
  1151. * Data may be signed using any one of the three available signing modes:
  1152. * - {@link Crypt_GPG::SIGN_MODE_NORMAL}
  1153. * - {@link Crypt_GPG::SIGN_MODE_CLEAR}
  1154. * - {@link Crypt_GPG::SIGN_MODE_DETACHED}
  1155. *
  1156. * @param string $data the data to be signed.
  1157. * @param boolean $mode optional. The data signing mode to use. Should
  1158. * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL},
  1159. * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
  1160. * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not
  1161. * specified, defaults to
  1162. * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>.
  1163. * @param boolean $armor optional. If true, ASCII armored data is
  1164. * returned; otherwise, binary data is returned.
  1165. * Defaults to true. This has no effect if the
  1166. * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1167. * used.
  1168. * @param boolean $textmode optional. If true, line-breaks in signed data
  1169. * are normalized. Use this option when signing
  1170. * e-mail, or for greater compatibility between
  1171. * systems with different line-break formats.
  1172. * Defaults to false. This has no effect if the
  1173. * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1174. * used as clear-signing always uses textmode.
  1175. *
  1176. * @return string the signed data, or the signature data if a detached
  1177. * signature is requested.
  1178. *
  1179. * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
  1180. * See {@link Crypt_GPG::addSignKey()}.
  1181. *
  1182. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  1183. * incorrect or if a required passphrase is not specified.
  1184. *
  1185. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1186. * Use the <kbd>debug</kbd> option and file a bug report if these
  1187. * exceptions occur.
  1188. */
  1189. public function sign($data, $mode = Crypt_GPG::SIGN_MODE_NORMAL,
  1190. $armor = true, $textmode = false
  1191. ) {
  1192. return $this->_sign($data, false, null, $mode, $armor, $textmode);
  1193. }
  1194. // }}}
  1195. // {{{ signFile()
  1196. /**
  1197. * Signs a file
  1198. *
  1199. * The file may be signed using any one of the three available signing
  1200. * modes:
  1201. * - {@link Crypt_GPG::SIGN_MODE_NORMAL}
  1202. * - {@link Crypt_GPG::SIGN_MODE_CLEAR}
  1203. * - {@link Crypt_GPG::SIGN_MODE_DETACHED}
  1204. *
  1205. * @param string $filename the name of the file containing the data to
  1206. * be signed.
  1207. * @param string $signedFile optional. The name of the file in which the
  1208. * signed data should be stored. If null or
  1209. * unspecified, the signed data is returned as a
  1210. * string.
  1211. * @param boolean $mode optional. The data signing mode to use. Should
  1212. * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL},
  1213. * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
  1214. * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not
  1215. * specified, defaults to
  1216. * <kbd>Crypt_GPG::SIGN_MODE_NORMAL</kbd>.
  1217. * @param boolean $armor optional. If true, ASCII armored data is
  1218. * returned; otherwise, binary data is returned.
  1219. * Defaults to true. This has no effect if the
  1220. * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1221. * used.
  1222. * @param boolean $textmode optional. If true, line-breaks in signed data
  1223. * are normalized. Use this option when signing
  1224. * e-mail, or for greater compatibility between
  1225. * systems with different line-break formats.
  1226. * Defaults to false. This has no effect if the
  1227. * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1228. * used as clear-signing always uses textmode.
  1229. *
  1230. * @return void|string if the <kbd>$signedFile</kbd> parameter is null, a
  1231. * string containing the signed data (or the signature
  1232. * data if a detached signature is requested) is
  1233. * returned.
  1234. *
  1235. * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
  1236. * See {@link Crypt_GPG::addSignKey()}.
  1237. *
  1238. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  1239. * incorrect or if a required passphrase is not specified.
  1240. *
  1241. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1242. * if the input file is not readable.
  1243. *
  1244. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1245. * Use the <kbd>debug</kbd> option and file a bug report if these
  1246. * exceptions occur.
  1247. */
  1248. public function signFile($filename, $signedFile = null,
  1249. $mode = Crypt_GPG::SIGN_MODE_NORMAL, $armor = true, $textmode = false
  1250. ) {
  1251. return $this->_sign(
  1252. $filename,
  1253. true,
  1254. $signedFile,
  1255. $mode,
  1256. $armor,
  1257. $textmode
  1258. );
  1259. }
  1260. // }}}
  1261. // {{{ verify()
  1262. /**
  1263. * Verifies signed data
  1264. *
  1265. * The {@link Crypt_GPG::decrypt()} method may be used to get the original
  1266. * message if the signed data is not clearsigned and does not use a
  1267. * detached signature.
  1268. *
  1269. * @param string $signedData the signed data to be verified.
  1270. * @param string $signature optional. If verifying data signed using a
  1271. * detached signature, this must be the detached
  1272. * signature data. The data that was signed is
  1273. * specified in <kbd>$signedData</kbd>.
  1274. *
  1275. * @return array an array of {@link Crypt_GPG_Signature} objects for the
  1276. * signed data. For each signature that is valid, the
  1277. * {@link Crypt_GPG_Signature::isValid()} will return true.
  1278. *
  1279. * @throws Crypt_GPG_NoDataException if the provided data is not signed
  1280. * data.
  1281. *
  1282. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1283. * Use the <kbd>debug</kbd> option and file a bug report if these
  1284. * exceptions occur.
  1285. *
  1286. * @see Crypt_GPG_Signature
  1287. */
  1288. public function verify($signedData, $signature = '')
  1289. {
  1290. return $this->_verify($signedData, false, $signature);
  1291. }
  1292. // }}}
  1293. // {{{ verifyFile()
  1294. /**
  1295. * Verifies a signed file
  1296. *
  1297. * The {@link Crypt_GPG::decryptFile()} method may be used to get the
  1298. * original message if the signed data is not clearsigned and does not use
  1299. * a detached signature.
  1300. *
  1301. * @param string $filename the signed file to be verified.
  1302. * @param string $signature optional. If verifying a file signed using a
  1303. * detached signature, this must be the detached
  1304. * signature data. The file that was signed is
  1305. * specified in <kbd>$filename</kbd>.
  1306. *
  1307. * @return array an array of {@link Crypt_GPG_Signature} objects for the
  1308. * signed data. For each signature that is valid, the
  1309. * {@link Crypt_GPG_Signature::isValid()} will return true.
  1310. *
  1311. * @throws Crypt_GPG_NoDataException if the provided data is not signed
  1312. * data.
  1313. *
  1314. * @throws Crypt_GPG_FileException if the input file is not readable.
  1315. *
  1316. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1317. * Use the <kbd>debug</kbd> option and file a bug report if these
  1318. * exceptions occur.
  1319. *
  1320. * @see Crypt_GPG_Signature
  1321. */
  1322. public function verifyFile($filename, $signature = '')
  1323. {
  1324. return $this->_verify($filename, true, $signature);
  1325. }
  1326. // }}}
  1327. // {{{ addDecryptKey()
  1328. /**
  1329. * Adds a key to use for decryption
  1330. *
  1331. * @param mixed $key the key to use. This may be a key identifier,
  1332. * user id, fingerprint, {@link Crypt_GPG_Key} or
  1333. * {@link Crypt_GPG_SubKey}. The key must be able
  1334. * to encrypt.
  1335. * @param string $passphrase optional. The passphrase of the key required
  1336. * for decryption.
  1337. *
  1338. * @return void
  1339. *
  1340. * @see Crypt_GPG::decrypt()
  1341. * @see Crypt_GPG::decryptFile()
  1342. * @see Crypt_GPG::clearDecryptKeys()
  1343. * @see Crypt_GPG::_addKey()
  1344. * @see Crypt_GPG_DecryptStatusHandler
  1345. *
  1346. * @sensitive $passphrase
  1347. */
  1348. public function addDecryptKey($key, $passphrase = null)
  1349. {
  1350. $this->_addKey($this->decryptKeys, true, false, $key, $passphrase);
  1351. }
  1352. // }}}
  1353. // {{{ addEncryptKey()
  1354. /**
  1355. * Adds a key to use for encryption
  1356. *
  1357. * @param mixed $key the key to use. This may be a key identifier, user id
  1358. * user id, fingerprint, {@link Crypt_GPG_Key} or
  1359. * {@link Crypt_GPG_SubKey}. The key must be able to
  1360. * encrypt.
  1361. *
  1362. * @return void
  1363. *
  1364. * @see Crypt_GPG::encrypt()
  1365. * @see Crypt_GPG::encryptFile()
  1366. * @see Crypt_GPG::clearEncryptKeys()
  1367. * @see Crypt_GPG::_addKey()
  1368. */
  1369. public function addEncryptKey($key)
  1370. {
  1371. $this->_addKey($this->encryptKeys, true, false, $key);
  1372. }
  1373. // }}}
  1374. // {{{ addSignKey()
  1375. /**
  1376. * Adds a key to use for signing
  1377. *
  1378. * @param mixed $key the key to use. This may be a key identifier,
  1379. * user id, fingerprint, {@link Crypt_GPG_Key} or
  1380. * {@link Crypt_GPG_SubKey}. The key must be able
  1381. * to sign.
  1382. * @param string $passphrase optional. The passphrase of the key required
  1383. * for signing.
  1384. *
  1385. * @return void
  1386. *
  1387. * @see Crypt_GPG::sign()
  1388. * @see Crypt_GPG::signFile()
  1389. * @see Crypt_GPG::clearSignKeys()
  1390. * @see Crypt_GPG::handleSignStatus()
  1391. * @see Crypt_GPG::_addKey()
  1392. *
  1393. * @sensitive $passphrase
  1394. */
  1395. public function addSignKey($key, $passphrase = null)
  1396. {
  1397. $this->_addKey($this->signKeys, false, true, $key, $passphrase);
  1398. }
  1399. // }}}
  1400. // {{{ clearDecryptKeys()
  1401. /**
  1402. * Clears all decryption keys
  1403. *
  1404. * @return void
  1405. *
  1406. * @see Crypt_GPG::decrypt()
  1407. * @see Crypt_GPG::addDecryptKey()
  1408. */
  1409. public function clearDecryptKeys()
  1410. {
  1411. $this->decryptKeys = array();
  1412. }
  1413. // }}}
  1414. // {{{ clearEncryptKeys()
  1415. /**
  1416. * Clears all encryption keys
  1417. *
  1418. * @return void
  1419. *
  1420. * @see Crypt_GPG::encrypt()
  1421. * @see Crypt_GPG::addEncryptKey()
  1422. */
  1423. public function clearEncryptKeys()
  1424. {
  1425. $this->encryptKeys = array();
  1426. }
  1427. // }}}
  1428. // {{{ clearSignKeys()
  1429. /**
  1430. * Clears all signing keys
  1431. *
  1432. * @return void
  1433. *
  1434. * @see Crypt_GPG::sign()
  1435. * @see Crypt_GPG::addSignKey()
  1436. */
  1437. public function clearSignKeys()
  1438. {
  1439. $this->signKeys = array();
  1440. }
  1441. // }}}
  1442. // {{{ handleSignStatus()
  1443. /**
  1444. * Handles the status output from GPG for the sign operation
  1445. *
  1446. * This method is responsible for sending the passphrase commands when
  1447. * required by the {@link Crypt_GPG::sign()} method. See <b>doc/DETAILS</b>
  1448. * in the {@link http://www.gnupg.org/download/ GPG distribution} for
  1449. * detailed information on GPG's status output.
  1450. *
  1451. * @param string $line the status line to handle.
  1452. *
  1453. * @return void
  1454. *
  1455. * @see Crypt_GPG::sign()
  1456. */
  1457. public function handleSignStatus($line)
  1458. {
  1459. $tokens = explode(' ', $line);
  1460. switch ($tokens[0]) {
  1461. case 'NEED_PASSPHRASE':
  1462. $subKeyId = $tokens[1];
  1463. if (array_key_exists($subKeyId, $this->signKeys)) {
  1464. $passphrase = $this->signKeys[$subKeyId]['passphrase'];
  1465. $this->engine->sendCommand($passphrase);
  1466. } else {
  1467. $this->engine->sendCommand('');
  1468. }
  1469. break;
  1470. }
  1471. }
  1472. // }}}
  1473. // {{{ handleImportKeyStatus()
  1474. /**
  1475. * Handles the status output from GPG for the import operation
  1476. *
  1477. * This method is responsible for building the result array that is
  1478. * returned from the {@link Crypt_GPG::importKey()} method. See
  1479. * <b>doc/DETAILS</b> in the
  1480. * {@link http://www.gnupg.org/download/ GPG distribution} for detailed
  1481. * information on GPG's status output.
  1482. *
  1483. * @param string $line the status line to handle.
  1484. * @param array &$result the current result array being processed.
  1485. *
  1486. * @return void
  1487. *
  1488. * @see Crypt_GPG::importKey()
  1489. * @see Crypt_GPG::importKeyFile()
  1490. * @see Crypt_GPG_Engine::addStatusHandler()
  1491. */
  1492. public function handleImportKeyStatus($line, array &$result)
  1493. {
  1494. $tokens = explode(' ', $line);
  1495. switch ($tokens[0]) {
  1496. case 'IMPORT_OK':
  1497. $result['fingerprint'] = $tokens[2];
  1498. break;
  1499. case 'IMPORT_RES':
  1500. $result['public_imported'] = intval($tokens[3]);
  1501. $result['public_unchanged'] = intval($tokens[5]);
  1502. $result['private_imported'] = intval($tokens[11]);
  1503. $result['private_unchanged'] = intval($tokens[12]);
  1504. break;
  1505. }
  1506. }
  1507. // }}}
  1508. // {{{ setEngine()
  1509. /**
  1510. * Sets the I/O engine to use for GnuPG operations
  1511. *
  1512. * Normally this method does not need to be used. It provides a means for
  1513. * dependency injection.
  1514. *
  1515. * @param Crypt_GPG_Engine $engine the engine to use.
  1516. *
  1517. * @return void
  1518. */
  1519. public function setEngine(Crypt_GPG_Engine $engine)
  1520. {
  1521. $this->engine = $engine;
  1522. }
  1523. // }}}
  1524. // {{{ _addKey()
  1525. /**
  1526. * Adds a key to one of the internal key arrays
  1527. *
  1528. * This handles resolving full key objects from the provided
  1529. * <kbd>$key</kbd> value.
  1530. *
  1531. * @param array &$array the array to which the key should be added.
  1532. * @param boolean $encrypt whether or not the key must be able to
  1533. * encrypt.
  1534. * @param boolean $sign whether or not the key must be able to sign.
  1535. * @param mixed $key the key to add. This may be a key identifier,
  1536. * user id, fingerprint, {@link Crypt_GPG_Key} or
  1537. * {@link Crypt_GPG_SubKey}.
  1538. * @param string $passphrase optional. The passphrase associated with the
  1539. * key.
  1540. *
  1541. * @return void
  1542. *
  1543. * @sensitive $passphrase
  1544. */
  1545. private function _addKey(array &$array, $encrypt, $sign, $key,
  1546. $passphrase = null
  1547. ) {
  1548. $subKeys = array();
  1549. if (is_scalar($key)) {
  1550. $keys = $this->getKeys($key);
  1551. if (count($keys) == 0) {
  1552. throw new Crypt_GPG_KeyNotFoundException(
  1553. 'Key "' . $key . '" not found.', 0, $key);
  1554. }
  1555. $key = $keys[0];
  1556. }
  1557. if ($key instanceof Crypt_GPG_Key) {
  1558. if ($encrypt && !$key->canEncrypt()) {
  1559. throw new InvalidArgumentException(
  1560. 'Key "' . $key . '" cannot encrypt.');
  1561. }
  1562. if ($sign && !$key->canSign()) {
  1563. throw new InvalidArgumentException(
  1564. 'Key "' . $key . '" cannot sign.');
  1565. }
  1566. foreach ($key->getSubKeys() as $subKey) {
  1567. $canEncrypt = $subKey->canEncrypt();
  1568. $canSign = $subKey->canSign();
  1569. if ( ($encrypt && $sign && $canEncrypt && $canSign)
  1570. || ($encrypt && !$sign && $canEncrypt)
  1571. || (!$encrypt && $sign && $canSign)
  1572. ) {
  1573. // We add all subkeys that meet the requirements because we
  1574. // were not told which subkey is required.
  1575. $subKeys[] = $subKey;
  1576. }
  1577. }
  1578. } elseif ($key instanceof Crypt_GPG_SubKey) {
  1579. $subKeys[] = $key;
  1580. }
  1581. if (count($subKeys) === 0) {
  1582. throw new InvalidArgumentException(
  1583. 'Key "' . $key . '" is not in a recognized format.');
  1584. }
  1585. foreach ($subKeys as $subKey) {
  1586. if ($encrypt && !$subKey->canEncrypt()) {
  1587. throw new InvalidArgumentException(
  1588. 'Key "' . $key . '" cannot encrypt.');
  1589. }
  1590. if ($sign && !$subKey->canSign()) {
  1591. throw new InvalidArgumentException(
  1592. 'Key "' . $key . '" cannot sign.');
  1593. }
  1594. $array[$subKey->getId()] = array(
  1595. 'fingerprint' => $subKey->getFingerprint(),
  1596. 'passphrase' => $passphrase
  1597. );
  1598. }
  1599. }
  1600. // }}}
  1601. // {{{ _importKey()
  1602. /**
  1603. * Imports a public or private key into the keyring
  1604. *
  1605. * @param string $key the key to be imported.
  1606. * @param boolean $isFile whether or not the input is a filename.
  1607. *
  1608. * @return array an associative array containing the following elements:
  1609. * - <kbd>fingerprint</kbd> - the fingerprint of the
  1610. * imported key,
  1611. * - <kbd>public_imported</kbd> - the number of public
  1612. * keys imported,
  1613. * - <kbd>public_unchanged</kbd> - the number of unchanged
  1614. * public keys,
  1615. * - <kbd>private_imported</kbd> - the number of private
  1616. * keys imported,
  1617. * - <kbd>private_unchanged</kbd> - the number of unchanged
  1618. * private keys.
  1619. *
  1620. * @throws Crypt_GPG_NoDataException if the key data is missing or if the
  1621. * data is is not valid key data.
  1622. *
  1623. * @throws Crypt_GPG_FileException if the key file is not readable.
  1624. *
  1625. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1626. * Use the <kbd>debug</kbd> option and file a bug report if these
  1627. * exceptions occur.
  1628. */
  1629. private function _importKey($key, $isFile)
  1630. {
  1631. $result = array();
  1632. if ($isFile) {
  1633. $input = @fopen($key, 'rb');
  1634. if ($input === false) {
  1635. throw new Crypt_GPG_FileException('Could not open key file "' .
  1636. $key . '" for importing.', 0, $key);
  1637. }
  1638. } else {
  1639. $input = strval($key);
  1640. if ($input == '') {
  1641. throw new Crypt_GPG_NoDataException(
  1642. 'No valid GPG key data found.', Crypt_GPG::ERROR_NO_DATA);
  1643. }
  1644. }
  1645. $arguments = array();
  1646. $version = $this->engine->getVersion();
  1647. if ( version_compare($version, '1.0.5', 'ge')
  1648. && version_compare($version, '1.0.7', 'lt')
  1649. ) {
  1650. $arguments[] = '--allow-secret-key-import';
  1651. }
  1652. $this->engine->reset();
  1653. $this->engine->addStatusHandler(
  1654. array($this, 'handleImportKeyStatus'),
  1655. array(&$result)
  1656. );
  1657. $this->engine->setOperation('--import', $arguments);
  1658. $this->engine->setInput($input);
  1659. $this->engine->run();
  1660. if ($isFile) {
  1661. fclose($input);
  1662. }
  1663. $code = $this->engine->getErrorCode();
  1664. switch ($code) {
  1665. case Crypt_GPG::ERROR_DUPLICATE_KEY:
  1666. case Crypt_GPG::ERROR_NONE:
  1667. // ignore duplicate key import errors
  1668. break;
  1669. case Crypt_GPG::ERROR_NO_DATA:
  1670. throw new Crypt_GPG_NoDataException(
  1671. 'No valid GPG key data found.', $code);
  1672. default:
  1673. throw new Crypt_GPG_Exception(
  1674. 'Unknown error importing GPG key. Please use the \'debug\' ' .
  1675. 'option when creating the Crypt_GPG object, and file a bug ' .
  1676. 'report at ' . self::BUG_URI, $code);
  1677. }
  1678. return $result;
  1679. }
  1680. // }}}
  1681. // {{{ _encrypt()
  1682. /**
  1683. * Encrypts data
  1684. *
  1685. * @param string $data the data to encrypt.
  1686. * @param boolean $isFile whether or not the data is a filename.
  1687. * @param string $outputFile the filename of the file in which to store
  1688. * the encrypted data. If null, the encrypted
  1689. * data is returned as a string.
  1690. * @param boolean $armor if true, ASCII armored data is returned;
  1691. * otherwise, binary data is returned.
  1692. *
  1693. * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
  1694. * string containing the encrypted data is returned.
  1695. *
  1696. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified.
  1697. * See {@link Crypt_GPG::addEncryptKey()}.
  1698. *
  1699. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1700. * if the input file is not readable.
  1701. *
  1702. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1703. * Use the <kbd>debug</kbd> option and file a bug report if these
  1704. * exceptions occur.
  1705. */
  1706. private function _encrypt($data, $isFile, $outputFile, $armor)
  1707. {
  1708. if (count($this->encryptKeys) === 0) {
  1709. throw new Crypt_GPG_KeyNotFoundException(
  1710. 'No encryption keys specified.');
  1711. }
  1712. if ($isFile) {
  1713. $input = @fopen($data, 'rb');
  1714. if ($input === false) {
  1715. throw new Crypt_GPG_FileException('Could not open input file "' .
  1716. $data . '" for encryption.', 0, $data);
  1717. }
  1718. } else {
  1719. $input = strval($data);
  1720. }
  1721. if ($outputFile === null) {
  1722. $output = '';
  1723. } else {
  1724. $output = @fopen($outputFile, 'wb');
  1725. if ($output === false) {
  1726. if ($isFile) {
  1727. fclose($input);
  1728. }
  1729. throw new Crypt_GPG_FileException('Could not open output ' .
  1730. 'file "' . $outputFile . '" for storing encrypted data.',
  1731. 0, $outputFile);
  1732. }
  1733. }
  1734. $arguments = ($armor) ? array('--armor') : array();
  1735. foreach ($this->encryptKeys as $key) {
  1736. $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']);
  1737. }
  1738. $this->engine->reset();
  1739. $this->engine->setInput($input);
  1740. $this->engine->setOutput($output);
  1741. $this->engine->setOperation('--encrypt', $arguments);
  1742. $this->engine->run();
  1743. if ($isFile) {
  1744. fclose($input);
  1745. }
  1746. if ($outputFile !== null) {
  1747. fclose($output);
  1748. }
  1749. $code = $this->engine->getErrorCode();
  1750. if ($code !== Crypt_GPG::ERROR_NONE) {
  1751. throw new Crypt_GPG_Exception(
  1752. 'Unknown error encrypting data. Please use the \'debug\' ' .
  1753. 'option when creating the Crypt_GPG object, and file a bug ' .
  1754. 'report at ' . self::BUG_URI, $code);
  1755. }
  1756. if ($outputFile === null) {
  1757. return $output;
  1758. }
  1759. }
  1760. // }}}
  1761. // {{{ _decrypt()
  1762. /**
  1763. * Decrypts data
  1764. *
  1765. * @param string $data the data to be decrypted.
  1766. * @param boolean $isFile whether or not the data is a filename.
  1767. * @param string $outputFile the name of the file to which the decrypted
  1768. * data should be written. If null, the decrypted
  1769. * data is returned as a string.
  1770. *
  1771. * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
  1772. * string containing the decrypted data is returned.
  1773. *
  1774. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  1775. * decrypt the data is not in the user's keyring.
  1776. *
  1777. * @throws Crypt_GPG_NoDataException if specified data does not contain
  1778. * GPG encrypted data.
  1779. *
  1780. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  1781. * incorrect or if a required passphrase is not specified. See
  1782. * {@link Crypt_GPG::addDecryptKey()}.
  1783. *
  1784. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1785. * if the input file is not readable.
  1786. *
  1787. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1788. * Use the <kbd>debug</kbd> option and file a bug report if these
  1789. * exceptions occur.
  1790. */
  1791. private function _decrypt($data, $isFile, $outputFile)
  1792. {
  1793. if ($isFile) {
  1794. $input = @fopen($data, 'rb');
  1795. if ($input === false) {
  1796. throw new Crypt_GPG_FileException('Could not open input file "' .
  1797. $data . '" for decryption.', 0, $data);
  1798. }
  1799. } else {
  1800. $input = strval($data);
  1801. if ($input == '') {
  1802. throw new Crypt_GPG_NoDataException(
  1803. 'Cannot decrypt data. No PGP encrypted data was found in '.
  1804. 'the provided data.', Crypt_GPG::ERROR_NO_DATA);
  1805. }
  1806. }
  1807. if ($outputFile === null) {
  1808. $output = '';
  1809. } else {
  1810. $output = @fopen($outputFile, 'wb');
  1811. if ($output === false) {
  1812. if ($isFile) {
  1813. fclose($input);
  1814. }
  1815. throw new Crypt_GPG_FileException('Could not open output ' .
  1816. 'file "' . $outputFile . '" for storing decrypted data.',
  1817. 0, $outputFile);
  1818. }
  1819. }
  1820. $handler = new Crypt_GPG_DecryptStatusHandler($this->engine,
  1821. $this->decryptKeys);
  1822. $this->engine->reset();
  1823. $this->engine->addStatusHandler(array($handler, 'handle'));
  1824. $this->engine->setOperation('--decrypt');
  1825. $this->engine->setInput($input);
  1826. $this->engine->setOutput($output);
  1827. $this->engine->run();
  1828. if ($isFile) {
  1829. fclose($input);
  1830. }
  1831. if ($outputFile !== null) {
  1832. fclose($output);
  1833. }
  1834. // if there was any problem decrypting the data, the handler will
  1835. // deal with it here.
  1836. $handler->throwException();
  1837. if ($outputFile === null) {
  1838. return $output;
  1839. }
  1840. }
  1841. // }}}
  1842. // {{{ _sign()
  1843. /**
  1844. * Signs data
  1845. *
  1846. * @param string $data the data to be signed.
  1847. * @param boolean $isFile whether or not the data is a filename.
  1848. * @param string $outputFile the name of the file in which the signed data
  1849. * should be stored. If null, the signed data is
  1850. * returned as a string.
  1851. * @param boolean $mode the data signing mode to use. Should be one of
  1852. * {@link Crypt_GPG::SIGN_MODE_NORMAL},
  1853. * {@link Crypt_GPG::SIGN_MODE_CLEAR} or
  1854. * {@link Crypt_GPG::SIGN_MODE_DETACHED}.
  1855. * @param boolean $armor if true, ASCII armored data is returned;
  1856. * otherwise, binary data is returned. This has
  1857. * no effect if the mode
  1858. * <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1859. * used.
  1860. * @param boolean $textmode if true, line-breaks in signed data be
  1861. * normalized. Use this option when signing
  1862. * e-mail, or for greater compatibility between
  1863. * systems with different line-break formats.
  1864. * Defaults to false. This has no effect if the
  1865. * mode <kbd>Crypt_GPG::SIGN_MODE_CLEAR</kbd> is
  1866. * used as clear-signing always uses textmode.
  1867. *
  1868. * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
  1869. * string containing the signed data (or the signature
  1870. * data if a detached signature is requested) is
  1871. * returned.
  1872. *
  1873. * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified.
  1874. * See {@link Crypt_GPG::addSignKey()}.
  1875. *
  1876. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  1877. * incorrect or if a required passphrase is not specified.
  1878. *
  1879. * @throws Crypt_GPG_FileException if the output file is not writeable or
  1880. * if the input file is not readable.
  1881. *
  1882. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  1883. * Use the <kbd>debug</kbd> option and file a bug report if these
  1884. * exceptions occur.
  1885. */
  1886. private function _sign($data, $isFile, $outputFile, $mode, $armor,
  1887. $textmode
  1888. ) {
  1889. if (count($this->signKeys) === 0) {
  1890. throw new Crypt_GPG_KeyNotFoundException(
  1891. 'No signing keys specified.');
  1892. }
  1893. if ($isFile) {
  1894. $input = @fopen($data, 'rb');
  1895. if ($input === false) {
  1896. throw new Crypt_GPG_FileException('Could not open input ' .
  1897. 'file "' . $data . '" for signing.', 0, $data);
  1898. }
  1899. } else {
  1900. $input = strval($data);
  1901. }
  1902. if ($outputFile === null) {
  1903. $output = '';
  1904. } else {
  1905. $output = @fopen($outputFile, 'wb');
  1906. if ($output === false) {
  1907. if ($isFile) {
  1908. fclose($input);
  1909. }
  1910. throw new Crypt_GPG_FileException('Could not open output ' .
  1911. 'file "' . $outputFile . '" for storing signed ' .
  1912. 'data.', 0, $outputFile);
  1913. }
  1914. }
  1915. switch ($mode) {
  1916. case Crypt_GPG::SIGN_MODE_DETACHED:
  1917. $operation = '--detach-sign';
  1918. break;
  1919. case Crypt_GPG::SIGN_MODE_CLEAR:
  1920. $operation = '--clearsign';
  1921. break;
  1922. case Crypt_GPG::SIGN_MODE_NORMAL:
  1923. default:
  1924. $operation = '--sign';
  1925. break;
  1926. }
  1927. $arguments = array();
  1928. if ($armor) {
  1929. $arguments[] = '--armor';
  1930. }
  1931. if ($textmode) {
  1932. $arguments[] = '--textmode';
  1933. }
  1934. foreach ($this->signKeys as $key) {
  1935. $arguments[] = '--local-user ' .
  1936. escapeshellarg($key['fingerprint']);
  1937. }
  1938. $this->engine->reset();
  1939. $this->engine->addStatusHandler(array($this, 'handleSignStatus'));
  1940. $this->engine->setInput($input);
  1941. $this->engine->setOutput($output);
  1942. $this->engine->setOperation($operation, $arguments);
  1943. $this->engine->run();
  1944. if ($isFile) {
  1945. fclose($input);
  1946. }
  1947. if ($outputFile !== null) {
  1948. fclose($output);
  1949. }
  1950. $code = $this->engine->getErrorCode();
  1951. switch ($code) {
  1952. case Crypt_GPG::ERROR_NONE:
  1953. break;
  1954. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  1955. throw new Crypt_GPG_KeyNotFoundException(
  1956. 'Cannot sign data. Private key not found. Import the '.
  1957. 'private key before trying to sign data.', $code,
  1958. $this->engine->getErrorKeyId());
  1959. case Crypt_GPG::ERROR_BAD_PASSPHRASE:
  1960. throw new Crypt_GPG_BadPassphraseException(
  1961. 'Cannot sign data. Incorrect passphrase provided.', $code);
  1962. case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
  1963. throw new Crypt_GPG_BadPassphraseException(
  1964. 'Cannot sign data. No passphrase provided.', $code);
  1965. default:
  1966. throw new Crypt_GPG_Exception(
  1967. 'Unknown error signing data. Please use the \'debug\' option ' .
  1968. 'when creating the Crypt_GPG object, and file a bug report ' .
  1969. 'at ' . self::BUG_URI, $code);
  1970. }
  1971. if ($outputFile === null) {
  1972. return $output;
  1973. }
  1974. }
  1975. // }}}
  1976. // {{{ _encryptAndSign()
  1977. /**
  1978. * Encrypts and signs data
  1979. *
  1980. * @param string $data the data to be encrypted and signed.
  1981. * @param boolean $isFile whether or not the data is a filename.
  1982. * @param string $outputFile the name of the file in which the encrypted,
  1983. * signed data should be stored. If null, the
  1984. * encrypted, signed data is returned as a
  1985. * string.
  1986. * @param boolean $armor if true, ASCII armored data is returned;
  1987. * otherwise, binary data is returned.
  1988. *
  1989. * @return void|string if the <kbd>$outputFile</kbd> parameter is null, a
  1990. * string containing the encrypted, signed data is
  1991. * returned.
  1992. *
  1993. * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified
  1994. * or if no signing key is specified. See
  1995. * {@link Crypt_GPG::addEncryptKey()} and
  1996. * {@link Crypt_GPG::addSignKey()}.
  1997. *
  1998. * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is
  1999. * incorrect or if a required passphrase is not specified.
  2000. *
  2001. * @throws Crypt_GPG_FileException if the output file is not writeable or
  2002. * if the input file is not readable.
  2003. *
  2004. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  2005. * Use the <kbd>debug</kbd> option and file a bug report if these
  2006. * exceptions occur.
  2007. */
  2008. private function _encryptAndSign($data, $isFile, $outputFile, $armor)
  2009. {
  2010. if (count($this->signKeys) === 0) {
  2011. throw new Crypt_GPG_KeyNotFoundException(
  2012. 'No signing keys specified.');
  2013. }
  2014. if (count($this->encryptKeys) === 0) {
  2015. throw new Crypt_GPG_KeyNotFoundException(
  2016. 'No encryption keys specified.');
  2017. }
  2018. if ($isFile) {
  2019. $input = @fopen($data, 'rb');
  2020. if ($input === false) {
  2021. throw new Crypt_GPG_FileException('Could not open input ' .
  2022. 'file "' . $data . '" for encrypting and signing.', 0,
  2023. $data);
  2024. }
  2025. } else {
  2026. $input = strval($data);
  2027. }
  2028. if ($outputFile === null) {
  2029. $output = '';
  2030. } else {
  2031. $output = @fopen($outputFile, 'wb');
  2032. if ($output === false) {
  2033. if ($isFile) {
  2034. fclose($input);
  2035. }
  2036. throw new Crypt_GPG_FileException('Could not open output ' .
  2037. 'file "' . $outputFile . '" for storing encrypted, ' .
  2038. 'signed data.', 0, $outputFile);
  2039. }
  2040. }
  2041. $arguments = ($armor) ? array('--armor') : array();
  2042. foreach ($this->signKeys as $key) {
  2043. $arguments[] = '--local-user ' .
  2044. escapeshellarg($key['fingerprint']);
  2045. }
  2046. foreach ($this->encryptKeys as $key) {
  2047. $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']);
  2048. }
  2049. $this->engine->reset();
  2050. $this->engine->addStatusHandler(array($this, 'handleSignStatus'));
  2051. $this->engine->setInput($input);
  2052. $this->engine->setOutput($output);
  2053. $this->engine->setOperation('--encrypt --sign', $arguments);
  2054. $this->engine->run();
  2055. if ($isFile) {
  2056. fclose($input);
  2057. }
  2058. if ($outputFile !== null) {
  2059. fclose($output);
  2060. }
  2061. $code = $this->engine->getErrorCode();
  2062. switch ($code) {
  2063. case Crypt_GPG::ERROR_NONE:
  2064. break;
  2065. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  2066. throw new Crypt_GPG_KeyNotFoundException(
  2067. 'Cannot sign encrypted data. Private key not found. Import '.
  2068. 'the private key before trying to sign the encrypted data.',
  2069. $code, $this->engine->getErrorKeyId());
  2070. case Crypt_GPG::ERROR_BAD_PASSPHRASE:
  2071. throw new Crypt_GPG_BadPassphraseException(
  2072. 'Cannot sign encrypted data. Incorrect passphrase provided.',
  2073. $code);
  2074. case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
  2075. throw new Crypt_GPG_BadPassphraseException(
  2076. 'Cannot sign encrypted data. No passphrase provided.', $code);
  2077. default:
  2078. throw new Crypt_GPG_Exception(
  2079. 'Unknown error encrypting and signing data. Please use the ' .
  2080. '\'debug\' option when creating the Crypt_GPG object, and ' .
  2081. 'file a bug report at ' . self::BUG_URI, $code);
  2082. }
  2083. if ($outputFile === null) {
  2084. return $output;
  2085. }
  2086. }
  2087. // }}}
  2088. // {{{ _verify()
  2089. /**
  2090. * Verifies data
  2091. *
  2092. * @param string $data the signed data to be verified.
  2093. * @param boolean $isFile whether or not the data is a filename.
  2094. * @param string $signature if verifying a file signed using a detached
  2095. * signature, this must be the detached signature
  2096. * data. Otherwise, specify ''.
  2097. *
  2098. * @return array an array of {@link Crypt_GPG_Signature} objects for the
  2099. * signed data.
  2100. *
  2101. * @throws Crypt_GPG_NoDataException if the provided data is not signed
  2102. * data.
  2103. *
  2104. * @throws Crypt_GPG_FileException if the input file is not readable.
  2105. *
  2106. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  2107. * Use the <kbd>debug</kbd> option and file a bug report if these
  2108. * exceptions occur.
  2109. *
  2110. * @see Crypt_GPG_Signature
  2111. */
  2112. private function _verify($data, $isFile, $signature)
  2113. {
  2114. if ($signature == '') {
  2115. $operation = '--verify';
  2116. $arguments = array();
  2117. } else {
  2118. // Signed data goes in FD_MESSAGE, detached signature data goes in
  2119. // FD_INPUT.
  2120. $operation = '--verify - "-&' . Crypt_GPG_Engine::FD_MESSAGE. '"';
  2121. $arguments = array('--enable-special-filenames');
  2122. }
  2123. $handler = new Crypt_GPG_VerifyStatusHandler();
  2124. if ($isFile) {
  2125. $input = @fopen($data, 'rb');
  2126. if ($input === false) {
  2127. throw new Crypt_GPG_FileException('Could not open input ' .
  2128. 'file "' . $data . '" for verifying.', 0, $data);
  2129. }
  2130. } else {
  2131. $input = strval($data);
  2132. if ($input == '') {
  2133. throw new Crypt_GPG_NoDataException(
  2134. 'No valid signature data found.', Crypt_GPG::ERROR_NO_DATA);
  2135. }
  2136. }
  2137. $this->engine->reset();
  2138. $this->engine->addStatusHandler(array($handler, 'handle'));
  2139. if ($signature == '') {
  2140. // signed or clearsigned data
  2141. $this->engine->setInput($input);
  2142. } else {
  2143. // detached signature
  2144. $this->engine->setInput($signature);
  2145. $this->engine->setMessage($input);
  2146. }
  2147. $this->engine->setOperation($operation, $arguments);
  2148. $this->engine->run();
  2149. if ($isFile) {
  2150. fclose($input);
  2151. }
  2152. $code = $this->engine->getErrorCode();
  2153. switch ($code) {
  2154. case Crypt_GPG::ERROR_NONE:
  2155. case Crypt_GPG::ERROR_BAD_SIGNATURE:
  2156. break;
  2157. case Crypt_GPG::ERROR_NO_DATA:
  2158. throw new Crypt_GPG_NoDataException(
  2159. 'No valid signature data found.', $code);
  2160. case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  2161. throw new Crypt_GPG_KeyNotFoundException(
  2162. 'Public key required for data verification not in keyring.',
  2163. $code, $this->engine->getErrorKeyId());
  2164. default:
  2165. throw new Crypt_GPG_Exception(
  2166. 'Unknown error validating signature details. Please use the ' .
  2167. '\'debug\' option when creating the Crypt_GPG object, and ' .
  2168. 'file a bug report at ' . self::BUG_URI, $code);
  2169. }
  2170. return $handler->getSignatures();
  2171. }
  2172. // }}}
  2173. // {{{ _decryptAndVerify()
  2174. /**
  2175. * Decrypts and verifies encrypted, signed data
  2176. *
  2177. * @param string $data the encrypted signed data to be decrypted and
  2178. * verified.
  2179. * @param boolean $isFile whether or not the data is a filename.
  2180. * @param string $outputFile the name of the file to which the decrypted
  2181. * data should be written. If null, the decrypted
  2182. * data is returned in the results array.
  2183. *
  2184. * @return array two element array. The array has an element 'data'
  2185. * containing the decrypted data and an element
  2186. * 'signatures' containing an array of
  2187. * {@link Crypt_GPG_Signature} objects for the signed data.
  2188. * If the decrypted data is written to a file, the 'data'
  2189. * element is null.
  2190. *
  2191. * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  2192. * decrypt the data is not in the user's keyring or it the public
  2193. * key needed for verification is not in the user's keyring.
  2194. *
  2195. * @throws Crypt_GPG_NoDataException if specified data does not contain
  2196. * GPG signed, encrypted data.
  2197. *
  2198. * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  2199. * incorrect or if a required passphrase is not specified. See
  2200. * {@link Crypt_GPG::addDecryptKey()}.
  2201. *
  2202. * @throws Crypt_GPG_FileException if the output file is not writeable or
  2203. * if the input file is not readable.
  2204. *
  2205. * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  2206. * Use the <kbd>debug</kbd> option and file a bug report if these
  2207. * exceptions occur.
  2208. *
  2209. * @see Crypt_GPG_Signature
  2210. */
  2211. private function _decryptAndVerify($data, $isFile, $outputFile)
  2212. {
  2213. if ($isFile) {
  2214. $input = @fopen($data, 'rb');
  2215. if ($input === false) {
  2216. throw new Crypt_GPG_FileException('Could not open input ' .
  2217. 'file "' . $data . '" for decrypting and verifying.', 0,
  2218. $data);
  2219. }
  2220. } else {
  2221. $input = strval($data);
  2222. if ($input == '') {
  2223. throw new Crypt_GPG_NoDataException(
  2224. 'No valid encrypted signed data found.',
  2225. Crypt_GPG::ERROR_NO_DATA);
  2226. }
  2227. }
  2228. if ($outputFile === null) {
  2229. $output = '';
  2230. } else {
  2231. $output = @fopen($outputFile, 'wb');
  2232. if ($output === false) {
  2233. if ($isFile) {
  2234. fclose($input);
  2235. }
  2236. throw new Crypt_GPG_FileException('Could not open output ' .
  2237. 'file "' . $outputFile . '" for storing decrypted data.',
  2238. 0, $outputFile);
  2239. }
  2240. }
  2241. $verifyHandler = new Crypt_GPG_VerifyStatusHandler();
  2242. $decryptHandler = new Crypt_GPG_DecryptStatusHandler($this->engine,
  2243. $this->decryptKeys);
  2244. $this->engine->reset();
  2245. $this->engine->addStatusHandler(array($verifyHandler, 'handle'));
  2246. $this->engine->addStatusHandler(array($decryptHandler, 'handle'));
  2247. $this->engine->setInput($input);
  2248. $this->engine->setOutput($output);
  2249. $this->engine->setOperation('--decrypt');
  2250. $this->engine->run();
  2251. if ($isFile) {
  2252. fclose($input);
  2253. }
  2254. if ($outputFile !== null) {
  2255. fclose($output);
  2256. }
  2257. $return = array(
  2258. 'data' => null,
  2259. 'signatures' => $verifyHandler->getSignatures()
  2260. );
  2261. // if there was any problem decrypting the data, the handler will
  2262. // deal with it here.
  2263. try {
  2264. $decryptHandler->throwException();
  2265. } catch (Exception $e) {
  2266. if ($e instanceof Crypt_GPG_KeyNotFoundException) {
  2267. throw new Crypt_GPG_KeyNotFoundException(
  2268. 'Public key required for data verification not in ',
  2269. 'the keyring. Either no suitable private decryption key ' .
  2270. 'is in the keyring or the public key required for data ' .
  2271. 'verification is not in the keyring. Import a suitable ' .
  2272. 'key before trying to decrypt and verify this data.',
  2273. self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId());
  2274. }
  2275. if ($e instanceof Crypt_GPG_NoDataException) {
  2276. throw new Crypt_GPG_NoDataException(
  2277. 'Cannot decrypt and verify data. No PGP encrypted data ' .
  2278. 'was found in the provided data.', self::ERROR_NO_DATA);
  2279. }
  2280. throw $e;
  2281. }
  2282. if ($outputFile === null) {
  2283. $return['data'] = $output;
  2284. }
  2285. return $return;
  2286. }
  2287. // }}}
  2288. }
  2289. // }}}
  2290. ?>