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

Source for file DecryptStatusHandler.php

Documentation is available at DecryptStatusHandler.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * Crypt_GPG is a package to use GnuPG from PHP
  7.  *
  8.  * This file contains an object that handles GnuPG's status output for the
  9.  * decrypt operation.
  10.  *
  11.  * PHP version 5
  12.  *
  13.  * LICENSE:
  14.  *
  15.  * This library is free software; you can redistribute it and/or modify
  16.  * it under the terms of the GNU Lesser General Public License as
  17.  * published by the Free Software Foundation; either version 2.1 of the
  18.  * License, or (at your option) any later version.
  19.  *
  20.  * This library is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23.  * Lesser General Public License for more details.
  24.  *
  25.  * You should have received a copy of the GNU Lesser General Public
  26.  * License along with this library; if not, write to the Free Software
  27.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28.  *
  29.  * @category  Encryption
  30.  * @package   Crypt_GPG
  31.  * @author    Michael Gauthier <mike@silverorange.com>
  32.  * @copyright 2008-2013 silverorange
  33.  * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  34.  * @version   CVS: $Id$
  35.  * @link      http://pear.php.net/package/Crypt_GPG
  36.  * @link      http://www.gnupg.org/
  37.  */
  38.  
  39. /**
  40.  * Crypt_GPG base class
  41.  */
  42. require_once 'Crypt/GPG.php';
  43.  
  44. /**
  45.  * Crypt_GPG exception classes
  46.  */
  47. require_once 'Crypt/GPG/Exceptions.php';
  48.  
  49.  
  50. /**
  51.  * Status line handler for the decrypt operation
  52.  *
  53.  * This class is used internally by Crypt_GPG and does not need be used
  54.  * directly. See the {@link Crypt_GPG} class for end-user API.
  55.  *
  56.  * This class is responsible for sending the passphrase commands when required
  57.  * by the {@link Crypt_GPG::decrypt()} method. See <b>doc/DETAILS</b> in the
  58.  * {@link http://www.gnupg.org/download/ GnuPG distribution} for detailed
  59.  * information on GnuPG's status output for the decrypt operation.
  60.  *
  61.  * This class is also responsible for parsing error status and throwing a
  62.  * meaningful exception in the event that decryption fails.
  63.  *
  64.  * @category  Encryption
  65.  * @package   Crypt_GPG
  66.  * @author    Michael Gauthier <mike@silverorange.com>
  67.  * @copyright 2008-2013 silverorange
  68.  * @license   http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
  69.  * @link      http://pear.php.net/package/Crypt_GPG
  70.  * @link      http://www.gnupg.org/
  71.  */
  72. {
  73.     // {{{ protected properties
  74.  
  75.     /**
  76.      * Keys used to decrypt
  77.      *
  78.      * The array is of the form:
  79.      * <code>
  80.      * array(
  81.      *   $key_id => array(
  82.      *     'fingerprint' => $fingerprint,
  83.      *     'passphrase'  => $passphrase
  84.      *   )
  85.      * );
  86.      * </code>
  87.      *
  88.      * @var array 
  89.      */
  90.     protected $keys = array();
  91.  
  92.     /**
  93.      * Engine used to which passphrases are passed
  94.      *
  95.      * @var Crypt_GPG_Engine 
  96.      */
  97.     protected $engine = null;
  98.  
  99.     /**
  100.      * The id of the current sub-key used for decryption
  101.      *
  102.      * @var string 
  103.      */
  104.     protected $currentSubKey = '';
  105.  
  106.     /**
  107.      * Whether or not decryption succeeded
  108.      *
  109.      * If the message is only signed (compressed) and not encrypted, this is
  110.      * always true. If the message is encrypted, this flag is set to false
  111.      * until we know the decryption succeeded.
  112.      *
  113.      * @var boolean 
  114.      */
  115.     protected $decryptionOkay = true;
  116.  
  117.     /**
  118.      * Whether or not there was no data for decryption
  119.      *
  120.      * @var boolean 
  121.      */
  122.     protected $noData = false;
  123.  
  124.     /**
  125.      * Keys for which the passhprase is missing
  126.      *
  127.      * This contains primary user ids indexed by sub-key id and is used to
  128.      * create helpful exception messages.
  129.      *
  130.      * @var array 
  131.      */
  132.     protected $missingPassphrases = array();
  133.  
  134.     /**
  135.      * Keys for which the passhprase is incorrect
  136.      *
  137.      * This contains primary user ids indexed by sub-key id and is used to
  138.      * create helpful exception messages.
  139.      *
  140.      * @var array 
  141.      */
  142.     protected $badPassphrases = array();
  143.  
  144.     /**
  145.      * Keys that can be used to decrypt the data but are missing from the
  146.      * keychain
  147.      *
  148.      * This is an array with both the key and value being the sub-key id of
  149.      * the missing keys.
  150.      *
  151.      * @var array 
  152.      */
  153.     protected $missingKeys = array();
  154.  
  155.     // }}}
  156.     // {{{ __construct()
  157.  
  158.     /**
  159.      * Creates a new decryption status handler
  160.      *
  161.      * @param Crypt_GPG_Engine $engine the GPG engine to which passphrases are
  162.      *                                  passed.
  163.      * @param array            $keys   the decryption keys to use.
  164.      */
  165.     public function __construct(Crypt_GPG_Engine $enginearray $keys)
  166.     {
  167.         $this->engine = $engine;
  168.         $this->keys   = $keys;
  169.     }
  170.  
  171.     // }}}
  172.     // {{{ handle()
  173.  
  174.     /**
  175. /**
  176.      * Handles a status line
  177.      *
  178.      * @param string $line the status line to handle.
  179.      *
  180.      * @return void 
  181.      */
  182.     public function handle($line)
  183.     {
  184.         $tokens explode(' '$line);
  185.         switch ($tokens[0]{
  186.         case 'ENC_TO':
  187.             // Now we know the message is encrypted. Set flag to check if
  188.             // decryption succeeded.
  189.             $this->decryptionOkay = false;
  190.  
  191.             // this is the new key message
  192.             $this->currentSubKeyId $tokens[1];
  193.             break;
  194.  
  195.         case 'NEED_PASSPHRASE':
  196.             // send passphrase to the GPG engine
  197.             $subKeyId $tokens[1];
  198.             if (array_key_exists($subKeyId$this->keys)) {
  199.                 $passphrase $this->keys[$subKeyId]['passphrase'];
  200.                 $this->engine->sendCommand($passphrase);
  201.             else {
  202.                 $this->engine->sendCommand('');
  203.             }
  204.             break;
  205.  
  206.         case 'USERID_HINT':
  207.             // remember the user id for pretty exception messages
  208.             $this->badPassphrases[$tokens[1]]
  209.                 = implode(' 'array_splice($tokens2));
  210.  
  211.             break;
  212.  
  213.         case 'GOOD_PASSPHRASE':
  214.             // if we got a good passphrase, remove the key from the list of
  215.             // bad passphrases.
  216.             unset($this->badPassphrases[$this->currentSubKeyId]);
  217.             break;
  218.  
  219.         case 'MISSING_PASSPHRASE':
  220.             $this->missingPassphrases[$this->currentSubKeyId]
  221.                 = $this->currentSubKeyId;
  222.  
  223.             break;
  224.  
  225.         case 'NO_SECKEY':
  226.             // note: this message is also received if there are multiple
  227.             // recipients and a previous key had a correct passphrase.
  228.             $this->missingKeys[$tokens[1]] $tokens[1];
  229.             break;
  230.  
  231.         case 'NODATA':
  232.             $this->noData = true;
  233.             break;
  234.  
  235.         case 'DECRYPTION_OKAY':
  236.             // If the message is encrypted, this is the all-clear signal.
  237.             $this->decryptionOkay = true;
  238.             break;
  239.         }
  240.     }
  241.  
  242.     // }}}
  243.     // {{{ throwException()
  244.  
  245.     /**
  246.      * Takes the final status of the decrypt operation and throws an
  247.      * appropriate exception
  248.      *
  249.      * If decryption was successful, no exception is thrown.
  250.      *
  251.      * @return void 
  252.      *
  253.      * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  254.      *          decrypt the data is not in the user's keyring.
  255.      *
  256.      * @throws Crypt_GPG_NoDataException if specified data does not contain
  257.      *          GPG encrypted data.
  258.      *
  259.      * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  260.      *          incorrect or if a required passphrase is not specified. See
  261.      *          {@link Crypt_GPG::addDecryptKey()}.
  262.      *
  263.      * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
  264.      *          Use the <i>debug</i> option and file a bug report if these
  265.      *          exceptions occur.
  266.      */
  267.     public function throwException()
  268.     {
  269.         $code Crypt_GPG::ERROR_NONE;
  270.  
  271.         if (!$this->decryptionOkay{
  272.             if (count($this->badPassphrases> 0{
  273.                 $code Crypt_GPG::ERROR_BAD_PASSPHRASE;
  274.             elseif (count($this->missingKeys> 0{
  275.                 $code Crypt_GPG::ERROR_KEY_NOT_FOUND;
  276.             else {
  277.                 $code Crypt_GPG::ERROR_UNKNOWN;
  278.             }
  279.         elseif ($this->noData{
  280.             $code Crypt_GPG::ERROR_NO_DATA;
  281.         }
  282.  
  283.         switch ($code{
  284.         case Crypt_GPG::ERROR_NONE:
  285.             break;
  286.  
  287.         case Crypt_GPG::ERROR_KEY_NOT_FOUND:
  288.             if (count($this->missingKeys> 0{
  289.                 $keyId reset($this->missingKeys);
  290.             else {
  291.                 $keyId '';
  292.             }
  293.             throw new Crypt_GPG_KeyNotFoundException(
  294.                 'Cannot decrypt data. No suitable private key is in the ' .
  295.                 'keyring. Import a suitable private key before trying to ' .
  296.                 'decrypt this data.',
  297.                 $code,
  298.                 $keyId
  299.             );
  300.         case Crypt_GPG::ERROR_BAD_PASSPHRASE:
  301.             $badPassphrases array_diff_key(
  302.                 $this->badPassphrases,
  303.                 $this->missingPassphrases
  304.             );
  305.  
  306.             $missingPassphrases array_intersect_key(
  307.                 $this->badPassphrases,
  308.                 $this->missingPassphrases
  309.             );
  310.  
  311.             $message =  'Cannot decrypt data.';
  312.             if (count($badPassphrases> 0{
  313.                 $message ' Incorrect passphrase provided for keys: "' .
  314.                     implode('", "'$badPassphrases'".';
  315.             }
  316.             if (count($missingPassphrases> 0{
  317.                 $message ' No passphrase provided for keys: "' .
  318.                     implode('", "'$badPassphrases'".';
  319.             }
  320.  
  321.             throw new Crypt_GPG_BadPassphraseException(
  322.                 $message,
  323.                 $code,
  324.                 $badPassphrases,
  325.                 $missingPassphrases
  326.             );
  327.         case Crypt_GPG::ERROR_NO_DATA:
  328.             throw new Crypt_GPG_NoDataException(
  329.                 'Cannot decrypt data. No PGP encrypted data was found in '.
  330.                 'the provided data.',
  331.                 $code
  332.             );
  333.         default:
  334.             throw new Crypt_GPG_Exception(
  335.                 'Unknown error decrypting data.',
  336.                 $code
  337.             );
  338.         }
  339.     }
  340.  
  341.     // }}}
  342. }
  343.  
  344. ?>

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