PageRenderTime 70ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/program/lib/Crypt/GPG.php

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