Crypt_GPG
[ class tree: Crypt_GPG ] [ index: Crypt_GPG ] [ all elements ]

Source for file GPG.php

Documentation is available at GPG.php

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

Documentation generated on Wed, 13 Mar 2013 18:30:09 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.