package.xml0000664000175000017500000004145712610161626011603 0ustar alecalec Crypt_GPG pear.php.net GNU Privacy Guard (GnuPG) This package provides an object oriented interface to GNU Privacy Guard (GnuPG). It requires the GnuPG executable to be on the system. Though GnuPG can support symmetric-key cryptography, this package is intended only to facilitate public-key cryptography. This package requires PHP version 5.2.1 or greater. Mike Gauthier gauthierm mike@silverorange.com yes Nathan Fredrickson nrf nathan@silverorange.com yes Aleksander Machniak alec alec@alec.pl yes 2015-10-16 1.4.0 1.4.0 stable stable LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #19914. PinEntry can't find Console_CommandLine. Fix Bug #20512. Debug should use htmlspecialchars(). Fix Bug #20527. Composer: @package-name@ in PinEntry.php is not resolved. Fix Bug #20939. Retrieve info if encryption or signing keys have been added. Fix Bug #20940. Determine algorithm used in signature. Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. Fix possible fread/fwrite to strings when the string values passed to Crypt_GPG are loosly equal to a stream resource handle. A workaround for PHP Bug #39598 is also provided in the event that GnuPG ends unexpectedly. This prevents infinite loops. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. 5.2.1 1.4.0 Console_CommandLine pear.php.net 1.1.10 mbstring windows posix 1.3.2 1.3.0 stable stable 2011-09-26 LGPL This release adds key generation to the list of supported operations and adds fluent interface support to the main Crypt_GPG class. Additionally the following bugs are fixed: Fix Bug #18618. Incorrect CHUNK_SIZE / Hang on file decryption. Fix Bug #18869. Unnecessary dependency on posix extension. 1.4.0b1 1.4.0 beta beta 2013-02-28 LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. 1.4.0b2 1.4.0 beta beta 2013-02-28 LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. A workaround for PHP Bug #39598 is also provided in the event that GnuPG ends unexpectedly. This prevents infinite loops. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. 1.4.0b3 1.4.0 beta beta 2013-03-01 LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. A workaround for PHP Bug #39598 is also provided in the event that GnuPG ends unexpectedly. This prevents infinite loops. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. 1.4.0b4 1.4.0 beta beta 2013-03-13 LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. Fix possible fread/fwrite to strings when the string values passed to Crypt_GPG are loosly equal to a stream resource handle. A workaround for PHP Bug #39598 is also provided in the event that GnuPG ends unexpectedly. This prevents infinite loops. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. 1.4.0 1.4.0 stable stable 2015-10-16 LGPL This release adds support for GnuPG 2.x, supporting the latest version of RHEL and derivatives. Additionally, the following bugs are fixed: Fix Bug #19914. PinEntry can't find Console_CommandLine. Fix Bug #20512. Debug should use htmlspecialchars(). Fix Bug #20527. Composer: @package-name@ in PinEntry.php is not resolved. Fix Bug #20939. Retrieve info if encryption or signing keys have been added. Fix Bug #20940. Determine algorithm used in signature. Fix Bug #17838. Passphrase operations don't work on GnuPG 2.x. Fix Bug #17628. Version regular expression on MAMP. Fix Bug #19883. Better exception on unwriteable or unexecutable homedir. Fix possible fread/fwrite to strings when the string values passed to Crypt_GPG are loosly equal to a stream resource handle. A workaround for PHP Bug #39598 is also provided in the event that GnuPG ends unexpectedly. This prevents infinite loops. This release makes the mbstring extension a required dependency as the assuan protocol used in GnuPG 2.x uses UTF-8. Crypt_GPG-1.4.0/Crypt/GPG/ByteUtils.php0000664000175000017500000000615012610161626016064 0ustar alecalec * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ // {{{ class Crypt_GPG_ByteUtils /** * A class for performing byte-wise string operations * * GPG I/O streams are managed using bytes rather than characters. This class * requires the mbstring extension to be available. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://php.net/mbstring */ class Crypt_GPG_ByteUtils { // {{{ strlen() /** * Gets the length of a string in bytes * * This is used for stream-based communication with the GPG subprocess. * * @param string $string the string for which to get the length. * * @return integer the length of the string in bytes. */ public static function strlen($string) { return mb_strlen($string, '8bit'); } // }}} // {{{ substr() /** * Gets the substring of a string in bytes * * This is used for stream-based communication with the GPG subprocess. * * @param string $string the input string. * @param integer $start the starting point at which to get the substring. * @param integer $length optional. The length of the substring. * * @return string the extracted part of the string. Unlike the default PHP * substr() function, the returned value is * always a string and never false. */ public static function substr($string, $start, $length = null) { if ($length === null) { return mb_substr( $string, $start, self::strlen($string) - $start, '8bit' ); } return mb_substr($string, $start, $length, '8bit'); } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/DecryptStatusHandler.php0000664000175000017500000002402212610161626020252 0ustar alecalec * @copyright 2008-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Crypt_GPG base class */ require_once 'Crypt/GPG.php'; /** * Crypt_GPG exception classes */ require_once 'Crypt/GPG/Exceptions.php'; /** * Status line handler for the decrypt operation * * This class is used internally by Crypt_GPG and does not need be used * directly. See the {@link Crypt_GPG} class for end-user API. * * This class is responsible for sending the passphrase commands when required * by the {@link Crypt_GPG::decrypt()} method. See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GnuPG distribution} for detailed * information on GnuPG's status output for the decrypt operation. * * This class is also responsible for parsing error status and throwing a * meaningful exception in the event that decryption fails. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_DecryptStatusHandler { // {{{ protected properties /** * Keys used to decrypt * * The array is of the form: * * array( * $key_id => array( * 'fingerprint' => $fingerprint, * 'passphrase' => $passphrase * ) * ); * * * @var array */ protected $keys = array(); /** * Engine used to which passphrases are passed * * @var Crypt_GPG_Engine */ protected $engine = null; /** * The id of the current sub-key used for decryption * * @var string */ protected $currentSubKey = ''; /** * Whether or not decryption succeeded * * If the message is only signed (compressed) and not encrypted, this is * always true. If the message is encrypted, this flag is set to false * until we know the decryption succeeded. * * @var boolean */ protected $decryptionOkay = true; /** * Whether or not there was no data for decryption * * @var boolean */ protected $noData = false; /** * Keys for which the passhprase is missing * * This contains primary user ids indexed by sub-key id and is used to * create helpful exception messages. * * @var array */ protected $missingPassphrases = array(); /** * Keys for which the passhprase is incorrect * * This contains primary user ids indexed by sub-key id and is used to * create helpful exception messages. * * @var array */ protected $badPassphrases = array(); /** * Keys that can be used to decrypt the data but are missing from the * keychain * * This is an array with both the key and value being the sub-key id of * the missing keys. * * @var array */ protected $missingKeys = array(); // }}} // {{{ __construct() /** * Creates a new decryption status handler * * @param Crypt_GPG_Engine $engine the GPG engine to which passphrases are * passed. * @param array $keys the decryption keys to use. */ public function __construct(Crypt_GPG_Engine $engine, array $keys) { $this->engine = $engine; $this->keys = $keys; } // }}} // {{{ handle() /** * Handles a status line * * @param string $line the status line to handle. * * @return void */ public function handle($line) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'ENC_TO': // Now we know the message is encrypted. Set flag to check if // decryption succeeded. $this->decryptionOkay = false; // this is the new key message $this->currentSubKeyId = $tokens[1]; break; case 'NEED_PASSPHRASE': // send passphrase to the GPG engine $subKeyId = $tokens[1]; if (array_key_exists($subKeyId, $this->keys)) { $passphrase = $this->keys[$subKeyId]['passphrase']; $this->engine->sendCommand($passphrase); } else { $this->engine->sendCommand(''); } break; case 'USERID_HINT': // remember the user id for pretty exception messages $this->badPassphrases[$tokens[1]] = implode(' ', array_splice($tokens, 2)); break; case 'GOOD_PASSPHRASE': // if we got a good passphrase, remove the key from the list of // bad passphrases. unset($this->badPassphrases[$this->currentSubKeyId]); break; case 'MISSING_PASSPHRASE': $this->missingPassphrases[$this->currentSubKeyId] = $this->currentSubKeyId; break; case 'NO_SECKEY': // note: this message is also received if there are multiple // recipients and a previous key had a correct passphrase. $this->missingKeys[$tokens[1]] = $tokens[1]; break; case 'NODATA': $this->noData = true; break; case 'DECRYPTION_OKAY': // If the message is encrypted, this is the all-clear signal. $this->decryptionOkay = true; break; } } // }}} // {{{ throwException() /** * Takes the final status of the decrypt operation and throws an * appropriate exception * * If decryption was successful, no exception is thrown. * * @return void * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function throwException() { $code = Crypt_GPG::ERROR_NONE; if (!$this->decryptionOkay) { if (count($this->badPassphrases) > 0) { $code = Crypt_GPG::ERROR_BAD_PASSPHRASE; } elseif (count($this->missingKeys) > 0) { $code = Crypt_GPG::ERROR_KEY_NOT_FOUND; } else { $code = Crypt_GPG::ERROR_UNKNOWN; } } elseif ($this->noData) { $code = Crypt_GPG::ERROR_NO_DATA; } switch ($code) { case Crypt_GPG::ERROR_NONE: break; case Crypt_GPG::ERROR_KEY_NOT_FOUND: if (count($this->missingKeys) > 0) { $keyId = reset($this->missingKeys); } else { $keyId = ''; } throw new Crypt_GPG_KeyNotFoundException( 'Cannot decrypt data. No suitable private key is in the ' . 'keyring. Import a suitable private key before trying to ' . 'decrypt this data.', $code, $keyId ); case Crypt_GPG::ERROR_BAD_PASSPHRASE: $badPassphrases = array_diff_key( $this->badPassphrases, $this->missingPassphrases ); $missingPassphrases = array_intersect_key( $this->badPassphrases, $this->missingPassphrases ); $message = 'Cannot decrypt data.'; if (count($badPassphrases) > 0) { $message = ' Incorrect passphrase provided for keys: "' . implode('", "', $badPassphrases) . '".'; } if (count($missingPassphrases) > 0) { $message = ' No passphrase provided for keys: "' . implode('", "', $badPassphrases) . '".'; } throw new Crypt_GPG_BadPassphraseException( $message, $code, $badPassphrases, $missingPassphrases ); case Crypt_GPG::ERROR_NO_DATA: throw new Crypt_GPG_NoDataException( 'Cannot decrypt data. No PGP encrypted data was found in '. 'the provided data.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error decrypting data.', $code ); } } // }}} } ?> Crypt_GPG-1.4.0/Crypt/GPG/Engine.php0000664000175000017500000020332412610161626015347 0ustar alecalec * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Crypt_GPG base class. */ require_once 'Crypt/GPG.php'; /** * GPG exception classes. */ require_once 'Crypt/GPG/Exceptions.php'; /** * Byte string operations. */ require_once 'Crypt/GPG/ByteUtils.php'; /** * Process control methods. */ require_once 'Crypt/GPG/ProcessControl.php'; /** * Standard PEAR exception is used if GPG binary is not found. */ require_once 'PEAR/Exception.php'; // {{{ class Crypt_GPG_Engine /** * Native PHP Crypt_GPG I/O engine * * This class is used internally by Crypt_GPG and does not need be used * directly. See the {@link Crypt_GPG} class for end-user API. * * This engine uses PHP's native process control functions to directly control * the GPG process. The GPG executable is required to be on the system. * * All data is passed to the GPG subprocess using file descriptors. This is the * most secure method of passing data to the GPG subprocess. * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_Engine { // {{{ constants /** * Size of data chunks that are sent to and retrieved from the IPC pipes. * * PHP reads 8192 bytes. If this is set to less than 8192, PHP reads 8192 * and buffers the rest so we might as well just read 8192. * * Using values other than 8192 also triggers PHP bugs. * * @see http://bugs.php.net/bug.php?id=35224 */ const CHUNK_SIZE = 8192; /** * Standard input file descriptor. This is used to pass data to the GPG * process. */ const FD_INPUT = 0; /** * Standard output file descriptor. This is used to receive normal output * from the GPG process. */ const FD_OUTPUT = 1; /** * Standard output file descriptor. This is used to receive error output * from the GPG process. */ const FD_ERROR = 2; /** * GPG status output file descriptor. The status file descriptor outputs * detailed information for many GPG commands. See the second section of * the file doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG package} for a detailed * description of GPG's status output. */ const FD_STATUS = 3; /** * Command input file descriptor. This is used for methods requiring * passphrases. */ const FD_COMMAND = 4; /** * Extra message input file descriptor. This is used for passing signed * data when verifying a detached signature. */ const FD_MESSAGE = 5; /** * Minimum version of GnuPG that is supported. */ const MIN_VERSION = '1.0.2'; // }}} // {{{ private class properties /** * Whether or not to use debugging mode * * When set to true, every GPG command is echoed before it is run. Sensitive * data is always handled using pipes and is not specified as part of the * command. As a result, sensitive data is never displayed when debug is * enabled. Sensitive data includes private key data and passphrases. * * Debugging is off by default. * * @var boolean * @see Crypt_GPG_Engine::__construct() */ private $_debug = false; /** * Location of GPG binary * * @var string * @see Crypt_GPG_Engine::__construct() * @see Crypt_GPG_Engine::_getBinary() */ private $_binary = ''; /** * Location of GnuPG agent binary * * Only used for GnuPG 2.x * * @var string * @see Crypt_GPG_Engine::__construct() * @see Crypt_GPG_Engine::_getAgent() */ private $_agent = ''; /** * Directory containing the GPG key files * * This property only contains the path when the homedir option * is specified in the constructor. * * @var string * @see Crypt_GPG_Engine::__construct() */ private $_homedir = ''; /** * File path of the public keyring * * This property only contains the file path when the public_keyring * option is specified in the constructor. * * If the specified file path starts with ~/, the path is * relative to the homedir if specified, otherwise to * ~/.gnupg. * * @var string * @see Crypt_GPG_Engine::__construct() */ private $_publicKeyring = ''; /** * File path of the private (secret) keyring * * This property only contains the file path when the private_keyring * option is specified in the constructor. * * If the specified file path starts with ~/, the path is * relative to the homedir if specified, otherwise to * ~/.gnupg. * * @var string * @see Crypt_GPG_Engine::__construct() */ private $_privateKeyring = ''; /** * File path of the trust database * * This property only contains the file path when the trust_db * option is specified in the constructor. * * If the specified file path starts with ~/, the path is * relative to the homedir if specified, otherwise to * ~/.gnupg. * * @var string * @see Crypt_GPG_Engine::__construct() */ private $_trustDb = ''; /** * Array of pipes used for communication with the GPG binary * * This is an array of file descriptor resources. * * @var array */ private $_pipes = array(); /** * Array of pipes used for communication with the gpg-agent binary * * This is an array of file descriptor resources. * * @var array */ private $_agentPipes = array(); /** * Array of currently opened pipes * * This array is used to keep track of remaining opened pipes so they can * be closed when the GPG subprocess is finished. This array is a subset of * the {@link Crypt_GPG_Engine::$_pipes} array and contains opened file * descriptor resources. * * @var array * @see Crypt_GPG_Engine::_closePipe() */ private $_openPipes = array(); /** * A handle for the GPG process * * @var resource */ private $_process = null; /** * A handle for the gpg-agent process * * @var resource */ private $_agentProcess = null; /** * GPG agent daemon socket and PID for running gpg-agent * * @var string */ private $_agentInfo = null; /** * Whether or not the operating system is Darwin (OS X) * * @var boolean */ private $_isDarwin = false; /** * Commands to be sent to GPG's command input stream * * @var string * @see Crypt_GPG_Engine::sendCommand() */ private $_commandBuffer = ''; /** * Array of status line handlers * * @var array * @see Crypt_GPG_Engine::addStatusHandler() */ private $_statusHandlers = array(); /** * Array of error line handlers * * @var array * @see Crypt_GPG_Engine::addErrorHandler() */ private $_errorHandlers = array(); /** * The error code of the current operation * * @var integer * @see Crypt_GPG_Engine::getErrorCode() */ private $_errorCode = Crypt_GPG::ERROR_NONE; /** * File related to the error code of the current operation * * @var string * @see Crypt_GPG_Engine::getErrorFilename() */ private $_errorFilename = ''; /** * Key id related to the error code of the current operation * * @var string * @see Crypt_GPG_Engine::getErrorKeyId() */ private $_errorkeyId = ''; /** * The number of currently needed passphrases * * If this is not zero when the GPG command is completed, the error code is * set to {@link Crypt_GPG::ERROR_MISSING_PASSPHRASE}. * * @var integer */ private $_needPassphrase = 0; /** * The input source * * This is data to send to GPG. Either a string or a stream resource. * * @var string|resource * @see Crypt_GPG_Engine::setInput() */ private $_input = null; /** * The extra message input source * * Either a string or a stream resource. * * @var string|resource * @see Crypt_GPG_Engine::setMessage() */ private $_message = null; /** * The output location * * This is where the output from GPG is sent. Either a string or a stream * resource. * * @var string|resource * @see Crypt_GPG_Engine::setOutput() */ private $_output = ''; /** * The GPG operation to execute * * @var string * @see Crypt_GPG_Engine::setOperation() */ private $_operation; /** * Arguments for the current operation * * @var array * @see Crypt_GPG_Engine::setOperation() */ private $_arguments = array(); /** * The version number of the GPG binary * * @var string * @see Crypt_GPG_Engine::getVersion() */ private $_version = ''; // }}} // {{{ __construct() /** * Creates a new GPG engine * * Available options are: * * - string homedir - the directory where the GPG * keyring files are stored. If not * specified, Crypt_GPG uses the * default of ~/.gnupg. * - string publicKeyring - the file path of the public * keyring. Use this if the public * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/pubring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string privateKeyring - the file path of the private * keyring. Use this if the private * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/secring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string trustDb - the file path of the web-of-trust * database. Use this if the trust * database is not in the homedir, or * if the database is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * trust database with this option * (/foo/bar/trustdb.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string binary - the location of the GPG binary. If * not specified, the driver attempts * to auto-detect the GPG binary * location using a list of known * default locations for the current * operating system. The option * gpgBinary is a * deprecated alias for this option. * - string agent - the location of the GnuPG agent * binary. The gpg-agent is only * used for GnuPG 2.x. If not * specified, the engine attempts * to auto-detect the gpg-agent * binary location using a list of * know default locations for the * current operating system. * - boolean debug - whether or not to use debug mode. * When debug mode is on, all * communication to and from the GPG * subprocess is logged. This can be * useful to diagnose errors when * using Crypt_GPG. * * @param array $options optional. An array of options used to create the * GPG object. All options are optional and are * represented as key-value pairs. * * @throws Crypt_GPG_FileException if the homedir does not exist * and cannot be created. This can happen if homedir is * not specified, Crypt_GPG is run as the web user, and the web * user has no home directory. This exception is also thrown if any * of the options publicKeyring, * privateKeyring or trustDb options are * specified but the files do not exist or are are not readable. * This can happen if the user running the Crypt_GPG process (for * example, the Apache user) does not have permission to read the * files. * * @throws PEAR_Exception if the provided binary is invalid, or * if no binary is provided and no suitable binary could * be found. * * @throws PEAR_Exception if the provided agent is invalid, or * if no agent is provided and no suitable gpg-agent * cound be found. */ public function __construct(array $options = array()) { $this->_isDarwin = (strncmp(strtoupper(PHP_OS), 'DARWIN', 6) === 0); // get homedir if (array_key_exists('homedir', $options)) { $this->_homedir = (string)$options['homedir']; } else { if (extension_loaded('posix')) { // note: this requires the package OS dep exclude 'windows' $info = posix_getpwuid(posix_getuid()); $this->_homedir = $info['dir'].'/.gnupg'; } else { if (isset($_SERVER['HOME'])) { $this->_homedir = $_SERVER['HOME']; } else { $this->_homedir = getenv('HOME'); } } if ($this->_homedir === false) { throw new Crypt_GPG_FileException( 'Could not locate homedir. Please specify the homedir ' . 'to use with the \'homedir\' option when instantiating ' . 'the Crypt_GPG object.' ); } } // attempt to create homedir if it does not exist if (!is_dir($this->_homedir)) { if (@mkdir($this->_homedir, 0777, true)) { // Set permissions on homedir. Parent directories are created // with 0777, homedir is set to 0700. chmod($this->_homedir, 0700); } else { throw new Crypt_GPG_FileException( 'The \'homedir\' "' . $this->_homedir . '" is not ' . 'readable or does not exist and cannot be created. This ' . 'can happen if \'homedir\' is not specified in the ' . 'Crypt_GPG options, Crypt_GPG is run as the web user, ' . 'and the web user has no home directory.', 0, $this->_homedir ); } } // check homedir permissions (See Bug #19833) if (!is_executable($this->_homedir)) { throw new Crypt_GPG_FileException( 'The \'homedir\' "' . $this->_homedir . '" is not enterable ' . 'by the current user. Please check the permissions on your ' . 'homedir and make sure the current user can both enter and ' . 'write to the directory.', 0, $this->_homedir ); } if (!is_writeable($this->_homedir)) { throw new Crypt_GPG_FileException( 'The \'homedir\' "' . $this->_homedir . '" is not writable ' . 'by the current user. Please check the permissions on your ' . 'homedir and make sure the current user can both enter and ' . 'write to the directory.', 0, $this->_homedir ); } // get binary if (array_key_exists('binary', $options)) { $this->_binary = (string)$options['binary']; } elseif (array_key_exists('gpgBinary', $options)) { // deprecated alias $this->_binary = (string)$options['gpgBinary']; } else { $this->_binary = $this->_getBinary(); } if ($this->_binary == '' || !is_executable($this->_binary)) { throw new PEAR_Exception( 'GPG binary not found. If you are sure the GPG binary is ' . 'installed, please specify the location of the GPG binary ' . 'using the \'binary\' driver option.' ); } // get agent if (array_key_exists('agent', $options)) { $this->_agent = (string)$options['agent']; } else { $this->_agent = $this->_getAgent(); } if ($this->_agent == '' || !is_executable($this->_agent)) { throw new PEAR_Exception( 'gpg-agent binary not found. If you are sure the gpg-agent ' . 'is installed, please specify the location of the gpg-agent ' . 'binary using the \'agent\' driver option.' ); } /* * Note: * * Normally, GnuPG expects keyrings to be in the homedir and expects * to be able to write temporary files in the homedir. Sometimes, * keyrings are not in the homedir, or location of the keyrings does * not allow writing temporary files. In this case, the homedir * option by itself is not enough to specify the keyrings because GnuPG * can not write required temporary files. Additional options are * provided so you can specify the location of the keyrings separately * from the homedir. */ // get public keyring if (array_key_exists('publicKeyring', $options)) { $this->_publicKeyring = (string)$options['publicKeyring']; if (!is_readable($this->_publicKeyring)) { throw new Crypt_GPG_FileException('The \'publicKeyring\' "' . $this->_publicKeyring . '" does not exist or is ' . 'not readable. Check the location and ensure the file ' . 'permissions are correct.', 0, $this->_publicKeyring); } } // get private keyring if (array_key_exists('privateKeyring', $options)) { $this->_privateKeyring = (string)$options['privateKeyring']; if (!is_readable($this->_privateKeyring)) { throw new Crypt_GPG_FileException('The \'privateKeyring\' "' . $this->_privateKeyring . '" does not exist or is ' . 'not readable. Check the location and ensure the file ' . 'permissions are correct.', 0, $this->_privateKeyring); } } // get trust database if (array_key_exists('trustDb', $options)) { $this->_trustDb = (string)$options['trustDb']; if (!is_readable($this->_trustDb)) { throw new Crypt_GPG_FileException('The \'trustDb\' "' . $this->_trustDb . '" does not exist or is not readable. ' . 'Check the location and ensure the file permissions are ' . 'correct.', 0, $this->_trustDb); } } if (array_key_exists('debug', $options)) { $this->_debug = (boolean)$options['debug']; } } // }}} // {{{ __destruct() /** * Closes open GPG subprocesses when this object is destroyed * * Subprocesses should never be left open by this class unless there is * an unknown error and unexpected script termination occurs. */ public function __destruct() { $this->_closeSubprocess(); } // }}} // {{{ addErrorHandler() /** * Adds an error handler method * * The method is run every time a new error line is received from the GPG * subprocess. The handler method must accept the error line to be handled * as its first parameter. * * @param callback $callback the callback method to use. * @param array $args optional. Additional arguments to pass as * parameters to the callback method. * * @return void */ public function addErrorHandler($callback, array $args = array()) { $this->_errorHandlers[] = array( 'callback' => $callback, 'args' => $args ); } // }}} // {{{ addStatusHandler() /** * Adds a status handler method * * The method is run every time a new status line is received from the * GPG subprocess. The handler method must accept the status line to be * handled as its first parameter. * * @param callback $callback the callback method to use. * @param array $args optional. Additional arguments to pass as * parameters to the callback method. * * @return void */ public function addStatusHandler($callback, array $args = array()) { $this->_statusHandlers[] = array( 'callback' => $callback, 'args' => $args ); } // }}} // {{{ sendCommand() /** * Sends a command to the GPG subprocess over the command file-descriptor * pipe * * @param string $command the command to send. * * @return void * * @sensitive $command */ public function sendCommand($command) { if (array_key_exists(self::FD_COMMAND, $this->_openPipes)) { $this->_commandBuffer .= $command . PHP_EOL; } } // }}} // {{{ reset() /** * Resets the GPG engine, preparing it for a new operation * * @return void * * @see Crypt_GPG_Engine::run() * @see Crypt_GPG_Engine::setOperation() */ public function reset() { $this->_operation = ''; $this->_arguments = array(); $this->_input = null; $this->_message = null; $this->_output = ''; $this->_errorCode = Crypt_GPG::ERROR_NONE; $this->_needPassphrase = 0; $this->_commandBuffer = ''; $this->_statusHandlers = array(); $this->_errorHandlers = array(); $this->addStatusHandler(array($this, '_handleErrorStatus')); $this->addErrorHandler(array($this, '_handleErrorError')); if ($this->_debug) { $this->addStatusHandler(array($this, '_handleDebugStatus')); $this->addErrorHandler(array($this, '_handleDebugError')); } } // }}} // {{{ run() /** * Runs the current GPG operation * * This creates and manages the GPG subprocess. * * The operation must be set with {@link Crypt_GPG_Engine::setOperation()} * before this method is called. * * @return void * * @throws Crypt_GPG_InvalidOperationException if no operation is specified. * * @see Crypt_GPG_Engine::reset() * @see Crypt_GPG_Engine::setOperation() */ public function run() { if ($this->_operation === '') { throw new Crypt_GPG_InvalidOperationException('No GPG operation ' . 'specified. Use Crypt_GPG_Engine::setOperation() before ' . 'calling Crypt_GPG_Engine::run().'); } $this->_openSubprocess(); $this->_process(); $this->_closeSubprocess(); } // }}} // {{{ getErrorCode() /** * Gets the error code of the last executed operation * * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has * been executed. * * @return integer the error code of the last executed operation. */ public function getErrorCode() { return $this->_errorCode; } // }}} // {{{ getErrorFilename() /** * Gets the file related to the error code of the last executed operation * * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has * been executed. If there is no file related to the error, an empty string * is returned. * * @return string the file related to the error code of the last executed * operation. */ public function getErrorFilename() { return $this->_errorFilename; } // }}} // {{{ getErrorKeyId() /** * Gets the key id related to the error code of the last executed operation * * This value is only meaningful after {@link Crypt_GPG_Engine::run()} has * been executed. If there is no key id related to the error, an empty * string is returned. * * @return string the key id related to the error code of the last executed * operation. */ public function getErrorKeyId() { return $this->_errorKeyId; } // }}} // {{{ setInput() /** * Sets the input source for the current GPG operation * * @param string|resource &$input either a reference to the string * containing the input data or an open * stream resource containing the input * data. * * @return void */ public function setInput(&$input) { $this->_input =& $input; } // }}} // {{{ setMessage() /** * Sets the message source for the current GPG operation * * Detached signature data should be specified here. * * @param string|resource &$message either a reference to the string * containing the message data or an open * stream resource containing the message * data. * * @return void */ public function setMessage(&$message) { $this->_message =& $message; } // }}} // {{{ setOutput() /** * Sets the output destination for the current GPG operation * * @param string|resource &$output either a reference to the string in * which to store GPG output or an open * stream resource to which the output data * should be written. * * @return void */ public function setOutput(&$output) { $this->_output =& $output; } // }}} // {{{ setOperation() /** * Sets the operation to perform * * @param string $operation the operation to perform. This should be one * of GPG's operations. For example, * --encrypt, --decrypt, * --sign, etc. * @param array $arguments optional. Additional arguments for the GPG * subprocess. See the GPG manual for specific * values. * * @return void * * @see Crypt_GPG_Engine::reset() * @see Crypt_GPG_Engine::run() */ public function setOperation($operation, array $arguments = array()) { $this->_operation = $operation; $this->_arguments = $arguments; } // }}} // {{{ getVersion() /** * Gets the version of the GnuPG binary * * @return string a version number string containing the version of GnuPG * being used. This value is suitable to use with PHP's * version_compare() function. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @throws Crypt_GPG_UnsupportedException if the provided binary is not * GnuPG or if the GnuPG version is less than 1.0.2. */ public function getVersion() { if ($this->_version == '') { $options = array( 'homedir' => $this->_homedir, 'binary' => $this->_binary, 'debug' => $this->_debug ); $engine = new self($options); $info = ''; // Set a garbage version so we do not end up looking up the version // recursively. $engine->_version = '1.0.0'; $engine->reset(); $engine->setOutput($info); $engine->setOperation('--version'); $engine->run(); $code = $this->getErrorCode(); if ($code !== Crypt_GPG::ERROR_NONE) { throw new Crypt_GPG_Exception( 'Unknown error getting GnuPG version information. Please ' . 'use the \'debug\' option when creating the Crypt_GPG ' . 'object, and file a bug report at ' . Crypt_GPG::BUG_URI, $code); } $matches = array(); $expression = '#gpg \(GnuPG[A-Za-z0-9/]*?\) (\S+)#'; if (preg_match($expression, $info, $matches) === 1) { $this->_version = $matches[1]; } else { throw new Crypt_GPG_Exception( 'No GnuPG version information provided by the binary "' . $this->_binary . '". Are you sure it is GnuPG?'); } if (version_compare($this->_version, self::MIN_VERSION, 'lt')) { throw new Crypt_GPG_Exception( 'The version of GnuPG being used (' . $this->_version . ') is not supported by Crypt_GPG. The minimum version ' . 'required by Crypt_GPG is ' . self::MIN_VERSION); } } return $this->_version; } // }}} // {{{ _handleErrorStatus() /** * Handles error values in the status output from GPG * * This method is responsible for setting the * {@link Crypt_GPG_Engine::$_errorCode}. See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on GPG's status output. * * @param string $line the status line to handle. * * @return void */ private function _handleErrorStatus($line) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'BAD_PASSPHRASE': $this->_errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE; break; case 'MISSING_PASSPHRASE': $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; break; case 'NODATA': $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; break; case 'DELETE_PROBLEM': if ($tokens[1] == '1') { $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; break; } elseif ($tokens[1] == '2') { $this->_errorCode = Crypt_GPG::ERROR_DELETE_PRIVATE_KEY; break; } break; case 'IMPORT_RES': if ($tokens[12] > 0) { $this->_errorCode = Crypt_GPG::ERROR_DUPLICATE_KEY; } break; case 'NO_PUBKEY': case 'NO_SECKEY': $this->_errorKeyId = $tokens[1]; $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; break; case 'NEED_PASSPHRASE': $this->_needPassphrase++; break; case 'GOOD_PASSPHRASE': $this->_needPassphrase--; break; case 'EXPSIG': case 'EXPKEYSIG': case 'REVKEYSIG': case 'BADSIG': $this->_errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE; break; } } // }}} // {{{ _handleErrorError() /** * Handles error values in the error output from GPG * * This method is responsible for setting the * {@link Crypt_GPG_Engine::$_errorCode}. * * @param string $line the error line to handle. * * @return void */ private function _handleErrorError($line) { if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { $pattern = '/no valid OpenPGP data found/'; if (preg_match($pattern, $line) === 1) { $this->_errorCode = Crypt_GPG::ERROR_NO_DATA; } } if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { $pattern = '/No secret key|secret key not available/'; if (preg_match($pattern, $line) === 1) { $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; } } if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { $pattern = '/No public key|public key not found/'; if (preg_match($pattern, $line) === 1) { $this->_errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND; } } if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { $matches = array(); $pattern = '/can\'t (?:access|open) `(.*?)\'/'; if (preg_match($pattern, $line, $matches) === 1) { $this->_errorFilename = $matches[1]; $this->_errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS; } } } // }}} // {{{ _handleDebugStatus() /** * Displays debug output for status lines * * @param string $line the status line to handle. * * @return void */ private function _handleDebugStatus($line) { $this->_debug('STATUS: ' . $line); } // }}} // {{{ _handleDebugError() /** * Displays debug output for error lines * * @param string $line the error line to handle. * * @return void */ private function _handleDebugError($line) { $this->_debug('ERROR: ' . $line); } // }}} // {{{ _process() /** * Performs internal streaming operations for the subprocess using either * strings or streams as input / output points * * This is the main I/O loop for streaming to and from the GPG subprocess. * * The implementation of this method is verbose mainly for performance * reasons. Adding streams to a lookup array and looping the array inside * the main I/O loop would be siginficantly slower for large streams. * * @return void * * @throws Crypt_GPG_Exception if there is an error selecting streams for * reading or writing. If this occurs, please file a bug report at * http://pear.php.net/bugs/report.php?package=Crypt_GPG. */ private function _process() { $this->_debug('BEGIN PROCESSING'); $this->_commandBuffer = ''; // buffers input to GPG $messageBuffer = ''; // buffers input to GPG $inputBuffer = ''; // buffers input to GPG $outputBuffer = ''; // buffers output from GPG $statusBuffer = ''; // buffers output from GPG $errorBuffer = ''; // buffers output from GPG $inputComplete = false; // input stream is completely buffered $messageComplete = false; // message stream is completely buffered if (is_string($this->_input)) { $inputBuffer = $this->_input; $inputComplete = true; } if (is_string($this->_message)) { $messageBuffer = $this->_message; $messageComplete = true; } if (is_string($this->_output)) { $outputBuffer =& $this->_output; } // convenience variables $fdInput = $this->_pipes[self::FD_INPUT]; $fdOutput = $this->_pipes[self::FD_OUTPUT]; $fdError = $this->_pipes[self::FD_ERROR]; $fdStatus = $this->_pipes[self::FD_STATUS]; $fdCommand = $this->_pipes[self::FD_COMMAND]; $fdMessage = $this->_pipes[self::FD_MESSAGE]; // select loop delay in milliseconds $delay = 0; while (true) { $inputStreams = array(); $outputStreams = array(); $exceptionStreams = array(); // set up input streams if (is_resource($this->_input) && !$inputComplete) { if (feof($this->_input)) { $inputComplete = true; } else { $inputStreams[] = $this->_input; } } // close GPG input pipe if there is no more data if ($inputBuffer == '' && $inputComplete) { $this->_debug('=> closing GPG input pipe'); $this->_closePipe(self::FD_INPUT); } if (is_resource($this->_message) && !$messageComplete) { if (feof($this->_message)) { $messageComplete = true; } else { $inputStreams[] = $this->_message; } } // close GPG message pipe if there is no more data if ($messageBuffer == '' && $messageComplete) { $this->_debug('=> closing GPG message pipe'); $this->_closePipe(self::FD_MESSAGE); } if (!feof($fdOutput)) { $inputStreams[] = $fdOutput; } if (!feof($fdStatus)) { $inputStreams[] = $fdStatus; } if (!feof($fdError)) { $inputStreams[] = $fdError; } // set up output streams if ($outputBuffer != '' && is_resource($this->_output)) { $outputStreams[] = $this->_output; } if ($this->_commandBuffer != '' && is_resource($fdCommand)) { $outputStreams[] = $fdCommand; } if ($messageBuffer != '' && is_resource($fdMessage)) { $outputStreams[] = $fdMessage; } if ($inputBuffer != '' && is_resource($fdInput)) { $outputStreams[] = $fdInput; } // no streams left to read or write, we're all done if (count($inputStreams) === 0 && count($outputStreams) === 0) { break; } $this->_debug('selecting streams'); $ready = stream_select( $inputStreams, $outputStreams, $exceptionStreams, null ); $this->_debug('=> got ' . $ready); if ($ready === false) { throw new Crypt_GPG_Exception( 'Error selecting stream for communication with GPG ' . 'subprocess. Please file a bug report at: ' . 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); } if ($ready === 0) { throw new Crypt_GPG_Exception( 'stream_select() returned 0. This can not happen! Please ' . 'file a bug report at: ' . 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'); } // write input (to GPG) if (in_array($fdInput, $outputStreams, true)) { $this->_debug('GPG is ready for input'); $chunk = Crypt_GPG_ByteUtils::substr( $inputBuffer, 0, self::CHUNK_SIZE ); $length = Crypt_GPG_ByteUtils::strlen($chunk); $this->_debug( '=> about to write ' . $length . ' bytes to GPG input' ); $length = fwrite($fdInput, $chunk, $length); if ($length === 0) { // If we wrote 0 bytes it was either EAGAIN or EPIPE. Since // the pipe was seleted for writing, we assume it was EPIPE. // There's no way to get the actual erorr code in PHP. See // PHP Bug #39598. https://bugs.php.net/bug.php?id=39598 $this->_debug('=> broken pipe on GPG input'); $this->_debug('=> closing pipe GPG input'); $this->_closePipe(self::FD_INPUT); } else { $this->_debug('=> wrote ' . $length . ' bytes'); $inputBuffer = Crypt_GPG_ByteUtils::substr( $inputBuffer, $length ); } } // read input (from PHP stream) if (in_array($this->_input, $inputStreams, true)) { $this->_debug('input stream is ready for reading'); $this->_debug( '=> about to read ' . self::CHUNK_SIZE . ' bytes from input stream' ); $chunk = fread($this->_input, self::CHUNK_SIZE); $length = Crypt_GPG_ByteUtils::strlen($chunk); $inputBuffer .= $chunk; $this->_debug('=> read ' . $length . ' bytes'); } // write message (to GPG) if (in_array($fdMessage, $outputStreams, true)) { $this->_debug('GPG is ready for message data'); $chunk = Crypt_GPG_ByteUtils::substr( $messageBuffer, 0, self::CHUNK_SIZE ); $length = Crypt_GPG_ByteUtils::strlen($chunk); $this->_debug( '=> about to write ' . $length . ' bytes to GPG message' ); $length = fwrite($fdMessage, $chunk, $length); if ($length === 0) { // If we wrote 0 bytes it was either EAGAIN or EPIPE. Since // the pipe was seleted for writing, we assume it was EPIPE. // There's no way to get the actual erorr code in PHP. See // PHP Bug #39598. https://bugs.php.net/bug.php?id=39598 $this->_debug('=> broken pipe on GPG message'); $this->_debug('=> closing pipe GPG message'); $this->_closePipe(self::FD_MESSAGE); } else { $this->_debug('=> wrote ' . $length . ' bytes'); $messageBuffer = Crypt_GPG_ByteUtils::substr( $messageBuffer, $length ); } } // read message (from PHP stream) if (in_array($this->_message, $inputStreams, true)) { $this->_debug('message stream is ready for reading'); $this->_debug( '=> about to read ' . self::CHUNK_SIZE . ' bytes from message stream' ); $chunk = fread($this->_message, self::CHUNK_SIZE); $length = Crypt_GPG_ByteUtils::strlen($chunk); $messageBuffer .= $chunk; $this->_debug('=> read ' . $length . ' bytes'); } // read output (from GPG) if (in_array($fdOutput, $inputStreams, true)) { $this->_debug('GPG output stream ready for reading'); $this->_debug( '=> about to read ' . self::CHUNK_SIZE . ' bytes from GPG output' ); $chunk = fread($fdOutput, self::CHUNK_SIZE); $length = Crypt_GPG_ByteUtils::strlen($chunk); $outputBuffer .= $chunk; $this->_debug('=> read ' . $length . ' bytes'); } // write output (to PHP stream) if (in_array($this->_output, $outputStreams, true)) { $this->_debug('output stream is ready for data'); $chunk = Crypt_GPG_ByteUtils::substr( $outputBuffer, 0, self::CHUNK_SIZE ); $length = Crypt_GPG_ByteUtils::strlen($chunk); $this->_debug( '=> about to write ' . $length . ' bytes to output stream' ); $length = fwrite($this->_output, $chunk, $length); $this->_debug('=> wrote ' . $length . ' bytes'); $outputBuffer = Crypt_GPG_ByteUtils::substr( $outputBuffer, $length ); } // read error (from GPG) if (in_array($fdError, $inputStreams, true)) { $this->_debug('GPG error stream ready for reading'); $this->_debug( '=> about to read ' . self::CHUNK_SIZE . ' bytes from GPG error' ); $chunk = fread($fdError, self::CHUNK_SIZE); $length = Crypt_GPG_ByteUtils::strlen($chunk); $errorBuffer .= $chunk; $this->_debug('=> read ' . $length . ' bytes'); // pass lines to error handlers while (($pos = strpos($errorBuffer, PHP_EOL)) !== false) { $line = Crypt_GPG_ByteUtils::substr($errorBuffer, 0, $pos); foreach ($this->_errorHandlers as $handler) { array_unshift($handler['args'], $line); call_user_func_array( $handler['callback'], $handler['args'] ); array_shift($handler['args']); } $errorBuffer = Crypt_GPG_ByteUtils::substr( $errorBuffer, $pos + Crypt_GPG_ByteUtils::strlen(PHP_EOL) ); } } // read status (from GPG) if (in_array($fdStatus, $inputStreams, true)) { $this->_debug('GPG status stream ready for reading'); $this->_debug( '=> about to read ' . self::CHUNK_SIZE . ' bytes from GPG status' ); $chunk = fread($fdStatus, self::CHUNK_SIZE); $length = Crypt_GPG_ByteUtils::strlen($chunk); $statusBuffer .= $chunk; $this->_debug('=> read ' . $length . ' bytes'); // pass lines to status handlers while (($pos = strpos($statusBuffer, PHP_EOL)) !== false) { $line = Crypt_GPG_ByteUtils::substr($statusBuffer, 0, $pos); // only pass lines beginning with magic prefix if (Crypt_GPG_ByteUtils::substr($line, 0, 9) == '[GNUPG:] ') { $line = Crypt_GPG_ByteUtils::substr($line, 9); foreach ($this->_statusHandlers as $handler) { array_unshift($handler['args'], $line); call_user_func_array( $handler['callback'], $handler['args'] ); array_shift($handler['args']); } } $statusBuffer = Crypt_GPG_ByteUtils::substr( $statusBuffer, $pos + Crypt_GPG_ByteUtils::strlen(PHP_EOL) ); } } // write command (to GPG) if (in_array($fdCommand, $outputStreams, true)) { $this->_debug('GPG is ready for command data'); // send commands $chunk = Crypt_GPG_ByteUtils::substr( $this->_commandBuffer, 0, self::CHUNK_SIZE ); $length = Crypt_GPG_ByteUtils::strlen($chunk); $this->_debug( '=> about to write ' . $length . ' bytes to GPG command' ); $length = fwrite($fdCommand, $chunk, $length); if ($length === 0) { // If we wrote 0 bytes it was either EAGAIN or EPIPE. Since // the pipe was seleted for writing, we assume it was EPIPE. // There's no way to get the actual erorr code in PHP. See // PHP Bug #39598. https://bugs.php.net/bug.php?id=39598 $this->_debug('=> broken pipe on GPG command'); $this->_debug('=> closing pipe GPG command'); $this->_closePipe(self::FD_COMMAND); } else { $this->_debug('=> wrote ' . $length); $this->_commandBuffer = Crypt_GPG_ByteUtils::substr( $this->_commandBuffer, $length ); } } if (count($outputStreams) === 0 || count($inputStreams) === 0) { // we have an I/O imbalance, increase the select loop delay // to smooth things out $delay += 10; } else { // things are running smoothly, decrease the delay $delay -= 8; $delay = max(0, $delay); } if ($delay > 0) { usleep($delay); } } // end loop while streams are open $this->_debug('END PROCESSING'); } // }}} // {{{ _openSubprocess() /** * Opens an internal GPG subprocess for the current operation * * Opens a GPG subprocess, then connects the subprocess to some pipes. Sets * the private class property {@link Crypt_GPG_Engine::$_process} to * the new subprocess. * * @return void * * @throws Crypt_GPG_OpenSubprocessException if the subprocess could not be * opened. * * @see Crypt_GPG_Engine::setOperation() * @see Crypt_GPG_Engine::_closeSubprocess() * @see Crypt_GPG_Engine::$_process */ private function _openSubprocess() { $version = $this->getVersion(); // Binary operations will not work on Windows with PHP < 5.2.6. This is // in case stream_select() ever works on Windows. $rb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'r' : 'rb'; $wb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'w' : 'wb'; $env = $_ENV; // Newer versions of GnuPG return localized results. Crypt_GPG only // works with English, so set the locale to 'C' for the subprocess. $env['LC_ALL'] = 'C'; // If using GnuPG 2.x start the gpg-agent if (version_compare($version, '2.0.0', 'ge')) { $agentCommandLine = $this->_agent; $agentArguments = array( '--options /dev/null', // ignore any saved options '--csh', // output is easier to parse '--keep-display', // prevent passing --display to pinentry '--no-grab', '--ignore-cache-for-signing', '--pinentry-touch-file /dev/null', '--disable-scdaemon', '--no-use-standard-socket', '--pinentry-program ' . escapeshellarg($this->_getPinEntry()) ); if ($this->_homedir) { $agentArguments[] = '--homedir ' . escapeshellarg($this->_homedir); } $agentCommandLine .= ' ' . implode(' ', $agentArguments) . ' --daemon'; $agentDescriptorSpec = array( self::FD_INPUT => array('pipe', $rb), // stdin self::FD_OUTPUT => array('pipe', $wb), // stdout self::FD_ERROR => array('pipe', $wb) // stderr ); $this->_debug('OPENING GPG-AGENT SUBPROCESS WITH THE FOLLOWING COMMAND:'); $this->_debug($agentCommandLine); $this->_agentProcess = proc_open( $agentCommandLine, $agentDescriptorSpec, $this->_agentPipes, null, $env, array('binary_pipes' => true) ); if (!is_resource($this->_agentProcess)) { throw new Crypt_GPG_OpenSubprocessException( 'Unable to open gpg-agent subprocess.', 0, $agentCommandLine ); } // Get GPG_AGENT_INFO and set environment variable for gpg process. // This is a blocking read, but is only 1 line. $agentInfo = fread( $this->_agentPipes[self::FD_OUTPUT], self::CHUNK_SIZE ); $agentInfo = explode(' ', $agentInfo, 3); $this->_agentInfo = $agentInfo[2]; $env['GPG_AGENT_INFO'] = $this->_agentInfo; // gpg-agent daemon is started, we can close the launching process $this->_closeAgentLaunchProcess(); } $commandLine = $this->_binary; $defaultArguments = array( '--status-fd ' . escapeshellarg(self::FD_STATUS), '--command-fd ' . escapeshellarg(self::FD_COMMAND), '--no-secmem-warning', '--no-tty', '--no-default-keyring', // ignored if keying files are not specified '--no-options' // prevent creation of ~/.gnupg directory ); if (version_compare($version, '1.0.7', 'ge')) { if (version_compare($version, '2.0.0', 'lt')) { $defaultArguments[] = '--no-use-agent'; } $defaultArguments[] = '--no-permission-warning'; } if (version_compare($version, '1.4.2', 'ge')) { $defaultArguments[] = '--exit-on-status-write-error'; } if (version_compare($version, '1.3.2', 'ge')) { $defaultArguments[] = '--trust-model always'; } else { $defaultArguments[] = '--always-trust'; } $arguments = array_merge($defaultArguments, $this->_arguments); if ($this->_homedir) { $arguments[] = '--homedir ' . escapeshellarg($this->_homedir); // the random seed file makes subsequent actions faster so only // disable it if we have to. if (!is_writeable($this->_homedir)) { $arguments[] = '--no-random-seed-file'; } } if ($this->_publicKeyring) { $arguments[] = '--keyring ' . escapeshellarg($this->_publicKeyring); } if ($this->_privateKeyring) { $arguments[] = '--secret-keyring ' . escapeshellarg($this->_privateKeyring); } if ($this->_trustDb) { $arguments[] = '--trustdb-name ' . escapeshellarg($this->_trustDb); } $commandLine .= ' ' . implode(' ', $arguments) . ' ' . $this->_operation; $descriptorSpec = array( self::FD_INPUT => array('pipe', $rb), // stdin self::FD_OUTPUT => array('pipe', $wb), // stdout self::FD_ERROR => array('pipe', $wb), // stderr self::FD_STATUS => array('pipe', $wb), // status self::FD_COMMAND => array('pipe', $rb), // command self::FD_MESSAGE => array('pipe', $rb) // message ); $this->_debug('OPENING GPG SUBPROCESS WITH THE FOLLOWING COMMAND:'); $this->_debug($commandLine); $this->_process = proc_open( $commandLine, $descriptorSpec, $this->_pipes, null, $env, array('binary_pipes' => true) ); if (!is_resource($this->_process)) { throw new Crypt_GPG_OpenSubprocessException( 'Unable to open GPG subprocess.', 0, $commandLine); } // Set streams as non-blocking. See Bug #18618. foreach ($this->_pipes as $pipe) { stream_set_blocking($pipe, 0); } $this->_openPipes = $this->_pipes; $this->_errorCode = Crypt_GPG::ERROR_NONE; } // }}} // {{{ _closeSubprocess() /** * Closes a the internal GPG subprocess * * Closes the internal GPG subprocess. Sets the private class property * {@link Crypt_GPG_Engine::$_process} to null. * * @return void * * @see Crypt_GPG_Engine::_openSubprocess() * @see Crypt_GPG_Engine::$_process */ private function _closeSubprocess() { // clear PINs from environment if they were set $_ENV['PINENTRY_USER_DATA'] = null; if (is_resource($this->_process)) { $this->_debug('CLOSING GPG SUBPROCESS'); // close remaining open pipes foreach (array_keys($this->_openPipes) as $pipeNumber) { $this->_closePipe($pipeNumber); } $exitCode = proc_close($this->_process); if ($exitCode != 0) { $this->_debug( '=> subprocess returned an unexpected exit code: ' . $exitCode ); if ($this->_errorCode === Crypt_GPG::ERROR_NONE) { if ($this->_needPassphrase > 0) { $this->_errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE; } else { $this->_errorCode = Crypt_GPG::ERROR_UNKNOWN; } } } $this->_process = null; $this->_pipes = array(); } $this->_closeAgentLaunchProcess(); if ($this->_agentInfo !== null) { $this->_debug('STOPPING GPG-AGENT DAEMON'); $parts = explode(':', $this->_agentInfo, 3); $pid = $parts[1]; $process = new Crypt_GPG_ProcessControl($pid); // terminate agent daemon $process->terminate(); while ($process->isRunning()) { usleep(10000); // 10 ms $process->terminate(); } $this->_agentInfo = null; $this->_debug('GPG-AGENT DAEMON STOPPED'); } } // }}} // {{ _closeAgentLaunchProcess() private function _closeAgentLaunchProcess() { if (is_resource($this->_agentProcess)) { $this->_debug('CLOSING GPG-AGENT LAUNCH PROCESS'); // close agent pipes foreach ($this->_agentPipes as $pipe) { fflush($pipe); fclose($pipe); } // close agent launching process proc_close($this->_agentProcess); $this->_agentProcess = null; $this->_agentPipes = array(); $this->_debug('GPG-AGENT LAUNCH PROCESS CLOSED'); } } // }} // {{{ _closePipe() /** * Closes an opened pipe used to communicate with the GPG subprocess * * If the pipe is already closed, it is ignored. If the pipe is open, it * is flushed and then closed. * * @param integer $pipeNumber the file descriptor number of the pipe to * close. * * @return void */ private function _closePipe($pipeNumber) { $pipeNumber = intval($pipeNumber); if (array_key_exists($pipeNumber, $this->_openPipes)) { fflush($this->_openPipes[$pipeNumber]); fclose($this->_openPipes[$pipeNumber]); unset($this->_openPipes[$pipeNumber]); } } // }}} // {{{ _getBinary() /** * Gets the name of the GPG binary for the current operating system * * This method is called if the 'binary' option is not * specified when creating this driver. * * @return string the name of the GPG binary for the current operating * system. If no suitable binary could be found, an empty * string is returned. */ private function _getBinary() { $binary = ''; if ($this->_isDarwin) { $binaryFiles = array( '/opt/local/bin/gpg', // MacPorts '/usr/local/bin/gpg', // Mac GPG '/sw/bin/gpg', // Fink '/usr/bin/gpg' ); } else { $binaryFiles = array( '/usr/bin/gpg', '/usr/local/bin/gpg' ); } foreach ($binaryFiles as $binaryFile) { if (is_executable($binaryFile)) { $binary = $binaryFile; break; } } return $binary; } // }}} // {{ _getAgent() private function _getAgent() { $agent = ''; if ($this->_isDarwin) { $agentFiles = array( '/opt/local/bin/gpg-agent', // MacPorts '/usr/local/bin/gpg-agent', // Mac GPG '/sw/bin/gpg-agent', // Fink '/usr/bin/gpg-agent' ); } else { $agentFiles = array( '/usr/bin/gpg-agent', '/usr/local/bin/gpg-agent' ); } foreach ($agentFiles as $agentFile) { if (is_executable($agentFile)) { $agent = $agentFile; break; } } return $agent; } // }} // {{ _getPinEntry() private function _getPinEntry() { // Check if we're running directly from git or if we're using a // PEAR-packaged version $pinEntry = '@bin-dir@' . DIRECTORY_SEPARATOR . 'crypt-gpg-pinentry'; if ($pinEntry[0] === '@') { $pinEntry = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'scripts' . DIRECTORY_SEPARATOR . 'crypt-gpg-pinentry'; } return $pinEntry; } // }} // {{{ _debug() /** * Displays debug text if debugging is turned on * * Debugging text is prepended with a debug identifier and echoed to stdout. * * @param string $text the debugging text to display. * * @return void */ private function _debug($text) { if ($this->_debug) { if (php_sapi_name() === 'cli') { foreach (explode(PHP_EOL, $text) as $line) { echo "Crypt_GPG DEBUG: ", $line, PHP_EOL; } } else { // running on a web server, format debug output nicely foreach (explode(PHP_EOL, $text) as $line) { echo "Crypt_GPG DEBUG: ", htmlspecialchars($line), '
', PHP_EOL; } } } } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/Exceptions.php0000664000175000017500000003542712610161626016272 0ustar alecalec * @author Michael Gauthier * @copyright 2005-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * PEAR Exception handler and base class */ require_once 'PEAR/Exception.php'; // {{{ class Crypt_GPG_Exception /** * An exception thrown by the Crypt_GPG package * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_Exception extends PEAR_Exception { } // }}} // {{{ class Crypt_GPG_FileException /** * An exception thrown when a file is used in ways it cannot be used * * For example, if an output file is specified and the file is not writeable, or * if an input file is specified and the file is not readable, this exception * is thrown. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2007-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_FileException extends Crypt_GPG_Exception { // {{{ private class properties /** * The name of the file that caused this exception * * @var string */ private $_filename = ''; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_FileException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $filename the name of the file that caused this exception. */ public function __construct($message, $code = 0, $filename = '') { $this->_filename = $filename; parent::__construct($message, $code); } // }}} // {{{ getFilename() /** * Returns the filename of the file that caused this exception * * @return string the filename of the file that caused this exception. * * @see Crypt_GPG_FileException::$_filename */ public function getFilename() { return $this->_filename; } // }}} } // }}} // {{{ class Crypt_GPG_OpenSubprocessException /** * An exception thrown when the GPG subprocess cannot be opened * * This exception is thrown when the {@link Crypt_GPG_Engine} tries to open a * new subprocess and fails. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_OpenSubprocessException extends Crypt_GPG_Exception { // {{{ private class properties /** * The command used to try to open the subprocess * * @var string */ private $_command = ''; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_OpenSubprocessException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $command the command that was called to open the * new subprocess. * * @see Crypt_GPG::_openSubprocess() */ public function __construct($message, $code = 0, $command = '') { $this->_command = $command; parent::__construct($message, $code); } // }}} // {{{ getCommand() /** * Returns the contents of the internal _command property * * @return string the command used to open the subprocess. * * @see Crypt_GPG_OpenSubprocessException::$_command */ public function getCommand() { return $this->_command; } // }}} } // }}} // {{{ class Crypt_GPG_InvalidOperationException /** * An exception thrown when an invalid GPG operation is attempted * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_InvalidOperationException extends Crypt_GPG_Exception { // {{{ private class properties /** * The attempted operation * * @var string */ private $_operation = ''; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_OpenSubprocessException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $operation the operation. */ public function __construct($message, $code = 0, $operation = '') { $this->_operation = $operation; parent::__construct($message, $code); } // }}} // {{{ getOperation() /** * Returns the contents of the internal _operation property * * @return string the attempted operation. * * @see Crypt_GPG_InvalidOperationException::$_operation */ public function getOperation() { return $this->_operation; } // }}} } // }}} // {{{ class Crypt_GPG_KeyNotFoundException /** * An exception thrown when Crypt_GPG fails to find the key for various * operations * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_KeyNotFoundException extends Crypt_GPG_Exception { // {{{ private class properties /** * The key identifier that was searched for * * @var string */ private $_keyId = ''; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_KeyNotFoundException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $keyId the key identifier of the key. */ public function __construct($message, $code = 0, $keyId= '') { $this->_keyId = $keyId; parent::__construct($message, $code); } // }}} // {{{ getKeyId() /** * Gets the key identifier of the key that was not found * * @return string the key identifier of the key that was not found. */ public function getKeyId() { return $this->_keyId; } // }}} } // }}} // {{{ class Crypt_GPG_NoDataException /** * An exception thrown when Crypt_GPG cannot find valid data for various * operations * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2006 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_NoDataException extends Crypt_GPG_Exception { } // }}} // {{{ class Crypt_GPG_BadPassphraseException /** * An exception thrown when a required passphrase is incorrect or missing * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2006-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_BadPassphraseException extends Crypt_GPG_Exception { // {{{ private class properties /** * Keys for which the passhprase is missing * * This contains primary user ids indexed by sub-key id. * * @var array */ private $_missingPassphrases = array(); /** * Keys for which the passhprase is incorrect * * This contains primary user ids indexed by sub-key id. * * @var array */ private $_badPassphrases = array(); // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_BadPassphraseException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $badPassphrases an array containing user ids of keys * for which the passphrase is incorrect. * @param string $missingPassphrases an array containing user ids of keys * for which the passphrase is missing. */ public function __construct($message, $code = 0, array $badPassphrases = array(), array $missingPassphrases = array() ) { $this->_badPassphrases = $badPassphrases; $this->_missingPassphrases = $missingPassphrases; parent::__construct($message, $code); } // }}} // {{{ getBadPassphrases() /** * Gets keys for which the passhprase is incorrect * * @return array an array of keys for which the passphrase is incorrect. * The array contains primary user ids indexed by the sub-key * id. */ public function getBadPassphrases() { return $this->_badPassphrases; } // }}} // {{{ getMissingPassphrases() /** * Gets keys for which the passhprase is missing * * @return array an array of keys for which the passphrase is missing. * The array contains primary user ids indexed by the sub-key * id. */ public function getMissingPassphrases() { return $this->_missingPassphrases; } // }}} } // }}} // {{{ class Crypt_GPG_DeletePrivateKeyException /** * An exception thrown when an attempt is made to delete public key that has an * associated private key on the keyring * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_DeletePrivateKeyException extends Crypt_GPG_Exception { // {{{ private class properties /** * The key identifier the deletion attempt was made upon * * @var string */ private $_keyId = ''; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_DeletePrivateKeyException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $keyId the key identifier of the public key that was * attempted to delete. * * @see Crypt_GPG::deletePublicKey() */ public function __construct($message, $code = 0, $keyId = '') { $this->_keyId = $keyId; parent::__construct($message, $code); } // }}} // {{{ getKeyId() /** * Gets the key identifier of the key that was not found * * @return string the key identifier of the key that was not found. */ public function getKeyId() { return $this->_keyId; } // }}} } // }}} // {{{ class Crypt_GPG_KeyNotCreatedException /** * An exception thrown when an attempt is made to generate a key and the * attempt fails * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_KeyNotCreatedException extends Crypt_GPG_Exception { } // }}} // {{{ class Crypt_GPG_InvalidKeyParamsException /** * An exception thrown when an attempt is made to generate a key and the * key parameters set on the key generator are invalid * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_InvalidKeyParamsException extends Crypt_GPG_Exception { // {{{ private class properties /** * The key algorithm * * @var integer */ private $_algorithm = 0; /** * The key size * * @var integer */ private $_size = 0; /** * The key usage * * @var integer */ private $_usage = 0; // }}} // {{{ __construct() /** * Creates a new Crypt_GPG_InvalidKeyParamsException * * @param string $message an error message. * @param integer $code a user defined error code. * @param string $algorithm the key algorithm. * @param string $size the key size. * @param string $usage the key usage. */ public function __construct( $message, $code = 0, $algorithm = 0, $size = 0, $usage = 0 ) { parent::__construct($message, $code); $this->_algorithm = $algorithm; $this->_size = $size; $this->_usage = $usage; } // }}} // {{{ getAlgorithm() /** * Gets the key algorithm * * @return integer the key algorithm. */ public function getAlgorithm() { return $this->_algorithm; } // }}} // {{{ getSize() /** * Gets the key size * * @return integer the key size. */ public function getSize() { return $this->_size; } // }}} // {{{ getUsage() /** * Gets the key usage * * @return integer the key usage. */ public function getUsage() { return $this->_usage; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/Key.php0000664000175000017500000001231612610161626014671 0ustar alecalec * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Sub-key class definition */ require_once 'Crypt/GPG/SubKey.php'; /** * User id class definition */ require_once 'Crypt/GPG/UserId.php'; // {{{ class Crypt_GPG_Key /** * A data class for GPG key information * * This class is used to store the results of the {@link Crypt_GPG::getKeys()} * method. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @see Crypt_GPG::getKeys() */ class Crypt_GPG_Key { // {{{ class properties /** * The user ids associated with this key * * This is an array of {@link Crypt_GPG_UserId} objects. * * @var array * * @see Crypt_GPG_Key::addUserId() * @see Crypt_GPG_Key::getUserIds() */ private $_userIds = array(); /** * The subkeys of this key * * This is an array of {@link Crypt_GPG_SubKey} objects. * * @var array * * @see Crypt_GPG_Key::addSubKey() * @see Crypt_GPG_Key::getSubKeys() */ private $_subKeys = array(); // }}} // {{{ getSubKeys() /** * Gets the sub-keys of this key * * @return array the sub-keys of this key. * * @see Crypt_GPG_Key::addSubKey() */ public function getSubKeys() { return $this->_subKeys; } // }}} // {{{ getUserIds() /** * Gets the user ids of this key * * @return array the user ids of this key. * * @see Crypt_GPG_Key::addUserId() */ public function getUserIds() { return $this->_userIds; } // }}} // {{{ getPrimaryKey() /** * Gets the primary sub-key of this key * * The primary key is the first added sub-key. * * @return Crypt_GPG_SubKey the primary sub-key of this key. */ public function getPrimaryKey() { $primary_key = null; if (count($this->_subKeys) > 0) { $primary_key = $this->_subKeys[0]; } return $primary_key; } // }}} // {{{ canSign() /** * Gets whether or not this key can sign data * * This key can sign data if any sub-key of this key can sign data. * * @return boolean true if this key can sign data and false if this key * cannot sign data. */ public function canSign() { $canSign = false; foreach ($this->_subKeys as $subKey) { if ($subKey->canSign()) { $canSign = true; break; } } return $canSign; } // }}} // {{{ canEncrypt() /** * Gets whether or not this key can encrypt data * * This key can encrypt data if any sub-key of this key can encrypt data. * * @return boolean true if this key can encrypt data and false if this * key cannot encrypt data. */ public function canEncrypt() { $canEncrypt = false; foreach ($this->_subKeys as $subKey) { if ($subKey->canEncrypt()) { $canEncrypt = true; break; } } return $canEncrypt; } // }}} // {{{ addSubKey() /** * Adds a sub-key to this key * * The first added sub-key will be the primary key of this key. * * @param Crypt_GPG_SubKey $subKey the sub-key to add. * * @return Crypt_GPG_Key the current object, for fluent interface. */ public function addSubKey(Crypt_GPG_SubKey $subKey) { $this->_subKeys[] = $subKey; return $this; } // }}} // {{{ addUserId() /** * Adds a user id to this key * * @param Crypt_GPG_UserId $userId the user id to add. * * @return Crypt_GPG_Key the current object, for fluent interface. */ public function addUserId(Crypt_GPG_UserId $userId) { $this->_userIds[] = $userId; return $this; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/KeyGenerator.php0000664000175000017500000007106612610161626016547 0ustar alecalec * @copyright 2011-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id:$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Base class for GPG methods */ require_once 'Crypt/GPGAbstract.php'; /** * Status output handler for key generation */ require_once 'Crypt/GPG/KeyGeneratorStatusHandler.php'; /** * Error output handler for key generation */ require_once 'Crypt/GPG/KeyGeneratorErrorHandler.php'; // {{{ class Crypt_GPG_KeyGenerator /** * GnuPG key generator * * This class provides an object oriented interface for generating keys with * the GNU Privacy Guard (GPG). * * Secure key generation requires true random numbers, and as such can be slow. * If the operating system runs out of entropy, key generation will block until * more entropy is available. * * If quick key generation is important, a hardware entropy generator, or an * entropy gathering daemon may be installed. For example, administrators of * Debian systems may want to install the 'randomsound' package. * * This class uses the experimental automated key generation support available * in GnuPG. See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on the key generation format. * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_KeyGenerator extends Crypt_GPGAbstract { // {{{ protected properties /** * The expiration date of generated keys * * @var integer * * @see Crypt_GPG_KeyGenerator::setExpirationDate() */ protected $expirationDate = 0; /** * The passphrase of generated keys * * @var string * * @see Crypt_GPG_KeyGenerator::setPassphrase() */ protected $passphrase = ''; /** * The algorithm for generated primary keys * * @var integer * * @see Crypt_GPG_KeyGenerator::setKeyParams() */ protected $keyAlgorithm = Crypt_GPG_SubKey::ALGORITHM_DSA; /** * The size of generated primary keys * * @var integer * * @see Crypt_GPG_KeyGenerator::setKeyParams() */ protected $keySize = 1024; /** * The usages of generated primary keys * * This is a bitwise combination of the usage constants in * {@link Crypt_GPG_SubKey}. * * @var integer * * @see Crypt_GPG_KeyGenerator::setKeyParams() */ protected $keyUsage = 6; // USAGE_SIGN | USAGE_CERTIFY /** * The algorithm for generated sub-keys * * @var integer * * @see Crypt_GPG_KeyGenerator::setSubKeyParams() */ protected $subKeyAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC; /** * The size of generated sub-keys * * @var integer * * @see Crypt_GPG_KeyGenerator::setSubKeyParams() */ protected $subKeySize = 2048; /** * The usages of generated sub-keys * * This is a bitwise combination of the usage constants in * {@link Crypt_GPG_SubKey}. * * @var integer * * @see Crypt_GPG_KeyGenerator::setSubKeyParams() */ protected $subKeyUsage = Crypt_GPG_SubKey::USAGE_ENCRYPT; /** * The GnuPG status handler to use for key generation * * @var Crypt_GPG_KeyGeneratorStatusHandler * * @see Crypt_GPG_KeyGenerator::setStatusHandler() */ protected $statusHandler = null; /** * The GnuPG error handler to use for key generation * * @var Crypt_GPG_KeyGeneratorErrorHandler * * @see Crypt_GPG_KeyGenerator::setErrorHandler() */ protected $errorHandler = null; // }}} // {{{ __construct() /** * Creates a new GnuPG key generator * * Available options are: * * - string homedir - the directory where the GPG * keyring files are stored. If not * specified, Crypt_GPG uses the * default of ~/.gnupg. * - string publicKeyring - the file path of the public * keyring. Use this if the public * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/pubring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string privateKeyring - the file path of the private * keyring. Use this if the private * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/secring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string trustDb - the file path of the web-of-trust * database. Use this if the trust * database is not in the homedir, or * if the database is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * trust database with this option * (/foo/bar/trustdb.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string binary - the location of the GPG binary. If * not specified, the driver attempts * to auto-detect the GPG binary * location using a list of known * default locations for the current * operating system. The option * gpgBinary is a * deprecated alias for this option. * - string agent - the location of the GnuPG agent * binary. The gpg-agent is only * used for GnuPG 2.x. If not * specified, the engine attempts * to auto-detect the gpg-agent * binary location using a list of * know default locations for the * current operating system. * - boolean debug - whether or not to use debug mode. * When debug mode is on, all * communication to and from the GPG * subprocess is logged. This can be * * @param array $options optional. An array of options used to create the * GPG object. All options are optional and are * represented as key-value pairs. * * @throws Crypt_GPG_FileException if the homedir does not exist * and cannot be created. This can happen if homedir is * not specified, Crypt_GPG is run as the web user, and the web * user has no home directory. This exception is also thrown if any * of the options publicKeyring, * privateKeyring or trustDb options are * specified but the files do not exist or are are not readable. * This can happen if the user running the Crypt_GPG process (for * example, the Apache user) does not have permission to read the * files. * * @throws PEAR_Exception if the provided binary is invalid, or * if no binary is provided and no suitable binary could * be found. * * @throws PEAR_Exception if the provided agent is invalid, or * if no agent is provided and no suitable gpg-agent * cound be found. */ public function __construct(array $options = array()) { parent::__construct($options); $this->statusHandler = new Crypt_GPG_KeyGeneratorStatusHandler(); $this->errorHandler = new Crypt_GPG_KeyGeneratorErrorHandler(); } // }}} // {{{ setExpirationDate() /** * Sets the expiration date of generated keys * * @param string|integer $date either a string that may be parsed by * PHP's strtotime() function, or an integer * timestamp representing the number of seconds * since the UNIX epoch. This date must be at * least one date in the future. Keys that * expire in the past may not be generated. Use * an expiration date of 0 for keys that do not * expire. * * @throws InvalidArgumentException if the date is not a valid format, or * if the date is not at least one day in * the future, or if the date is greater * than 2038-01-19T03:14:07. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setExpirationDate($date) { if (is_int($date) || ctype_digit(strval($date))) { $expirationDate = intval($date); } else { $expirationDate = strtotime($date); } if ($expirationDate === false) { throw new InvalidArgumentException( sprintf( 'Invalid expiration date format: "%s". Please use a ' . 'format compatible with PHP\'s strtotime().', $date ) ); } if ($expirationDate !== 0 && $expirationDate < time() + 86400) { throw new InvalidArgumentException( 'Expiration date must be at least a day in the future.' ); } // GnuPG suffers from the 2038 bug if ($expirationDate > 2147483647) { throw new InvalidArgumentException( 'Expiration date must not be greater than 2038-01-19T03:14:07.' ); } $this->expirationDate = $expirationDate; return $this; } // }}} // {{{ setPassphrase() /** * Sets the passphrase of generated keys * * @param string $passphrase the passphrase to use for generated keys. Use * null or an empty string for no passphrase. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setPassphrase($passphrase) { $this->passphrase = strval($passphrase); return $this; } // }}} // {{{ setKeyParams() /** * Sets the parameters for the primary key of generated key-pairs * * @param integer $algorithm the algorithm used by the key. This should be * one of the Crypt_GPG_SubKey::ALGORITHM_* * constants. * @param integer $size optional. The size of the key. Different * algorithms have different size requirements. * If not specified, the default size for the * specified algorithm will be used. If an * invalid key size is used, GnuPG will do its * best to round it to a valid size. * @param integer $usage optional. A bitwise combination of key usages. * If not specified, the primary key will be used * only to sign and certify. This is the default * behavior of GnuPG in interactive mode. Use * the Crypt_GPG_SubKey::USAGE_* constants here. * The primary key may be used to certify even * if the certify usage is not specified. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setKeyParams($algorithm, $size = 0, $usage = 0) { $algorithm = intval($algorithm); if ($algorithm === Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC) { throw new Crypt_GPG_InvalidKeyParamsException( 'Primary key algorithm must be capable of signing. The ' . 'Elgamal algorithm can only encrypt.', 0, $algorithm, $size, $usage ); } if ($size != 0) { $size = intval($size); } if ($usage != 0) { $usage = intval($usage); } $usageEncrypt = Crypt_GPG_SubKey::USAGE_ENCRYPT; if ( $algorithm === Crypt_GPG_SubKey::ALGORITHM_DSA && ($usage & $usageEncrypt) === $usageEncrypt ) { throw new Crypt_GPG_InvalidKeyParamsException( 'The DSA algorithm is not capable of encrypting. Please ' . 'specify a different algorithm or do not include encryption ' . 'as a usage for the primary key.', 0, $algorithm, $size, $usage ); } $this->keyAlgorithm = $algorithm; if ($size != 0) { $this->keySize = $size; } if ($usage != 0) { $this->keyUsage = $usage; } return $this; } // }}} // {{{ setSubKeyParams() /** * Sets the parameters for the sub-key of generated key-pairs * * @param integer $algorithm the algorithm used by the key. This should be * one of the Crypt_GPG_SubKey::ALGORITHM_* * constants. * @param integer $size optional. The size of the key. Different * algorithms have different size requirements. * If not specified, the default size for the * specified algorithm will be used. If an * invalid key size is used, GnuPG will do its * best to round it to a valid size. * @param integer $usage optional. A bitwise combination of key usages. * If not specified, the sub-key will be used * only to encrypt. This is the default behavior * of GnuPG in interactive mode. Use the * Crypt_GPG_SubKey::USAGE_* constants here. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setSubKeyParams($algorithm, $size = '', $usage = 0) { $algorithm = intval($algorithm); if ($size != 0) { $size = intval($size); } if ($usage != 0) { $usage = intval($usage); } $usageSign = Crypt_GPG_SubKey::USAGE_SIGN; if ( $algorithm === Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC && ($usage & $usageSign) === $usageSign ) { throw new Crypt_GPG_InvalidKeyParamsException( 'The Elgamal algorithm is not capable of signing. Please ' . 'specify a different algorithm or do not include signing ' . 'as a usage for the sub-key.', 0, $algorithm, $size, $usage ); } $usageEncrypt = Crypt_GPG_SubKey::USAGE_ENCRYPT; if ( $algorithm === Crypt_GPG_SubKey::ALGORITHM_DSA && ($usage & $usageEncrypt) === $usageEncrypt ) { throw new Crypt_GPG_InvalidKeyParamsException( 'The DSA algorithm is not capable of encrypting. Please ' . 'specify a different algorithm or do not include encryption ' . 'as a usage for the sub-key.', 0, $algorithm, $size, $usage ); } $this->subKeyAlgorithm = $algorithm; if ($size != 0) { $this->subKeySize = $size; } if ($usage != 0) { $this->subKeyUsage = $usage; } return $this; } // }}} // {{{ setStatusHandler() /** * Sets the status handler to use for key generation * * Normally this method does not need to be used. It provides a means for * dependency injection. * * @param Crypt_GPG_KeyStatusHandler $handler the key status handler to * use. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setStatusHandler( Crypt_GPG_KeyGeneratorStatusHandler $handler ) { $this->statusHandler = $handler; return $this; } // }}} // {{{ setErrorHandler() /** * Sets the error handler to use for key generation * * Normally this method does not need to be used. It provides a means for * dependency injection. * * @param Crypt_GPG_KeyErrorHandler $handler the key error handler to * use. * * @return Crypt_GPG_KeyGenerator the current object, for fluent interface. */ public function setErrorHandler( Crypt_GPG_KeyGeneratorErrorHandler $handler ) { $this->errorHandler = $handler; return $this; } // }}} // {{{ generateKey() /** * Generates a new key-pair in the current keyring * * Secure key generation requires true random numbers, and as such can be * solw. If the operating system runs out of entropy, key generation will * block until more entropy is available. * * If quick key generation is important, a hardware entropy generator, or * an entropy gathering daemon may be installed. For example, * administrators of Debian systems may want to install the 'randomsound' * package. * * @param string|Crypt_GPG_UserId $name either a {@link Crypt_GPG_UserId} * object, or a string containing * the name of the user id. * @param string $email optional. If $name is * specified as a string, this is * the email address of the user id. * @param string $comment optional. If $name is * specified as a string, this is * the comment of the user id. * * @return Crypt_GPG_Key the newly generated key. * * @throws Crypt_GPG_KeyNotCreatedException if the key parameters are * incorrect, if an unknown error occurs during key generation, or * if the newly generated key is not found in the keyring. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function generateKey($name, $email = '', $comment = '') { $handle = uniqid('key', true); $userId = $this->getUserId($name, $email, $comment); $keyParams = array( 'Key-Type' => $this->keyAlgorithm, 'Key-Length' => $this->keySize, 'Key-Usage' => $this->getUsage($this->keyUsage), 'Subkey-Type' => $this->subKeyAlgorithm, 'Subkey-Length' => $this->subKeySize, 'Subkey-Usage' => $this->getUsage($this->subKeyUsage), 'Name-Real' => $userId->getName(), 'Handle' => $handle, ); if ($this->expirationDate != 0) { // GnuPG only accepts granularity of days $expirationDate = date('Y-m-d', $this->expirationDate); $keyParams['Expire-Date'] = $expirationDate; } if ($this->passphrase != '') { $keyParams['Passphrase'] = $this->passphrase; } if ($userId->getEmail() != '') { $keyParams['Name-Email'] = $userId->getEmail(); } if ($userId->getComment() != '') { $keyParams['Name-Comment'] = $userId->getComment(); } $keyParamsFormatted = array(); foreach ($keyParams as $name => $value) { $keyParamsFormatted[] = $name . ': ' . $value; } $input = implode("\n", $keyParamsFormatted) . "\n%commit\n"; $statusHandler = clone $this->statusHandler; $statusHandler->setHandle($handle); $errorHandler = clone $this->errorHandler; $this->engine->reset(); $this->engine->addStatusHandler(array($statusHandler, 'handle')); $this->engine->addErrorHandler(array($errorHandler, 'handle')); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->setOperation('--gen-key', array('--batch')); $this->engine->run(); $code = $errorHandler->getErrorCode(); switch ($code) { case self::ERROR_BAD_KEY_PARAMS: switch ($errorHandler->getLineNumber()) { case 1: throw new Crypt_GPG_InvalidKeyParamsException( 'Invalid primary key algorithm specified.', 0, $this->keyAlgorithm, $this->keySize, $this->keyUsage ); case 4: throw new Crypt_GPG_InvalidKeyParamsException( 'Invalid sub-key algorithm specified.', 0, $this->subKeyAlgorithm, $this->subKeySize, $this->subKeyUsage ); default: throw new Crypt_GPG_InvalidKeyParamsException( 'Invalid key algorithm specified.' ); } } $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; default: throw new Crypt_GPG_Exception( 'Unknown error generating key-pair. Please use the \'debug\' ' . 'option when creating the Crypt_GPG object, and file a bug ' . 'report at ' . self::BUG_URI, $code ); } $code = $statusHandler->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; case self::ERROR_KEY_NOT_CREATED: throw new Crypt_GPG_KeyNotCreatedException( 'Unable to create new key-pair. Invalid key parameters. ' . 'Make sure the specified key algorithms and sizes are ' . 'correct.', $code ); } $fingerprint = $statusHandler->getKeyFingerprint(); $keys = $this->_getKeys($fingerprint); if (count($keys) === 0) { throw new Crypt_GPG_KeyNotCreatedException( sprintf( 'Newly created key "%s" not found in keyring.', $fingerprint ) ); } return $keys[0]; } // }}} // {{{ getUsage() /** * Builds a GnuPG key usage string suitable for key generation * * See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on the key usage format. * * @param integer $usage a bitwise combination of the key usages. This is * a combination of the Crypt_GPG_SubKey::USAGE_* * constants. * * @return string the key usage string. */ protected function getUsage($usage) { $map = array( Crypt_GPG_SubKey::USAGE_ENCRYPT => 'encrypt', Crypt_GPG_SubKey::USAGE_SIGN => 'sign', Crypt_GPG_SubKey::USAGE_CERTIFY => 'cert', Crypt_GPG_SubKey::USAGE_AUTHENTICATION => 'auth', ); // cert is always used for primary keys and does not need to be // specified $usage &= ~Crypt_GPG_SubKey::USAGE_CERTIFY; $usageArray = array(); foreach ($map as $key => $value) { if (($usage & $key) === $key) { $usageArray[] = $value; } } return implode(',', $usageArray); } // }}} // {{{ getUserId() /** * Gets a user id object from parameters * * @param string|Crypt_GPG_UserId $name either a {@link Crypt_GPG_UserId} * object, or a string containing * the name of the user id. * @param string $email optional. If $name is * specified as a string, this is * the email address of the user id. * @param string $comment optional. If $name is * specified as a string, this is * the comment of the user id. * * @return Crypt_GPG_UserId a user id object for the specified parameters. */ protected function getUserId($name, $email = '', $comment = '') { if ($name instanceof Crypt_GPG_UserId) { $userId = $name; } else { $userId = new Crypt_GPG_UserId(); $userId->setName($name)->setEmail($email)->setComment($comment); } return $userId; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/KeyGeneratorErrorHandler.php0000664000175000017500000000627712610161626021061 0ustar alecalec * @copyright 2011-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id:$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Error line handler for the key generation operation * * This class is used internally by Crypt_GPG and does not need be used * directly. See the {@link Crypt_GPG} class for end-user API. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2011-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_KeyGeneratorErrorHandler { // {{{ protected properties /** * Error code (if any) caused by key generation * * @var integer */ protected $errorCode = Crypt_GPG::ERROR_NONE; /** * Line number at which the error occurred * * @var integer */ protected $lineNumber = null; // }}} // {{{ handle() /** * Handles an error line * * @param string $line the error line to handle. * * @return void */ public function handle($line) { $matches = array(); $pattern = '/:([0-9]+): invalid algorithm$/'; if (preg_match($pattern, $line, $matches) === 1) { $this->errorCode = Crypt_GPG::ERROR_BAD_KEY_PARAMS; $this->lineNumber = intval($matches[1]); } } // }}} // {{{ getErrorCode() /** * Gets the error code resulting from key gneration * * @return integer the error code resulting from key generation. */ public function getErrorCode() { return $this->errorCode; } // }}} // {{{ getLineNumber() /** * Gets the line number at which the error occurred * * @return integer the line number at which the error occurred. Null if * no error occurred. */ public function getLineNumber() { return $this->lineNumber; } // }}} } ?> Crypt_GPG-1.4.0/Crypt/GPG/KeyGeneratorStatusHandler.php0000664000175000017500000001130012610161626021232 0ustar alecalec * @copyright 2011-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id:$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Status line handler for the key generation operation * * This class is used internally by Crypt_GPG and does not need be used * directly. See the {@link Crypt_GPG} class for end-user API. * * This class is responsible for parsing the final key fingerprint from the * status output and for updating the key generation progress file. See * doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on GPG's status output for the batch key generation operation. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2011-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_KeyGeneratorStatusHandler { // {{{ protected properties /** * The key fingerprint * * Ths key fingerprint is emitted by GPG after the key generation is * complete. * * @var string */ protected $keyFingerprint = ''; /** * The unique key handle used by this handler * * The key handle is used to track GPG status output for a particular key * before the key has its own identifier. * * @var string * * @see Crypt_GPG_KeyGeneratorStatusHandler::setHandle() */ protected $handle = ''; /** * Error code (if any) caused by key generation * * @var integer */ protected $errorCode = Crypt_GPG::ERROR_NONE; // }}} // {{{ setHandle() /** * Sets the unique key handle used by this handler * * The key handle is used to track GPG status output for a particular key * before the key has its own identifier. * * @param string $handle the key handle this status handle will use. * * @return Crypt_GPG_KeyGeneratorStatusHandler the current object, for * fluent interface. */ public function setHandle($handle) { $this->handle = strval($handle); return $this; } // }}} // {{{ handle() /** * Handles a status line * * @param string $line the status line to handle. * * @return void */ public function handle($line) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'KEY_CREATED': if ($tokens[3] == $this->handle) { $this->keyFingerprint = $tokens[2]; } break; case 'KEY_NOT_CREATED': if ($tokens[1] == $this->handle) { $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_CREATED; } break; case 'PROGRESS': // todo: at some point, support reporting status async break; } } // }}} // {{{ getKeyFingerprint() /** * Gets the key fingerprint parsed by this handler * * @return array the key fingerprint parsed by this handler. */ public function getKeyFingerprint() { return $this->keyFingerprint; } // }}} // {{{ getErrorCode() /** * Gets the error code resulting from key gneration * * @return integer the error code resulting from key generation. */ public function getErrorCode() { return $this->errorCode; } // }}} } ?> Crypt_GPG-1.4.0/Crypt/GPG/PinEntry.php0000664000175000017500000005732312610161626015720 0ustar alecalec * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * CLI user-interface and parser. */ require_once 'Console/CommandLine.php'; // {{{ class Crypt_GPG_PinEntry /** * A command-line dummy pinentry program for use with gpg-agent and Crypt_GPG * * This pinentry receives passphrases through en environment variable and * automatically enters the PIN in response to gpg-agent requests. No user- * interaction required. * * Thie pinentry can be run independently for testing and debugging with the * following syntax: * *
 * Usage:
 *   crypt-gpg-pinentry [options]
 *
 * Options:
 *   -l log, --log=log  Optional location to log pinentry activity.
 *   -v, --verbose      Sets verbosity level. Use multiples for more detail
 *                      (e.g. "-vv").
 *   -h, --help         show this help message and exit
 *   --version          show the program version and exit
 * 
* * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @see Crypt_GPG::getKeys() */ class Crypt_GPG_PinEntry { // {{{ class constants /** * Verbosity level for showing no output. */ const VERBOSITY_NONE = 0; /** * Verbosity level for showing error output. */ const VERBOSITY_ERRORS = 1; /** * Verbosity level for showing all output, including Assuan protocol * messages. */ const VERBOSITY_ALL = 2; /** * Length of buffer for reading lines from the Assuan server. * * PHP reads 8192 bytes. If this is set to less than 8192, PHP reads 8192 * and buffers the rest so we might as well just read 8192. * * Using values other than 8192 also triggers PHP bugs. * * @see http://bugs.php.net/bug.php?id=35224 */ const CHUNK_SIZE = 8192; // }}} // {{{ protected properties /** * File handle for the input stream * * @var resource */ protected $stdin = null; /** * File handle for the output stream * * @var resource */ protected $stdout = null; /** * File handle for the log file if a log file is used * * @var resource */ protected $logFile = null; /** * Whether or not this pinentry is finished and is exiting * * @var boolean */ protected $moribund = false; /** * Verbosity level * * One of: * - {@link Crypt_GPG_PinEntry::VERBOSITY_NONE}, * - {@link Crypt_GPG_PinEntry::VERBOSITY_ERRORS}, or * - {@link Crypt_GPG_PinEntry::VERBOSITY_ALL} * * @var integer */ protected $verbosity = self::VERBOSITY_NONE; /** * The command-line interface parser for this pinentry * * @var Console_CommandLine * * @see Crypt_GPG_PinEntry::getParser() */ protected $parser = null; /** * PINs to be entered by this pinentry * * An indexed array of associative arrays in the form: * * $keyId, * 'passphrase' => $passphrase * ), * ... * ); * ?> * * * This array is parsed from the environment variable * PINENTRY_USER_DATA. * * @var array * * @see Crypt_GPG_PinEntry::initPinsFromENV() */ protected $pins = array(); /** * PINs that have been tried for the current PIN * * This is an associative array indexed by the key identifier with * values being the same as elements in the {@link Crypt_GPG_PinEntry::$pins} * array. * * @var array */ protected $triedPins = array(); /** * The PIN currently being requested by the Assuan server * * If set, this is an associative array in the form: * * $shortKeyId, * 'userId' => $userIdString * ); * ?> * * * @var array|null */ protected $currentPin = null; // }}} // {{{ __invoke() /** * Runs this pinentry * * @return void */ public function __invoke() { $this->parser = $this->getCommandLineParser(); try { $result = $this->parser->parse(); $this->setVerbosity($result->options['verbose']); $this->setLogFilename($result->options['log']); $this->connect(); $this->initPinsFromENV(); while (($line = fgets($this->stdin, self::CHUNK_SIZE)) !== false) { $this->parseCommand(mb_substr($line, 0, -1, '8bit')); if ($this->moribund) { break; } } $this->disconnect(); } catch (Console_CommandLineException $e) { $this->log($e->getMessage() . PHP_EOL, slf::VERBOSITY_ERRORS); exit(1); } catch (Exception $e) { $this->log($e->getMessage() . PHP_EOL, self::VERBOSITY_ERRORS); $this->log($e->getTraceAsString() . PHP_EOL, self::VERBOSITY_ERRORS); exit(1); } } // }}} // {{{ setVerbosity() /** * Sets the verbosity of logging for this pinentry * * Verbosity levels are: * * - {@link Crypt_GPG_PinEntry::VERBOSITY_NONE} - no logging. * - {@link Crypt_GPG_PinEntry::VERBOSITY_ERRORS} - log errors only. * - {@link Crypt_GPG_PinEntry::VERBOSITY_ALL} - log everything, including * the assuan protocol. * * @param integer $verbosity the level of verbosity of this pinentry. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ public function setVerbosity($verbosity) { $this->verbosity = (integer)$verbosity; return $this; } // }}} // {{{ setLogFilename() /** * Sets the log file location * * @param string $filename the new log filename to use. If an empty string * is used, file-based logging is disabled. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ public function setLogFilename($filename) { if (is_resource($this->logFile)) { fflush($this->logFile); fclose($this->logFile); $this->logFile = null; } if ($filename != '') { if (($this->logFile = fopen($filename, 'w')) === false) { $this->log( 'Unable to open log file "' . $filename . '" ' . 'for writing.' . PHP_EOL, self::VERBOSITY_ERRORS ); exit(1); } else { stream_set_write_buffer($this->logFile, 0); } } return $this; } // }}} // {{{ getUIXML() /** * Gets the CLI user-interface definition for this pinentry * * Detects whether or not this package is PEAR-installed and appropriately * locates the XML UI definition. * * @return string the location of the CLI user-interface definition XML. */ protected function getUIXML() { $dir = '@data-dir@' . DIRECTORY_SEPARATOR . '@package-name@' . DIRECTORY_SEPARATOR . 'data'; // Check if we're running from a PEAR-packaged version // or directly from a git checkout or other installation // that does not resolve PEAR variables if (strpos($dir, '@') !== false) { $dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'; // Workaround for composer installs (#20527) $composerDir = $dir . DIRECTORY_SEPARATOR . 'Crypt_GPG' . DIRECTORY_SEPARATOR . 'data'; if (is_dir($composerDir)) { $dir = $composerDir; } } return $dir . DIRECTORY_SEPARATOR . 'pinentry-cli.xml'; } // }}} // {{{ getCommandLineParser() /** * Gets the CLI parser for this pinentry * * @return Console_CommandLine the CLI parser for this pinentry. */ protected function getCommandLineParser() { return Console_CommandLine::fromXmlFile($this->getUIXML()); } // }}} // {{{ log() /** * Logs a message at the specified verbosity level * * If a log file is used, the message is written to the log. Otherwise, * the message is sent to STDERR. * * @param string $data the message to log. * @param integer $level the verbosity level above which the message should * be logged. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function log($data, $level) { if ($this->verbosity >= $level) { if (is_resource($this->logFile)) { fwrite($this->logFile, $data); fflush($this->logFile); } else { $this->parser->outputter->stderr($data); } } return $this; } // }}} // {{{ connect() /** * Connects this pinentry to the assuan server * * Opens I/O streams and sends initial handshake. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function connect() { // Binary operations will not work on Windows with PHP < 5.2.6. $rb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'r' : 'rb'; $wb = (version_compare(PHP_VERSION, '5.2.6') < 0) ? 'w' : 'wb'; $this->stdin = fopen('php://stdin', $rb); $this->stdout = fopen('php://stdout', $wb); if (function_exists('stream_set_read_buffer')) { stream_set_read_buffer($this->stdin, 0); } stream_set_write_buffer($this->stdout, 0); // initial handshake $this->send($this->getOK('Crypt_GPG pinentry ready and waiting')); return $this; } // }}} // {{{ parseCommand() /** * Parses an assuan command and performs the appropriate action * * Documentation of the assuan commands for pinentry is limited to * non-existent. Most of these commands were taken from the C source code * to gpg-agent and pinentry. * * Additional context was provided by using strace -f when calling the * gpg-agent. * * @param string $line the assuan command line to parse * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function parseCommand($line) { $this->log('<- ' . $line . PHP_EOL, self::VERBOSITY_ALL); $parts = explode(' ', $line, 2); $command = $parts[0]; if (count($parts) === 2) { $data = $parts[1]; } else { $data = null; } switch ($command) { case 'SETDESC': return $this->sendSetDescription($data); case 'SETPROMPT': case 'SETERROR': case 'SETOK': case 'SETNOTOK': case 'SETCANCEL': case 'SETQUALITYBAR': case 'SETQUALITYBAR_TT': case 'OPTION': return $this->sendNotImplementedOK(); case 'MESSAGE': return $this->sendMessage(); case 'CONFIRM': return $this->sendConfirm(); case 'GETINFO': return $this->sendGetInfo($data); case 'GETPIN': return $this->sendGetPin($data); case 'RESET': return $this->sendReset(); case 'BYE': return $this->sendBye(); } } // }}} // {{{ initPinsFromENV() /** * Initializes the PINs to be entered by this pinentry from the environment * variable PINENTRY_USER_DATA * * The PINs are parsed from a JSON-encoded string. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function initPinsFromENV() { if (($userData = getenv('PINENTRY_USER_DATA')) !== false) { $pins = json_decode($userData, true); if ($pins === null) { $this->log( '-- failed to parse user data' . PHP_EOL, self::VERBOSITY_ERRORS ); } else { $this->pins = $pins; $this->log( '-- got user data [not showing passphrases]' . PHP_EOL, self::VERBOSITY_ALL ); } } return $this; } // }}} // {{{ disconnect() /** * Disconnects this pinentry from the Assuan server * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function disconnect() { $this->log('-- disconnecting' . PHP_EOL, self::VERBOSITY_ALL); fflush($this->stdout); fclose($this->stdout); fclose($this->stdin); $this->stdin = null; $this->stdout = null; $this->log('-- disconnected' . PHP_EOL, self::VERBOSITY_ALL); if (is_resource($this->logFile)) { fflush($this->logFile); fclose($this->logFile); $this->logFile = null; } return $this; } // }}} // {{{ sendNotImplementedOK() /** * Sends an OK response for a not implemented feature * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendNotImplementedOK() { return $this->send($this->getOK()); } // }}} // {{{ sendSetDescription() /** * Parses the currently requested key identifier and user identifier from * the description passed to this pinentry * * @param string $text the raw description sent from gpg-agent. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendSetDescription($text) { $text = rawurldecode($text); $matches = array(); // TODO: handle user id with quotation marks $exp = '/\n"(.+)"\n.*\sID ([A-Z0-9]+),\n/mu'; if (preg_match($exp, $text, $matches) === 1) { $userId = $matches[1]; $keyId = $matches[2]; // only reset tried pins for new requested pin if ( $this->currentPin === null || $this->currentPin['keyId'] !== $keyId ) { $this->currentPin = array( 'userId' => $userId, 'keyId' => $keyId ); $this->triedPins = array(); $this->log( '-- looking for PIN for ' . $keyId . PHP_EOL, self::VERBOSITY_ALL ); } } return $this->send($this->getOK()); } // }}} // {{{ sendConfirm() /** * Tells the assuan server the PIN entry was confirmed (not cancelled) * by pressing the fake 'close' button * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendConfirm() { return $this->sendButtonInfo('close'); } // }}} // {{{ sendMessage() /** * Tells the assuan server that any requested pop-up messages were confirmed * by pressing the fake 'close' button * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendMessage() { return $this->sendButtonInfo('close'); } // }}} // {{{ sendButtonInfo() /** * Sends information about pressed buttons to the assuan server * * This is used to fake a user-interface for this pinentry. * * @param string $text the button status to send. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendButtonInfo($text) { return $this->send('BUTTON_INFO ' . $text . "\n"); } // }}} // {{{ sendGetPin() /** * Sends the PIN value for the currently requested key * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendGetPin() { $foundPin = ''; if (is_array($this->currentPin)) { $keyIdLength = mb_strlen($this->currentPin['keyId'], '8bit'); // search for the pin foreach ($this->pins as $pin) { // only check pins we haven't tried if (!isset($this->triedPins[$pin['keyId']])) { // get last X characters of key identifier to compare $keyId = mb_substr( $pin['keyId'], -$keyIdLength, mb_strlen($pin['keyId'], '8bit'), '8bit' ); if ($keyId === $this->currentPin['keyId']) { $foundPin = $pin['passphrase']; $this->triedPins[$pin['keyId']] = $pin; break; } } } } return $this ->send($this->getData($foundPin)) ->send($this->getOK()); } // }}} // {{{ sendGetInfo() /** * Sends information about this pinentry * * @param string $data the information requested by the assuan server. * Currently only 'pid' is supported. Other requests * return no information. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendGetInfo($data) { $parts = explode(' ', $data, 2); $command = reset($parts); switch ($command) { case 'pid': return $this->sendGetInfoPID(); default: return $this->send($this->getOK()); } return $this; } // }}} // {{{ sendGetInfoPID() /** * Sends the PID of this pinentry to the assuan server * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendGetInfoPID() { return $this ->send($this->getData(getmypid())) ->send($this->getOK()); } // }}} // {{{ sendBye() /** * Flags this pinentry for disconnection and sends an OK response * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendBye() { $return = $this->send($this->getOK('closing connection')); $this->moribund = true; return $return; } // }}} // {{{ sendReset() /** * Resets this pinentry and sends an OK response * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function sendReset() { $this->currentPin = null; $this->triedPins = array(); return $this->send($this->getOK()); } // }}} // {{{ getOK() /** * Gets an OK response to send to the assuan server * * @param string $data an optional message to include with the OK response. * * @return string the OK response. */ protected function getOK($data = null) { $return = 'OK'; if ($data) { $return .= ' ' . $data; } return $return . "\n"; } // }}} // {{{ getData() /** * Gets data ready to send to the assuan server * * Data is appropriately escaped and long lines are wrapped. * * @param string $data the data to send to the assuan server. * * @return string the properly escaped, formatted data. * * @see http://www.gnupg.org/documentation/manuals/assuan/Server-responses.html */ protected function getData($data) { // Escape data. Only %, \n and \r need to be escaped but other // values are allowed to be escaped. See // http://www.gnupg.org/documentation/manuals/assuan/Server-responses.html $data = rawurlencode($data); $data = $this->getWordWrappedData($data, 'D'); return $data; } // }}} // {{{ getComment() /** * Gets a comment ready to send to the assuan server * * @param string $data the comment to send to the assuan server. * * @return string the properly formatted comment. * * @see http://www.gnupg.org/documentation/manuals/assuan/Server-responses.html */ protected function getComment($data) { return $this->getWordWrappedData($data, '#'); } // }}} // {{{ getWordWrappedData() /** * Wraps strings at 1,000 bytes without splitting UTF-8 multibyte * characters * * Each line is prepended with the specified line prefix. Wrapped lines * are automatically appended with \ characters. * * Protocol strings are UTF-8 but maximum line length is 1,000 bytes. * mb_strcut() is used so we can limit line length by bytes * and not split characters across multiple lines. * * @param string $data the data to wrap. * @param string $prefix a single character to use as the line prefix. For * example, 'D' or '#'. * * @return string the word-wrapped, prefixed string. * * @see http://www.gnupg.org/documentation/manuals/assuan/Server-responses.html */ protected function getWordWrappedData($data, $prefix) { $lines = array(); do { if (mb_strlen($data, '8bit') > 997) { $line = $prefix . ' ' . mb_strcut($data, 0, 996, 'utf-8') . "\\\n"; $lines[] = $line; $lineLength = mb_strlen($line, '8bit') - 1; $dataLength = mb_substr($data, '8bit'); $data = mb_substr( $data, $lineLength, $dataLength - $lineLength, '8bit' ); } else { $lines[] = $prefix . ' ' . $data . "\n"; $data = ''; } } while ($data != ''); return implode('', $lines); } // }}} // {{{ send() /** * Sends raw data to the assuan server * * @param string $data the data to send. * * @return Crypt_GPG_PinEntry the current object, for fluent interface. */ protected function send($data) { $this->log('-> ' . $data, self::VERBOSITY_ALL); fwrite($this->stdout, $data); fflush($this->stdout); return $this; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/ProcessControl.php0000664000175000017500000001010412610161626017111 0ustar alecalec * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ // {{{ class Crypt_GPG_ProcessControl /** * A class for monitoring and terminating processes by PID * * This is used to safely terminate the gpg-agent for GnuPG 2.x. This class * is limited in its abilities and can only check if a PID is running and * send a PID SIGTERM. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class Crypt_GPG_ProcessControl { // {{{ protected properties /** * The PID (process identifier) being monitored * * @var integer */ protected $pid; // }}} // {{{ __construct() /** * Creates a new process controller from the given PID (process identifier) * * @param integer $pid the PID (process identifier). */ public function __construct($pid) { $this->pid = $pid; } // }}} // {{{ public function getPid() /** * Gets the PID (process identifier) being controlled * * @return integer the PID being controlled. */ public function getPid() { return $this->pid; } // }}} // {{{ isRunning() /** * Checks if the process is running * * Uses ps on UNIX-like systems and tasklist on * Windows. * * @return boolean true if the process is running, false if not. */ public function isRunning() { $running = false; if (PHP_OS === 'WINNT') { $command = 'tasklist /fo csv /nh /fi ' . escapeshellarg('PID eq ' . $this->pid); $result = exec($command); $parts = explode(',', $result); $running = (count($parts) > 1 && trim($parts[1], '"') == $this->pid); } else { $result = exec('ps -p ' . escapeshellarg($this->pid) . ' -o pid='); $running = (trim($result) == $this->pid); } return $running; } // }}} // {{{ terminate() /** * Ends the process gracefully * * The signal SIGTERM is sent to the process. The gpg-agent process will * end gracefully upon receiving the SIGTERM signal. Upon 3 consecutive * SIGTERM signals the gpg-agent will forcefully shut down. * * If the posix extension is available, posix_kill() * is used. Otherwise kill is used on UNIX-like systems and * taskkill is used in Windows. * * @return void */ public function terminate() { if (function_exists('posix_kill')) { posix_kill($this->pid, 15); } elseif (PHP_OS === 'WINNT') { exec('taskkill /PID ' . escapeshellarg($this->pid)); } else { exec('kill -15 ' . escapeshellarg($this->pid)); } } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/Signature.php0000664000175000017500000002757412610161626016116 0ustar alecalec * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * User id class definition */ require_once 'Crypt/GPG/UserId.php'; // {{{ class Crypt_GPG_Signature /** * A class for GPG signature information * * This class is used to store the results of the Crypt_GPG::verify() method. * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @see Crypt_GPG::verify() */ class Crypt_GPG_Signature { // {{{ class properties /** * A base64-encoded string containing a unique id for this signature if * this signature has been verified as ok * * This id is used to prevent replay attacks and is not present for all * types of signatures. * * @var string */ private $_id = ''; /** * The fingerprint of the key used to create the signature * * @var string */ private $_keyFingerprint = ''; /** * The id of the key used to create the signature * * @var string */ private $_keyId = ''; /** * The creation date of this signature * * This is a Unix timestamp. * * @var integer */ private $_creationDate = 0; /** * The expiration date of the signature * * This is a Unix timestamp. If this signature does not expire, this will * be zero. * * @var integer */ private $_expirationDate = 0; /** * The user id associated with this signature * * @var Crypt_GPG_UserId */ private $_userId = null; /** * Whether or not this signature is valid * * @var boolean */ private $_isValid = false; // }}} // {{{ __construct() /** * Creates a new signature * * Signatures can be initialized from an array of named values. Available * names are: * * - string id - the unique id of this signature. * - string fingerprint - the fingerprint of the key used to * create the signature. The fingerprint * should not contain formatting * characters. * - string keyId - the id of the key used to create the * the signature. * - integer creation - the date the signature was created. * This is a UNIX timestamp. * - integer expiration - the date the signature expired. This * is a UNIX timestamp. If the signature * does not expire, use 0. * - boolean valid - whether or not the signature is valid. * - string userId - the user id associated with the * signature. This may also be a * {@link Crypt_GPG_UserId} object. * * @param Crypt_GPG_Signature|array $signature optional. Either an existing * signature object, which is copied; or an array of initial values. */ public function __construct($signature = null) { // copy from object if ($signature instanceof Crypt_GPG_Signature) { $this->_id = $signature->_id; $this->_keyFingerprint = $signature->_keyFingerprint; $this->_keyId = $signature->_keyId; $this->_creationDate = $signature->_creationDate; $this->_expirationDate = $signature->_expirationDate; $this->_isValid = $signature->_isValid; if ($signature->_userId instanceof Crypt_GPG_UserId) { $this->_userId = clone $signature->_userId; } } // initialize from array if (is_array($signature)) { if (array_key_exists('id', $signature)) { $this->setId($signature['id']); } if (array_key_exists('fingerprint', $signature)) { $this->setKeyFingerprint($signature['fingerprint']); } if (array_key_exists('keyId', $signature)) { $this->setKeyId($signature['keyId']); } if (array_key_exists('creation', $signature)) { $this->setCreationDate($signature['creation']); } if (array_key_exists('expiration', $signature)) { $this->setExpirationDate($signature['expiration']); } if (array_key_exists('valid', $signature)) { $this->setValid($signature['valid']); } if (array_key_exists('userId', $signature)) { $userId = new Crypt_GPG_UserId($signature['userId']); $this->setUserId($userId); } } } // }}} // {{{ getId() /** * Gets the id of this signature * * @return string a base64-encoded string containing a unique id for this * signature. This id is used to prevent replay attacks and * is not present for all types of signatures. */ public function getId() { return $this->_id; } // }}} // {{{ getKeyFingerprint() /** * Gets the fingerprint of the key used to create this signature * * @return string the fingerprint of the key used to create this signature. */ public function getKeyFingerprint() { return $this->_keyFingerprint; } // }}} // {{{ getKeyId() /** * Gets the id of the key used to create this signature * * Whereas the fingerprint of the signing key may not always be available * (for example if the signature is bad), the id should always be * available. * * @return string the id of the key used to create this signature. */ public function getKeyId() { return $this->_keyId; } // }}} // {{{ getCreationDate() /** * Gets the creation date of this signature * * @return integer the creation date of this signature. This is a Unix * timestamp. */ public function getCreationDate() { return $this->_creationDate; } // }}} // {{{ getExpirationDate() /** * Gets the expiration date of the signature * * @return integer the expiration date of this signature. This is a Unix * timestamp. If this signature does not expire, this will * be zero. */ public function getExpirationDate() { return $this->_expirationDate; } // }}} // {{{ getUserId() /** * Gets the user id associated with this signature * * @return Crypt_GPG_UserId the user id associated with this signature. */ public function getUserId() { return $this->_userId; } // }}} // {{{ isValid() /** * Gets whether or no this signature is valid * * @return boolean true if this signature is valid and false if it is not. */ public function isValid() { return $this->_isValid; } // }}} // {{{ setId() /** * Sets the id of this signature * * @param string $id a base64-encoded string containing a unique id for * this signature. * * @return Crypt_GPG_Signature the current object, for fluent interface. * * @see Crypt_GPG_Signature::getId() */ public function setId($id) { $this->_id = strval($id); return $this; } // }}} // {{{ setKeyFingerprint() /** * Sets the key fingerprint of this signature * * @param string $fingerprint the key fingerprint of this signature. This * is the fingerprint of the primary key used to * create this signature. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setKeyFingerprint($fingerprint) { $this->_keyFingerprint = strval($fingerprint); return $this; } // }}} // {{{ setKeyId() /** * Sets the key id of this signature * * @param string $id the key id of this signature. This is the id of the * primary key used to create this signature. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setKeyId($id) { $this->_keyId = strval($id); return $this; } // }}} // {{{ setCreationDate() /** * Sets the creation date of this signature * * @param integer $creationDate the creation date of this signature. This * is a Unix timestamp. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setCreationDate($creationDate) { $this->_creationDate = intval($creationDate); return $this; } // }}} // {{{ setExpirationDate() /** * Sets the expiration date of this signature * * @param integer $expirationDate the expiration date of this signature. * This is a Unix timestamp. Specify zero if * this signature does not expire. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setExpirationDate($expirationDate) { $this->_expirationDate = intval($expirationDate); return $this; } // }}} // {{{ setUserId() /** * Sets the user id associated with this signature * * @param Crypt_GPG_UserId $userId the user id associated with this * signature. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setUserId(Crypt_GPG_UserId $userId) { $this->_userId = $userId; return $this; } // }}} // {{{ setValid() /** * Sets whether or not this signature is valid * * @param boolean $isValid true if this signature is valid and false if it * is not. * * @return Crypt_GPG_Signature the current object, for fluent interface. */ public function setValid($isValid) { $this->_isValid = ($isValid) ? true : false; return $this; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/SignatureCreationInfo.php0000664000175000017500000001200712610161626020400 0ustar alecalec * @copyright 2015 PEAR * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php * @link http://www.gnupg.org/ */ /** * Information about a recently created signature. * * @category Encryption * @package Crypt_GPG * @author Christian Weiske * @copyright 2015 PEAR * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php * @link http://www.gnupg.org/ */ class Crypt_GPG_SignatureCreationInfo { /** * One of the three signature types: * - {@link Crypt_GPG::SIGN_MODE_NORMAL} * - {@link Crypt_GPG::SIGN_MODE_CLEAR} * - {@link Crypt_GPG::SIGN_MODE_DETACHED} * * @var integer */ protected $mode; /** * Public Key algorithm * * @var integer */ protected $pkAlgorithm; /** * Algorithm to hash the data * * @see RFC 2440 / 9.4. Hash Algorithm * @var integer */ protected $hashAlgorithm; /** * OpenPGP signature class * * @var mixed */ protected $class; /** * Unix timestamp when the signature was created * * @var integer */ protected $timestamp; /** * Key fingerprint * * @var string */ protected $keyFingerprint; /** * If the line given to the constructor was valid * * @var boolean */ protected $valid; /** * Names for the hash algorithm IDs. * * Names taken from RFC 3156, without the leading "pgp-". * * @see RFC 2440 / 9.4. Hash Algorithm * @see RFC 3156 / 5. OpenPGP signed data * @var array */ protected static $hashAlgorithmNames = array( 1 => 'md5', 2 => 'sha1', 3 => 'ripemd160', 5 => 'md2', 6 => 'tiger192', 7 => 'haval-5-160', ); /** * Parse a SIG_CREATED line from gnupg * * @param string $sigCreatedLine Line beginning with "SIG_CREATED " */ public function __construct($sigCreatedLine = null) { if ($sigCreatedLine === null) { $this->valid = false; return; } $parts = explode(' ', $sigCreatedLine); if (count($parts) !== 7) { $this->valid = false; return; } list( $title, $mode, $pkAlgorithm, $hashAlgorithm, $class, $timestamp, $keyFingerprint ) = $parts; switch (strtoupper($mode[0])) { case 'D': $this->mode = Crypt_GPG::SIGN_MODE_DETACHED; break; case 'C': $this->mode = Crypt_GPG::SIGN_MODE_CLEAR; break; case 'S': $this->mode = Crypt_GPG::SIGN_MODE_NORMAL; break; } $this->pkAlgorithm = (int) $pkAlgorithm; $this->hashAlgorithm = (int) $hashAlgorithm; $this->class = $class; if (is_numeric($timestamp)) { $this->timestamp = (int) $timestamp; } else { $this->timestamp = strtotime($timestamp); } $this->keyFingerprint = $keyFingerprint; $this->valid = true; } /** * Get the signature type * - {@link Crypt_GPG::SIGN_MODE_NORMAL} * - {@link Crypt_GPG::SIGN_MODE_CLEAR} * - {@link Crypt_GPG::SIGN_MODE_DETACHED} * * @return integer */ public function getMode() { return $this->mode; } /** * Return the public key algorithm used. * * @return integer */ public function getPkAlgorithm() { return $this->pkAlgorithm; } /** * Return the hash algorithm used to hash the data to sign. * * @return integer */ public function getHashAlgorithm() { return $this->hashAlgorithm; } /** * Get a name for the used hashing algorithm. * * @return string|null */ public function getHashAlgorithmName() { if (!isset(self::$hashAlgorithmNames[$this->hashAlgorithm])) { return null; } return self::$hashAlgorithmNames[$this->hashAlgorithm]; } /** * Return the timestamp at which the signature was created * * @return integer */ public function getTimestamp() { return $this->timestamp; } /** * Return the key's fingerprint * * @return string */ public function getKeyFingerprint() { return $this->keyFingerprint; } /** * Tell if the fingerprint line given to the constructor was valid * * @return boolean */ public function isValid() { return $this->valid; } } ?> Crypt_GPG-1.4.0/Crypt/GPG/SubKey.php0000664000175000017500000004405212610161626015345 0ustar alecalec * @author Nathan Fredrickson * @copyright 2005-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ // {{{ class Crypt_GPG_SubKey /** * A class for GPG sub-key information * * This class is used to store the results of the {@link Crypt_GPG::getKeys()} * method. Sub-key objects are members of a {@link Crypt_GPG_Key} object. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @author Nathan Fredrickson * @copyright 2005-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @see Crypt_GPG::getKeys() * @see Crypt_GPG_Key::getSubKeys() */ class Crypt_GPG_SubKey { // {{{ algorithm class constants /** * RSA encryption algorithm. */ const ALGORITHM_RSA = 1; /** * Elgamal encryption algorithm (encryption only). */ const ALGORITHM_ELGAMAL_ENC = 16; /** * DSA encryption algorithm (sometimes called DH, sign only). */ const ALGORITHM_DSA = 17; /** * Elgamal encryption algorithm (signage and encryption - should not be * used). */ const ALGORITHM_ELGAMAL_ENC_SGN = 20; // }}} // {{{ usage class constants /** * Key can be used to encrypt */ const USAGE_ENCRYPT = 1; /** * Key can be used to sign */ const USAGE_SIGN = 2; /** * Key can be used to certify other keys */ const USAGE_CERTIFY = 4; /** * Key can be used for authentication */ const USAGE_AUTHENTICATION = 8; // }}} // {{{ class properties /** * The id of this sub-key * * @var string */ private $_id = ''; /** * The algorithm used to create this sub-key * * The value is one of the Crypt_GPG_SubKey::ALGORITHM_* constants. * * @var integer */ private $_algorithm = 0; /** * The fingerprint of this sub-key * * @var string */ private $_fingerprint = ''; /** * Length of this sub-key in bits * * @var integer */ private $_length = 0; /** * Date this sub-key was created * * This is a Unix timestamp. * * @var integer */ private $_creationDate = 0; /** * Date this sub-key expires * * This is a Unix timestamp. If this sub-key does not expire, this will be * zero. * * @var integer */ private $_expirationDate = 0; /** * Contains usage flags of this sub-key * * @var int */ private $_usage = 0; /** * Whether or not the private key for this sub-key exists in the keyring * * @var boolean */ private $_hasPrivate = false; /** * Whether or not this sub-key is revoked * * @var boolean */ private $_isRevoked = false; // }}} // {{{ __construct() /** * Creates a new sub-key object * * Sub-keys can be initialized from an array of named values. Available * names are: * * - string id - the key id of the sub-key. * - integer algorithm - the encryption algorithm of the * sub-key. * - string fingerprint - the fingerprint of the sub-key. The * fingerprint should not contain * formatting characters. * - integer length - the length of the sub-key in bits. * - integer creation - the date the sub-key was created. * This is a UNIX timestamp. * - integer expiration - the date the sub-key expires. This * is a UNIX timestamp. If the sub-key * does not expire, use 0. * - boolean canSign - whether or not the sub-key can be * used to sign data. * - boolean canEncrypt - whether or not the sub-key can be * used to encrypt data. * - integer usage - the sub-key usage flags * - boolean hasPrivate - whether or not the private key for * the sub-key exists in the keyring. * - boolean isRevoked - whether or not this sub-key is * revoked. * * @param Crypt_GPG_SubKey|string|array $key optional. Either an existing * sub-key object, which is copied; a sub-key string, which is * parsed; or an array of initial values. */ public function __construct($key = null) { // parse from string if (is_string($key)) { $key = self::parse($key); } // copy from object if ($key instanceof Crypt_GPG_SubKey) { $this->_id = $key->_id; $this->_algorithm = $key->_algorithm; $this->_fingerprint = $key->_fingerprint; $this->_length = $key->_length; $this->_creationDate = $key->_creationDate; $this->_expirationDate = $key->_expirationDate; $this->_usage = $key->_usage; $this->_hasPrivate = $key->_hasPrivate; $this->_isRevoked = $key->_isRevoked; } // initialize from array if (is_array($key)) { if (array_key_exists('id', $key)) { $this->setId($key['id']); } if (array_key_exists('algorithm', $key)) { $this->setAlgorithm($key['algorithm']); } if (array_key_exists('fingerprint', $key)) { $this->setFingerprint($key['fingerprint']); } if (array_key_exists('length', $key)) { $this->setLength($key['length']); } if (array_key_exists('creation', $key)) { $this->setCreationDate($key['creation']); } if (array_key_exists('expiration', $key)) { $this->setExpirationDate($key['expiration']); } if (array_key_exists('usage', $key)) { $this->setUsage($key['usage']); } if (array_key_exists('canSign', $key)) { $this->setCanSign($key['canSign']); } if (array_key_exists('canEncrypt', $key)) { $this->setCanEncrypt($key['canEncrypt']); } if (array_key_exists('hasPrivate', $key)) { $this->setHasPrivate($key['hasPrivate']); } if (array_key_exists('isRevoked', $key)) { $this->setRevoked($key['isRevoked']); } } } // }}} // {{{ getId() /** * Gets the id of this sub-key * * @return string the id of this sub-key. */ public function getId() { return $this->_id; } // }}} // {{{ getAlgorithm() /** * Gets the algorithm used by this sub-key * * The algorithm should be one of the Crypt_GPG_SubKey::ALGORITHM_* * constants. * * @return integer the algorithm used by this sub-key. */ public function getAlgorithm() { return $this->_algorithm; } // }}} // {{{ getCreationDate() /** * Gets the creation date of this sub-key * * This is a Unix timestamp. * * @return integer the creation date of this sub-key. */ public function getCreationDate() { return $this->_creationDate; } // }}} // {{{ getExpirationDate() /** * Gets the date this sub-key expires * * This is a Unix timestamp. If this sub-key does not expire, this will be * zero. * * @return integer the date this sub-key expires. */ public function getExpirationDate() { return $this->_expirationDate; } // }}} // {{{ getFingerprint() /** * Gets the fingerprint of this sub-key * * @return string the fingerprint of this sub-key. */ public function getFingerprint() { return $this->_fingerprint; } // }}} // {{{ getLength() /** * Gets the length of this sub-key in bits * * @return integer the length of this sub-key in bits. */ public function getLength() { return $this->_length; } // }}} // {{{ canSign() /** * Gets whether or not this sub-key can sign data * * @return boolean true if this sub-key can sign data and false if this * sub-key can not sign data. */ public function canSign() { return ($this->_usage & self::USAGE_SIGN) != 0; } // }}} // {{{ canEncrypt() /** * Gets whether or not this sub-key can encrypt data * * @return boolean true if this sub-key can encrypt data and false if this * sub-key can not encrypt data. */ public function canEncrypt() { return ($this->_usage & self::USAGE_ENCRYPT) != 0; } // }}} // {{{ usage() /** * Gets usage flags of this sub-key * * @return int Sum of usage flags */ public function usage() { return $this->_usage; } // }}} // {{{ hasPrivate() /** * Gets whether or not the private key for this sub-key exists in the * keyring * * @return boolean true the private key for this sub-key exists in the * keyring and false if it does not. */ public function hasPrivate() { return $this->_hasPrivate; } // }}} // {{{ isRevoked() /** * Gets whether or not this sub-key is revoked * * @return boolean true if this sub-key is revoked and false if it is not. */ public function isRevoked() { return $this->_isRevoked; } // }}} // {{{ setCreationDate() /** * Sets the creation date of this sub-key * * The creation date is a Unix timestamp. * * @param integer $creationDate the creation date of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCreationDate($creationDate) { $this->_creationDate = intval($creationDate); return $this; } // }}} // {{{ setExpirationDate() /** * Sets the expiration date of this sub-key * * The expiration date is a Unix timestamp. Specify zero if this sub-key * does not expire. * * @param integer $expirationDate the expiration date of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setExpirationDate($expirationDate) { $this->_expirationDate = intval($expirationDate); return $this; } // }}} // {{{ setId() /** * Sets the id of this sub-key * * @param string $id the id of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setId($id) { $this->_id = strval($id); return $this; } // }}} // {{{ setAlgorithm() /** * Sets the algorithm used by this sub-key * * @param integer $algorithm the algorithm used by this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setAlgorithm($algorithm) { $this->_algorithm = intval($algorithm); return $this; } // }}} // {{{ setFingerprint() /** * Sets the fingerprint of this sub-key * * @param string $fingerprint the fingerprint of this sub-key. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setFingerprint($fingerprint) { $this->_fingerprint = strval($fingerprint); return $this; } // }}} // {{{ setLength() /** * Sets the length of this sub-key in bits * * @param integer $length the length of this sub-key in bits. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setLength($length) { $this->_length = intval($length); return $this; } // }}} // {{{ setCanSign() /** * Sets whether or not this sub-key can sign data * * @param boolean $canSign true if this sub-key can sign data and false if * it can not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCanSign($canSign) { if ($canSign) { $this->_usage |= self::USAGE_SIGN; } else { $this->_usage &= ~self::USAGE_SIGN; } return $this; } // }}} // {{{ setCanEncrypt() /** * Sets whether or not this sub-key can encrypt data * * @param boolean $canEncrypt true if this sub-key can encrypt data and * false if it can not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setCanEncrypt($canEncrypt) { if ($canEncrypt) { $this->_usage |= self::USAGE_ENCRYPT; } else { $this->_usage &= ~self::USAGE_ENCRYPT; } return $this; } // }}} // {{{ setUsage() /** * Sets usage flags of the sub-key * * @param integer $usage Usage flags * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setUsage($usage) { $this->_usage = (int) $usage; return $this; } // }}} // {{{ setHasPrivate() /** * Sets whether of not the private key for this sub-key exists in the * keyring * * @param boolean $hasPrivate true if the private key for this sub-key * exists in the keyring and false if it does * not. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setHasPrivate($hasPrivate) { $this->_hasPrivate = ($hasPrivate) ? true : false; return $this; } // }}} // {{{ setRevoked() /** * Sets whether or not this sub-key is revoked * * @param boolean $isRevoked whether or not this sub-key is revoked. * * @return Crypt_GPG_SubKey the current object, for fluent interface. */ public function setRevoked($isRevoked) { $this->_isRevoked = ($isRevoked) ? true : false; return $this; } // }}} // {{{ parse() /** * Parses a sub-key object from a sub-key string * * See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for information * on how the sub-key string is parsed. * * @param string $string the string containing the sub-key. * * @return Crypt_GPG_SubKey the sub-key object parsed from the string. */ public static function parse($string) { $tokens = explode(':', $string); $subKey = new Crypt_GPG_SubKey(); $subKey->setId($tokens[4]); $subKey->setLength($tokens[2]); $subKey->setAlgorithm($tokens[3]); $subKey->setCreationDate(self::_parseDate($tokens[5])); $subKey->setExpirationDate(self::_parseDate($tokens[6])); if ($tokens[1] == 'r') { $subKey->setRevoked(true); } $usage = 0; $usage_map = array( 'a' => self::USAGE_AUTHENTICATION, 'c' => self::USAGE_CERTIFY, 'e' => self::USAGE_ENCRYPT, 's' => self::USAGE_SIGN, ); foreach ($usage_map as $key => $flag) { if (strpos($tokens[11], $key) !== false) { $usage |= $flag; } } $subKey->setUsage($usage); return $subKey; } // }}} // {{{ _parseDate() /** * Parses a date string as provided by GPG into a UNIX timestamp * * @param string $string the date string. * * @return integer the UNIX timestamp corresponding to the provided date * string. */ private static function _parseDate($string) { if ($string == '') { $timestamp = 0; } else { // all times are in UTC according to GPG documentation $timeZone = new DateTimeZone('UTC'); if (strpos($string, 'T') === false) { // interpret as UNIX timestamp $string = '@' . $string; } $date = new DateTime($string, $timeZone); // convert to UNIX timestamp $timestamp = intval($date->format('U')); } return $timestamp; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/UserId.php0000664000175000017500000002225512610161626015337 0ustar alecalec * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ // {{{ class Crypt_GPG_UserId /** * A class for GPG user id information * * This class is used to store the results of the {@link Crypt_GPG::getKeys()} * method. User id objects are members of a {@link Crypt_GPG_Key} object. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @see Crypt_GPG::getKeys() * @see Crypt_GPG_Key::getUserIds() */ class Crypt_GPG_UserId { // {{{ class properties /** * The name field of this user id * * @var string */ private $_name = ''; /** * The comment field of this user id * * @var string */ private $_comment = ''; /** * The email field of this user id * * @var string */ private $_email = ''; /** * Whether or not this user id is revoked * * @var boolean */ private $_isRevoked = false; /** * Whether or not this user id is valid * * @var boolean */ private $_isValid = true; // }}} // {{{ __construct() /** * Creates a new user id * * User ids can be initialized from an array of named values. Available * names are: * * - string name - the name field of the user id. * - string comment - the comment field of the user id. * - string email - the email field of the user id. * - boolean valid - whether or not the user id is valid. * - boolean revoked - whether or not the user id is revoked. * * @param Crypt_GPG_UserId|string|array $userId optional. Either an * existing user id object, which is copied; a user id string, which * is parsed; or an array of initial values. */ public function __construct($userId = null) { // parse from string if (is_string($userId)) { $userId = self::parse($userId); } // copy from object if ($userId instanceof Crypt_GPG_UserId) { $this->_name = $userId->_name; $this->_comment = $userId->_comment; $this->_email = $userId->_email; $this->_isRevoked = $userId->_isRevoked; $this->_isValid = $userId->_isValid; } // initialize from array if (is_array($userId)) { if (array_key_exists('name', $userId)) { $this->setName($userId['name']); } if (array_key_exists('comment', $userId)) { $this->setComment($userId['comment']); } if (array_key_exists('email', $userId)) { $this->setEmail($userId['email']); } if (array_key_exists('revoked', $userId)) { $this->setRevoked($userId['revoked']); } if (array_key_exists('valid', $userId)) { $this->setValid($userId['valid']); } } } // }}} // {{{ getName() /** * Gets the name field of this user id * * @return string the name field of this user id. */ public function getName() { return $this->_name; } // }}} // {{{ getComment() /** * Gets the comments field of this user id * * @return string the comments field of this user id. */ public function getComment() { return $this->_comment; } // }}} // {{{ getEmail() /** * Gets the email field of this user id * * @return string the email field of this user id. */ public function getEmail() { return $this->_email; } // }}} // {{{ isRevoked() /** * Gets whether or not this user id is revoked * * @return boolean true if this user id is revoked and false if it is not. */ public function isRevoked() { return $this->_isRevoked; } // }}} // {{{ isValid() /** * Gets whether or not this user id is valid * * @return boolean true if this user id is valid and false if it is not. */ public function isValid() { return $this->_isValid; } // }}} // {{{ __toString() /** * Gets a string representation of this user id * * The string is formatted as: * name (comment) . * * @return string a string representation of this user id. */ public function __toString() { $components = array(); if (strlen($this->_name) > 0) { $components[] = $this->_name; } if (strlen($this->_comment) > 0) { $components[] = '(' . $this->_comment . ')'; } if (strlen($this->_email) > 0) { $components[] = '<' . $this->_email. '>'; } return implode(' ', $components); } // }}} // {{{ setName() /** * Sets the name field of this user id * * @param string $name the name field of this user id. * * @return Crypt_GPG_UserId the current object, for fluent interface. */ public function setName($name) { $this->_name = strval($name); return $this; } // }}} // {{{ setComment() /** * Sets the comment field of this user id * * @param string $comment the comment field of this user id. * * @return Crypt_GPG_UserId the current object, for fluent interface. */ public function setComment($comment) { $this->_comment = strval($comment); return $this; } // }}} // {{{ setEmail() /** * Sets the email field of this user id * * @param string $email the email field of this user id. * * @return Crypt_GPG_UserId the current object, for fluent interface. */ public function setEmail($email) { $this->_email = strval($email); return $this; } // }}} // {{{ setRevoked() /** * Sets whether or not this user id is revoked * * @param boolean $isRevoked whether or not this user id is revoked. * * @return Crypt_GPG_UserId the current object, for fluent interface. */ public function setRevoked($isRevoked) { $this->_isRevoked = ($isRevoked) ? true : false; return $this; } // }}} // {{{ setValid() /** * Sets whether or not this user id is valid * * @param boolean $isValid whether or not this user id is valid. * * @return Crypt_GPG_UserId the current object, for fluent interface. */ public function setValid($isValid) { $this->_isValid = ($isValid) ? true : false; return $this; } // }}} // {{{ parse() /** * Parses a user id object from a user id string * * A user id string is of the form: * name (comment) with the comment * and email-address fields being optional. * * @param string $string the user id string to parse. * * @return Crypt_GPG_UserId the user id object parsed from the string. */ public static function parse($string) { $userId = new Crypt_GPG_UserId(); $email = ''; $comment = ''; // get email address from end of string if it exists $matches = array(); if (preg_match('/^(.+?) <([^>]+)>$/', $string, $matches) === 1) { $string = $matches[1]; $email = $matches[2]; } // get comment from end of string if it exists $matches = array(); if (preg_match('/^(.+?) \(([^\)]+)\)$/', $string, $matches) === 1) { $string = $matches[1]; $comment = $matches[2]; } $name = $string; $userId->setName($name); $userId->setComment($comment); $userId->setEmail($email); return $userId; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPG/VerifyStatusHandler.php0000664000175000017500000001503612610161626020111 0ustar alecalec * @copyright 2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ /** * Signature object class definition */ require_once 'Crypt/GPG/Signature.php'; /** * Status line handler for the verify operation * * This class is used internally by Crypt_GPG and does not need be used * directly. See the {@link Crypt_GPG} class for end-user API. * * This class is responsible for building signature objects that are returned * by the {@link Crypt_GPG::verify()} method. See doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on GPG's status output for the verify operation. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG_VerifyStatusHandler { // {{{ protected properties /** * The current signature id * * Ths signature id is emitted by GPG before the new signature line so we * must remember it temporarily. * * @var string */ protected $signatureId = ''; /** * List of parsed {@link Crypt_GPG_Signature} objects * * @var array */ protected $signatures = array(); /** * Array index of the current signature * * @var integer */ protected $index = -1; // }}} // {{{ handle() /** * Handles a status line * * @param string $line the status line to handle. * * @return void */ public function handle($line) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'GOODSIG': case 'EXPSIG': case 'EXPKEYSIG': case 'REVKEYSIG': case 'BADSIG': $signature = new Crypt_GPG_Signature(); // if there was a signature id, set it on the new signature if ($this->signatureId != '') { $signature->setId($this->signatureId); $this->signatureId = ''; } // Detect whether fingerprint or key id was returned and set // signature values appropriately. Key ids are strings of either // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 // hexadecimal characters. The key id is the last 16 characters of // the key fingerprint. if (strlen($tokens[1]) > 16) { $signature->setKeyFingerprint($tokens[1]); $signature->setKeyId(substr($tokens[1], -16)); } else { $signature->setKeyId($tokens[1]); } // get user id string $string = implode(' ', array_splice($tokens, 2)); $string = rawurldecode($string); $signature->setUserId(Crypt_GPG_UserId::parse($string)); $this->index++; $this->signatures[$this->index] = $signature; break; case 'ERRSIG': $signature = new Crypt_GPG_Signature(); // if there was a signature id, set it on the new signature if ($this->signatureId != '') { $signature->setId($this->signatureId); $this->signatureId = ''; } // Detect whether fingerprint or key id was returned and set // signature values appropriately. Key ids are strings of either // 16 or 8 hexadecimal characters. Fingerprints are strings of 40 // hexadecimal characters. The key id is the last 16 characters of // the key fingerprint. if (strlen($tokens[1]) > 16) { $signature->setKeyFingerprint($tokens[1]); $signature->setKeyId(substr($tokens[1], -16)); } else { $signature->setKeyId($tokens[1]); } $this->index++; $this->signatures[$this->index] = $signature; break; case 'VALIDSIG': if (!array_key_exists($this->index, $this->signatures)) { break; } $signature = $this->signatures[$this->index]; $signature->setValid(true); $signature->setKeyFingerprint($tokens[1]); if (strpos($tokens[3], 'T') === false) { $signature->setCreationDate($tokens[3]); } else { $signature->setCreationDate(strtotime($tokens[3])); } if (array_key_exists(4, $tokens)) { if (strpos($tokens[4], 'T') === false) { $signature->setExpirationDate($tokens[4]); } else { $signature->setExpirationDate(strtotime($tokens[4])); } } break; case 'SIG_ID': // note: signature id comes before new signature line and may not // exist for some signature types $this->signatureId = $tokens[1]; break; } } // }}} // {{{ getSignatures() /** * Gets the {@link Crypt_GPG_Signature} objects parsed by this handler * * @return array the signature objects parsed by this handler. */ public function getSignatures() { return $this->signatures; } // }}} } ?> Crypt_GPG-1.4.0/Crypt/GPG.php0000664000175000017500000025140512610161626014145 0ustar alecalec * addEncryptKey($mySecretKeyId); * $encryptedData = $gpg->encrypt($data); * ?> * * * PHP version 5 * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php * @link http://www.gnupg.org/ */ /** * Base class for GPG methods */ require_once 'Crypt/GPGAbstract.php'; /** * Signature handler class */ require_once 'Crypt/GPG/VerifyStatusHandler.php'; /** * Decryption handler class */ require_once 'Crypt/GPG/DecryptStatusHandler.php'; /** * Information about a created signature */ require_once 'Crypt/GPG/SignatureCreationInfo.php'; // {{{ class Crypt_GPG /** * A class to use GPG from PHP * * This class provides an object oriented interface to GNU Privacy Guard (GPG). * * Though GPG can support symmetric-key cryptography, this class is intended * only to facilitate public-key cryptography. * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ class Crypt_GPG extends Crypt_GPGAbstract { // {{{ class constants for data signing modes /** * Signing mode for normal signing of data. The signed message will not * be readable without special software. * * This is the default signing mode. * * @see Crypt_GPG::sign() * @see Crypt_GPG::signFile() */ const SIGN_MODE_NORMAL = 1; /** * Signing mode for clearsigning data. Clearsigned signatures are ASCII * armored data and are readable without special software. If the signed * message is unencrypted, the message will still be readable. The message * text will be in the original encoding. * * @see Crypt_GPG::sign() * @see Crypt_GPG::signFile() */ const SIGN_MODE_CLEAR = 2; /** * Signing mode for creating a detached signature. When using detached * signatures, only the signature data is returned. The original message * text may be distributed separately from the signature data. This is * useful for miltipart/signed email messages as per * {@link http://www.ietf.org/rfc/rfc3156.txt RFC 3156}. * * @see Crypt_GPG::sign() * @see Crypt_GPG::signFile() */ const SIGN_MODE_DETACHED = 3; // }}} // {{{ class constants for fingerprint formats /** * No formatting is performed. * * Example: C3BC615AD9C766E5A85C1F2716D27458B1BBA1C4 * * @see Crypt_GPG::getFingerprint() */ const FORMAT_NONE = 1; /** * Fingerprint is formatted in the format used by the GnuPG gpg command's * default output. * * Example: C3BC 615A D9C7 66E5 A85C 1F27 16D2 7458 B1BB A1C4 * * @see Crypt_GPG::getFingerprint() */ const FORMAT_CANONICAL = 2; /** * Fingerprint is formatted in the format used when displaying X.509 * certificates * * Example: C3:BC:61:5A:D9:C7:66:E5:A8:5C:1F:27:16:D2:74:58:B1:BB:A1:C4 * * @see Crypt_GPG::getFingerprint() */ const FORMAT_X509 = 3; // }}} // {{{ class constants for boolean options /** * Use to specify ASCII armored mode for returned data */ const ARMOR_ASCII = true; /** * Use to specify binary mode for returned data */ const ARMOR_BINARY = false; /** * Use to specify that line breaks in signed text should be normalized */ const TEXT_NORMALIZED = true; /** * Use to specify that line breaks in signed text should not be normalized */ const TEXT_RAW = false; // }}} // {{{ protected class properties /** * Engine used to control the GPG subprocess * * @var Crypt_GPG_Engine * * @see Crypt_GPG::setEngine() */ protected $engine = null; /** * Keys used to encrypt * * The array is of the form: * * array( * $key_id => array( * 'fingerprint' => $fingerprint, * 'passphrase' => null * ) * ); * * * @var array * @see Crypt_GPG::addEncryptKey() * @see Crypt_GPG::clearEncryptKeys() */ protected $encryptKeys = array(); /** * Keys used to decrypt * * The array is of the form: * * array( * $key_id => array( * 'fingerprint' => $fingerprint, * 'passphrase' => $passphrase * ) * ); * * * @var array * @see Crypt_GPG::addSignKey() * @see Crypt_GPG::clearSignKeys() */ protected $signKeys = array(); /** * Keys used to sign * * The array is of the form: * * array( * $key_id => array( * 'fingerprint' => $fingerprint, * 'passphrase' => $passphrase * ) * ); * * * @var array * @see Crypt_GPG::addDecryptKey() * @see Crypt_GPG::clearDecryptKeys() */ protected $decryptKeys = array(); /** * Information about the last signature that was generated. * A string (line) beginning with "SIG_CREATED " * * @see handleSignStatus() * @var string */ protected $lastSignatureInfo = null; // }}} // {{{ importKey() /** * Imports a public or private key into the keyring * * Keys may be removed from the keyring using * {@link Crypt_GPG::deletePublicKey()} or * {@link Crypt_GPG::deletePrivateKey()}. * * @param string $data the key data to be imported. * * @return array an associative array containing the following elements: * - fingerprint - the fingerprint of the * imported key, * - public_imported - the number of public * keys imported, * - public_unchanged - the number of unchanged * public keys, * - private_imported - the number of private * keys imported, * - private_unchanged - the number of unchanged * private keys. * * @throws Crypt_GPG_NoDataException if the key data is missing or if the * data is is not valid key data. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function importKey($data) { return $this->_importKey($data, false); } // }}} // {{{ importKeyFile() /** * Imports a public or private key file into the keyring * * Keys may be removed from the keyring using * {@link Crypt_GPG::deletePublicKey()} or * {@link Crypt_GPG::deletePrivateKey()}. * * @param string $filename the key file to be imported. * * @return array an associative array containing the following elements: * - fingerprint - the fingerprint of the * imported key, * - public_imported - the number of public * keys imported, * - public_unchanged - the number of unchanged * public keys, * - private_imported - the number of private * keys imported, * - private_unchanged - the number of unchanged * private keys. * private keys. * * @throws Crypt_GPG_NoDataException if the key data is missing or if the * data is is not valid key data. * * @throws Crypt_GPG_FileException if the key file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function importKeyFile($filename) { return $this->_importKey($filename, true); } // }}} // {{{ exportPublicKey() /** * Exports a public key from the keyring * * The exported key remains on the keyring. To delete the public key, use * {@link Crypt_GPG::deletePublicKey()}. * * If more than one key fingerprint is available for the specified * $keyId (for example, if you use a non-unique uid) only the * first public key is exported. * * @param string $keyId either the full uid of the public key, the email * part of the uid of the public key or the key id of * the public key. For example, * "Test User (example) ", * "test@example.com" or a hexadecimal string. * @param boolean $armor optional. If true, ASCII armored data is returned; * otherwise, binary data is returned. Defaults to * true. * * @return string the public key data. * * @throws Crypt_GPG_KeyNotFoundException if a public key with the given * $keyId is not found. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function exportPublicKey($keyId, $armor = true) { $fingerprint = $this->getFingerprint($keyId); if ($fingerprint === null) { throw new Crypt_GPG_KeyNotFoundException( 'Public key not found: ' . $keyId, self::ERROR_KEY_NOT_FOUND, $keyId ); } $keyData = ''; $operation = '--export ' . escapeshellarg($fingerprint); $arguments = ($armor) ? array('--armor') : array(); $this->engine->reset(); $this->engine->setOutput($keyData); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); if ($code !== self::ERROR_NONE) { throw new Crypt_GPG_Exception( 'Unknown error exporting public key. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } return $keyData; } // }}} // {{{ deletePublicKey() /** * Deletes a public key from the keyring * * If more than one key fingerprint is available for the specified * $keyId (for example, if you use a non-unique uid) only the * first public key is deleted. * * The private key must be deleted first or an exception will be thrown. * See {@link Crypt_GPG::deletePrivateKey()}. * * @param string $keyId either the full uid of the public key, the email * part of the uid of the public key or the key id of * the public key. For example, * "Test User (example) ", * "test@example.com" or a hexadecimal string. * * @return void * * @throws Crypt_GPG_KeyNotFoundException if a public key with the given * $keyId is not found. * * @throws Crypt_GPG_DeletePrivateKeyException if the specified public key * has an associated private key on the keyring. The private key * must be deleted first. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function deletePublicKey($keyId) { $fingerprint = $this->getFingerprint($keyId); if ($fingerprint === null) { throw new Crypt_GPG_KeyNotFoundException( 'Public key not found: ' . $keyId, self::ERROR_KEY_NOT_FOUND, $keyId ); } $operation = '--delete-key ' . escapeshellarg($fingerprint); $arguments = array( '--batch', '--yes' ); $this->engine->reset(); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; case self::ERROR_DELETE_PRIVATE_KEY: throw new Crypt_GPG_DeletePrivateKeyException( 'Private key must be deleted before public key can be ' . 'deleted.', $code, $keyId ); default: throw new Crypt_GPG_Exception( 'Unknown error deleting public key. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } } // }}} // {{{ deletePrivateKey() /** * Deletes a private key from the keyring * * If more than one key fingerprint is available for the specified * $keyId (for example, if you use a non-unique uid) only the * first private key is deleted. * * Calls GPG with the --delete-secret-key command. * * @param string $keyId either the full uid of the private key, the email * part of the uid of the private key or the key id of * the private key. For example, * "Test User (example) ", * "test@example.com" or a hexadecimal string. * * @return void * * @throws Crypt_GPG_KeyNotFoundException if a private key with the given * $keyId is not found. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function deletePrivateKey($keyId) { $fingerprint = $this->getFingerprint($keyId); if ($fingerprint === null) { throw new Crypt_GPG_KeyNotFoundException( 'Private key not found: ' . $keyId, self::ERROR_KEY_NOT_FOUND, $keyId ); } $operation = '--delete-secret-key ' . escapeshellarg($fingerprint); $arguments = array( '--batch', '--yes' ); $this->engine->reset(); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; case self::ERROR_KEY_NOT_FOUND: throw new Crypt_GPG_KeyNotFoundException( 'Private key not found: ' . $keyId, $code, $keyId ); default: throw new Crypt_GPG_Exception( 'Unknown error deleting private key. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } } // }}} // {{{ getKeys() /** * Gets the available keys in the keyring * * Calls GPG with the --list-keys command and grabs keys. See * the first section of doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG package} for a detailed * description of how the GPG command output is parsed. * * @param string $keyId optional. Only keys with that match the specified * pattern are returned. The pattern may be part of * a user id, a key id or a key fingerprint. If not * specified, all keys are returned. * * @return array an array of {@link Crypt_GPG_Key} objects. If no keys * match the specified $keyId an empty array is * returned. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Key */ public function getKeys($keyId = '') { return parent::_getKeys($keyId); } // }}} // {{{ getFingerprint() /** * Gets a key fingerprint from the keyring * * If more than one key fingerprint is available (for example, if you use * a non-unique user id) only the first key fingerprint is returned. * * Calls the GPG --list-keys command with the * --with-fingerprint option to retrieve a public key * fingerprint. * * @param string $keyId either the full user id of the key, the email * part of the user id of the key, or the key id of * the key. For example, * "Test User (example) ", * "test@example.com" or a hexadecimal string. * @param integer $format optional. How the fingerprint should be formatted. * Use {@link Crypt_GPG::FORMAT_X509} for X.509 * certificate format, * {@link Crypt_GPG::FORMAT_CANONICAL} for the format * used by GnuPG output and * {@link Crypt_GPG::FORMAT_NONE} for no formatting. * Defaults to Crypt_GPG::FORMAT_NONE. * * @return string the fingerprint of the key, or null if no fingerprint * is found for the given $keyId. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function getFingerprint($keyId, $format = self::FORMAT_NONE) { $output = ''; $operation = '--list-keys ' . escapeshellarg($keyId); $arguments = array( '--with-colons', '--with-fingerprint' ); $this->engine->reset(); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_KEY_NOT_FOUND: // ignore not found key errors break; default: throw new Crypt_GPG_Exception( 'Unknown error getting key fingerprint. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } $fingerprint = null; $lines = explode(PHP_EOL, $output); foreach ($lines as $line) { if (substr($line, 0, 3) == 'fpr') { $lineExp = explode(':', $line); $fingerprint = $lineExp[9]; switch ($format) { case self::FORMAT_CANONICAL: $fingerprintExp = str_split($fingerprint, 4); $format = '%s %s %s %s %s %s %s %s %s %s'; $fingerprint = vsprintf($format, $fingerprintExp); break; case self::FORMAT_X509: $fingerprintExp = str_split($fingerprint, 2); $fingerprint = implode(':', $fingerprintExp); break; } break; } } return $fingerprint; } // }}} // {{{ getLastSignatureInfo() /** * Get information about the last signature that was created. * * @return Crypt_GPG_SignatureCreationInfo */ public function getLastSignatureInfo() { if ($this->lastSignatureInfo === null) { return null; } return new Crypt_GPG_SignatureCreationInfo($this->lastSignatureInfo); } // }}} // {{{ encrypt() /** * Encrypts string data * * Data is ASCII armored by default but may optionally be returned as * binary. * * @param string $data the data to be encrypted. * @param boolean $armor optional. If true, ASCII armored data is returned; * otherwise, binary data is returned. Defaults to * true. * * @return string the encrypted data. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. * See {@link Crypt_GPG::addEncryptKey()}. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @sensitive $data */ public function encrypt($data, $armor = self::ARMOR_ASCII) { return $this->_encrypt($data, false, null, $armor); } // }}} // {{{ encryptFile() /** * Encrypts a file * * Encrypted data is ASCII armored by default but may optionally be saved * as binary. * * @param string $filename the filename of the file to encrypt. * @param string $encryptedFile optional. The filename of the file in * which to store the encrypted data. If null * or unspecified, the encrypted data is * returned as a string. * @param boolean $armor optional. If true, ASCII armored data is * returned; otherwise, binary data is * returned. Defaults to true. * * @return void|string if the $encryptedFile parameter is null, * a string containing the encrypted data is returned. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. * See {@link Crypt_GPG::addEncryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function encryptFile( $filename, $encryptedFile = null, $armor = self::ARMOR_ASCII ) { return $this->_encrypt($filename, true, $encryptedFile, $armor); } // }}} // {{{ encryptAndSign() /** * Encrypts and signs data * * Data is encrypted and signed in a single pass. * * NOTE: Until GnuPG version 1.4.10, it was not possible to verify * encrypted-signed data without decrypting it at the same time. If you try * to use {@link Crypt_GPG::verify()} method on encrypted-signed data with * earlier GnuPG versions, you will get an error. Please use * {@link Crypt_GPG::decryptAndVerify()} to verify encrypted-signed data. * * @param string $data the data to be encrypted and signed. * @param boolean $armor optional. If true, ASCII armored data is returned; * otherwise, binary data is returned. Defaults to * true. * * @return string the encrypted signed data. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified * or if no signing key is specified. See * {@link Crypt_GPG::addEncryptKey()} and * {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG::decryptAndVerify() */ public function encryptAndSign($data, $armor = self::ARMOR_ASCII) { return $this->_encryptAndSign($data, false, null, $armor); } // }}} // {{{ encryptAndSignFile() /** * Encrypts and signs a file * * The file is encrypted and signed in a single pass. * * NOTE: Until GnuPG version 1.4.10, it was not possible to verify * encrypted-signed files without decrypting them at the same time. If you * try to use {@link Crypt_GPG::verify()} method on encrypted-signed files * with earlier GnuPG versions, you will get an error. Please use * {@link Crypt_GPG::decryptAndVerifyFile()} to verify encrypted-signed * files. * * @param string $filename the name of the file containing the data to * be encrypted and signed. * @param string $signedFile optional. The name of the file in which the * encrypted, signed data should be stored. If * null or unspecified, the encrypted, signed * data is returned as a string. * @param boolean $armor optional. If true, ASCII armored data is * returned; otherwise, binary data is returned. * Defaults to true. * * @return void|string if the $signedFile parameter is null, a * string containing the encrypted, signed data is * returned. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified * or if no signing key is specified. See * {@link Crypt_GPG::addEncryptKey()} and * {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG::decryptAndVerifyFile() */ public function encryptAndSignFile( $filename, $signedFile = null, $armor = self::ARMOR_ASCII ) { return $this->_encryptAndSign($filename, true, $signedFile, $armor); } // }}} // {{{ decrypt() /** * Decrypts string data * * This method assumes the required private key is available in the keyring * and throws an exception if the private key is not available. To add a * private key to the keyring, use the {@link Crypt_GPG::importKey()} or * {@link Crypt_GPG::importKeyFile()} methods. * * @param string $encryptedData the data to be decrypted. * * @return string the decrypted data. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function decrypt($encryptedData) { return $this->_decrypt($encryptedData, false, null); } // }}} // {{{ decryptFile() /** * Decrypts a file * * This method assumes the required private key is available in the keyring * and throws an exception if the private key is not available. To add a * private key to the keyring, use the {@link Crypt_GPG::importKey()} or * {@link Crypt_GPG::importKeyFile()} methods. * * @param string $encryptedFile the name of the encrypted file data to * decrypt. * @param string $decryptedFile optional. The name of the file to which the * decrypted data should be written. If null * or unspecified, the decrypted data is * returned as a string. * * @return void|string if the $decryptedFile parameter is null, * a string containing the decrypted data is returned. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function decryptFile($encryptedFile, $decryptedFile = null) { return $this->_decrypt($encryptedFile, true, $decryptedFile); } // }}} // {{{ decryptAndVerify() /** * Decrypts and verifies string data * * This method assumes the required private key is available in the keyring * and throws an exception if the private key is not available. To add a * private key to the keyring, use the {@link Crypt_GPG::importKey()} or * {@link Crypt_GPG::importKeyFile()} methods. * * @param string $encryptedData the encrypted, signed data to be decrypted * and verified. * * @return array two element array. The array has an element 'data' * containing the decrypted data and an element * 'signatures' containing an array of * {@link Crypt_GPG_Signature} objects for the signed data. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function decryptAndVerify($encryptedData) { return $this->_decryptAndVerify($encryptedData, false, null); } // }}} // {{{ decryptAndVerifyFile() /** * Decrypts and verifies a signed, encrypted file * * This method assumes the required private key is available in the keyring * and throws an exception if the private key is not available. To add a * private key to the keyring, use the {@link Crypt_GPG::importKey()} or * {@link Crypt_GPG::importKeyFile()} methods. * * @param string $encryptedFile the name of the signed, encrypted file to * to decrypt and verify. * @param string $decryptedFile optional. The name of the file to which the * decrypted data should be written. If null * or unspecified, the decrypted data is * returned in the results array. * * @return array two element array. The array has an element 'data' * containing the decrypted data and an element * 'signatures' containing an array of * {@link Crypt_GPG_Signature} objects for the signed data. * If the decrypted data is written to a file, the 'data' * element is null. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function decryptAndVerifyFile($encryptedFile, $decryptedFile = null) { return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile); } // }}} // {{{ sign() /** * Signs data * * Data may be signed using any one of the three available signing modes: * - {@link Crypt_GPG::SIGN_MODE_NORMAL} * - {@link Crypt_GPG::SIGN_MODE_CLEAR} * - {@link Crypt_GPG::SIGN_MODE_DETACHED} * * @param string $data the data to be signed. * @param boolean $mode optional. The data signing mode to use. Should * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, * {@link Crypt_GPG::SIGN_MODE_CLEAR} or * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not * specified, defaults to * Crypt_GPG::SIGN_MODE_NORMAL. * @param boolean $armor optional. If true, ASCII armored data is * returned; otherwise, binary data is returned. * Defaults to true. This has no effect if the * mode Crypt_GPG::SIGN_MODE_CLEAR is * used. * @param boolean $textmode optional. If true, line-breaks in signed data * are normalized. Use this option when signing * e-mail, or for greater compatibility between * systems with different line-break formats. * Defaults to false. This has no effect if the * mode Crypt_GPG::SIGN_MODE_CLEAR is * used as clear-signing always uses textmode. * * @return string the signed data, or the signature data if a detached * signature is requested. * * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. * See {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function sign( $data, $mode = self::SIGN_MODE_NORMAL, $armor = self::ARMOR_ASCII, $textmode = self::TEXT_RAW ) { return $this->_sign($data, false, null, $mode, $armor, $textmode); } // }}} // {{{ signFile() /** * Signs a file * * The file may be signed using any one of the three available signing * modes: * - {@link Crypt_GPG::SIGN_MODE_NORMAL} * - {@link Crypt_GPG::SIGN_MODE_CLEAR} * - {@link Crypt_GPG::SIGN_MODE_DETACHED} * * @param string $filename the name of the file containing the data to * be signed. * @param string $signedFile optional. The name of the file in which the * signed data should be stored. If null or * unspecified, the signed data is returned as a * string. * @param boolean $mode optional. The data signing mode to use. Should * be one of {@link Crypt_GPG::SIGN_MODE_NORMAL}, * {@link Crypt_GPG::SIGN_MODE_CLEAR} or * {@link Crypt_GPG::SIGN_MODE_DETACHED}. If not * specified, defaults to * Crypt_GPG::SIGN_MODE_NORMAL. * @param boolean $armor optional. If true, ASCII armored data is * returned; otherwise, binary data is returned. * Defaults to true. This has no effect if the * mode Crypt_GPG::SIGN_MODE_CLEAR is * used. * @param boolean $textmode optional. If true, line-breaks in signed data * are normalized. Use this option when signing * e-mail, or for greater compatibility between * systems with different line-break formats. * Defaults to false. This has no effect if the * mode Crypt_GPG::SIGN_MODE_CLEAR is * used as clear-signing always uses textmode. * * @return void|string if the $signedFile parameter is null, a * string containing the signed data (or the signature * data if a detached signature is requested) is * returned. * * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. * See {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ public function signFile( $filename, $signedFile = null, $mode = self::SIGN_MODE_NORMAL, $armor = self::ARMOR_ASCII, $textmode = self::TEXT_RAW ) { return $this->_sign( $filename, true, $signedFile, $mode, $armor, $textmode ); } // }}} // {{{ verify() /** * Verifies signed data * * The {@link Crypt_GPG::decrypt()} method may be used to get the original * message if the signed data is not clearsigned and does not use a * detached signature. * * @param string $signedData the signed data to be verified. * @param string $signature optional. If verifying data signed using a * detached signature, this must be the detached * signature data. The data that was signed is * specified in $signedData. * * @return array an array of {@link Crypt_GPG_Signature} objects for the * signed data. For each signature that is valid, the * {@link Crypt_GPG_Signature::isValid()} will return true. * * @throws Crypt_GPG_NoDataException if the provided data is not signed * data. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Signature */ public function verify($signedData, $signature = '') { return $this->_verify($signedData, false, $signature); } // }}} // {{{ verifyFile() /** * Verifies a signed file * * The {@link Crypt_GPG::decryptFile()} method may be used to get the * original message if the signed data is not clearsigned and does not use * a detached signature. * * @param string $filename the signed file to be verified. * @param string $signature optional. If verifying a file signed using a * detached signature, this must be the detached * signature data. The file that was signed is * specified in $filename. * * @return array an array of {@link Crypt_GPG_Signature} objects for the * signed data. For each signature that is valid, the * {@link Crypt_GPG_Signature::isValid()} will return true. * * @throws Crypt_GPG_NoDataException if the provided data is not signed * data. * * @throws Crypt_GPG_FileException if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Signature */ public function verifyFile($filename, $signature = '') { return $this->_verify($filename, true, $signature); } // }}} // {{{ addDecryptKey() /** * Adds a key to use for decryption * * @param mixed $key the key to use. This may be a key identifier, * user id, fingerprint, {@link Crypt_GPG_Key} or * {@link Crypt_GPG_SubKey}. The key must be able * to encrypt. * @param string $passphrase optional. The passphrase of the key required * for decryption. * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::decrypt() * @see Crypt_GPG::decryptFile() * @see Crypt_GPG::clearDecryptKeys() * @see Crypt_GPG::_addKey() * @see Crypt_GPG_DecryptStatusHandler * * @sensitive $passphrase */ public function addDecryptKey($key, $passphrase = null) { $this->_addKey($this->decryptKeys, true, false, $key, $passphrase); return $this; } // }}} // {{{ addEncryptKey() /** * Adds a key to use for encryption * * @param mixed $key the key to use. This may be a key identifier, user id * user id, fingerprint, {@link Crypt_GPG_Key} or * {@link Crypt_GPG_SubKey}. The key must be able to * encrypt. * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::encrypt() * @see Crypt_GPG::encryptFile() * @see Crypt_GPG::clearEncryptKeys() * @see Crypt_GPG::_addKey() */ public function addEncryptKey($key) { $this->_addKey($this->encryptKeys, true, false, $key); return $this; } // }}} // {{{ addSignKey() /** * Adds a key to use for signing * * @param mixed $key the key to use. This may be a key identifier, * user id, fingerprint, {@link Crypt_GPG_Key} or * {@link Crypt_GPG_SubKey}. The key must be able * to sign. * @param string $passphrase optional. The passphrase of the key required * for signing. * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::sign() * @see Crypt_GPG::signFile() * @see Crypt_GPG::clearSignKeys() * @see Crypt_GPG::handleSignStatus() * @see Crypt_GPG::_addKey() * * @sensitive $passphrase */ public function addSignKey($key, $passphrase = null) { $this->_addKey($this->signKeys, false, true, $key, $passphrase); return $this; } // }}} // {{{ clearDecryptKeys() /** * Clears all decryption keys * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::decrypt() * @see Crypt_GPG::addDecryptKey() */ public function clearDecryptKeys() { $this->decryptKeys = array(); return $this; } // }}} // {{{ clearEncryptKeys() /** * Clears all encryption keys * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::encrypt() * @see Crypt_GPG::addEncryptKey() */ public function clearEncryptKeys() { $this->encryptKeys = array(); return $this; } // }}} // {{{ clearSignKeys() /** * Clears all signing keys * * @return Crypt_GPG the current object, for fluent interface. * * @see Crypt_GPG::sign() * @see Crypt_GPG::addSignKey() */ public function clearSignKeys() { $this->signKeys = array(); return $this; } // }}} // {{{ handleSignStatus() /** * Handles the status output from GPG for the sign operation * * This method is responsible for sending the passphrase commands when * required by the {@link Crypt_GPG::sign()} method. See doc/DETAILS * in the {@link http://www.gnupg.org/download/ GPG distribution} for * detailed information on GPG's status output. * * @param string $line the status line to handle. * * @return void * * @see Crypt_GPG::sign() */ public function handleSignStatus($line) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'NEED_PASSPHRASE': $subKeyId = $tokens[1]; if (array_key_exists($subKeyId, $this->signKeys)) { $passphrase = $this->signKeys[$subKeyId]['passphrase']; $this->engine->sendCommand($passphrase); } else { $this->engine->sendCommand(''); } break; case 'SIG_CREATED': $this->lastSignatureInfo = $line; break; } } // }}} // {{{ handleImportKeyStatus() /** * Handles the status output from GPG for the import operation * * This method is responsible for building the result array that is * returned from the {@link Crypt_GPG::importKey()} method. See * doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG distribution} for detailed * information on GPG's status output. * * @param string $line the status line to handle. * @param array &$result the current result array being processed. * * @return void * * @see Crypt_GPG::importKey() * @see Crypt_GPG::importKeyFile() * @see Crypt_GPG_Engine::addStatusHandler() */ public function handleImportKeyStatus($line, array &$result) { $tokens = explode(' ', $line); switch ($tokens[0]) { case 'IMPORT_OK': $result['fingerprint'] = $tokens[2]; if (empty($result['fingerprints'])) { $result['fingerprints'] = array($tokens[2]); } else if (!in_array($tokens[2], $result['fingerprints'])) { $result['fingerprints'][] = $tokens[2]; } break; case 'IMPORT_RES': $result['public_imported'] = intval($tokens[3]); $result['public_unchanged'] = intval($tokens[5]); $result['private_imported'] = intval($tokens[11]); $result['private_unchanged'] = intval($tokens[12]); break; } } // }}} /** * Tell if there are encryption keys registered * * @return boolean True if the data shall be encrypted */ public function hasEncryptKeys() { return count($this->encryptKeys) > 0; } /** * Tell if there are signing keys registered * * @return boolean True if the data shall be signed */ public function hasSignKeys() { return count($this->signKeys) > 0; } // {{{ _addKey() /** * Adds a key to one of the internal key arrays * * This handles resolving full key objects from the provided * $key value. * * @param array &$array the array to which the key should be added. * @param boolean $encrypt whether or not the key must be able to * encrypt. * @param boolean $sign whether or not the key must be able to sign. * @param mixed $key the key to add. This may be a key identifier, * user id, fingerprint, {@link Crypt_GPG_Key} or * {@link Crypt_GPG_SubKey}. * @param string $passphrase optional. The passphrase associated with the * key. * * @return void * * @sensitive $passphrase */ protected function _addKey(array &$array, $encrypt, $sign, $key, $passphrase = null ) { $subKeys = array(); if (is_scalar($key)) { $keys = $this->getKeys($key); if (count($keys) == 0) { throw new Crypt_GPG_KeyNotFoundException( 'Key "' . $key . '" not found.', 0, $key ); } $key = $keys[0]; } if ($key instanceof Crypt_GPG_Key) { if ($encrypt && !$key->canEncrypt()) { throw new InvalidArgumentException( 'Key "' . $key . '" cannot encrypt.' ); } if ($sign && !$key->canSign()) { throw new InvalidArgumentException( 'Key "' . $key . '" cannot sign.' ); } foreach ($key->getSubKeys() as $subKey) { $canEncrypt = $subKey->canEncrypt(); $canSign = $subKey->canSign(); if ( ($encrypt && $sign && $canEncrypt && $canSign) || ($encrypt && !$sign && $canEncrypt) || (!$encrypt && $sign && $canSign) ) { // We add all subkeys that meet the requirements because we // were not told which subkey is required. $subKeys[] = $subKey; } } } elseif ($key instanceof Crypt_GPG_SubKey) { $subKeys[] = $key; } if (count($subKeys) === 0) { throw new InvalidArgumentException( 'Key "' . $key . '" is not in a recognized format.' ); } foreach ($subKeys as $subKey) { if ($encrypt && !$subKey->canEncrypt()) { throw new InvalidArgumentException( 'Key "' . $key . '" cannot encrypt.' ); } if ($sign && !$subKey->canSign()) { throw new InvalidArgumentException( 'Key "' . $key . '" cannot sign.' ); } $array[$subKey->getId()] = array( 'fingerprint' => $subKey->getFingerprint(), 'passphrase' => $passphrase ); } } // }}} // {{{ _setPinEntryEnv() /** * Sets the PINENTRY_USER_DATA environment variable with the currently * added keys and passphrases * * Keys and pasphrases are stored as an indexed array of associative * arrays that is JSON encoded to a flat string. * * For GnuPG 2.x this is how passphrases are passed. For GnuPG 1.x the * environment variable is set but not used. * * @param array $keys the internal key array to use. * * @return void */ protected function _setPinEntryEnv(array $keys) { $envKeys = array(); foreach ($keys as $id => $key) { $envKeys[] = array( 'keyId' => $id, 'fingerprint' => $key['fingerprint'], 'passphrase' => $key['passphrase'] ); } $envKeys = json_encode($envKeys); $_ENV['PINENTRY_USER_DATA'] = $envKeys; } // }}} // {{{ _importKey() /** * Imports a public or private key into the keyring * * @param string $key the key to be imported. * @param boolean $isFile whether or not the input is a filename. * * @return array an associative array containing the following elements: * - fingerprint - the fingerprint of the * imported key, * - public_imported - the number of public * keys imported, * - public_unchanged - the number of unchanged * public keys, * - private_imported - the number of private * keys imported, * - private_unchanged - the number of unchanged * private keys. * * @throws Crypt_GPG_NoDataException if the key data is missing or if the * data is is not valid key data. * * @throws Crypt_GPG_FileException if the key file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ protected function _importKey($key, $isFile) { $result = array(); if ($isFile) { $input = @fopen($key, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open key file "' . $key . '" for importing.', 0, $key ); } } else { $input = strval($key); if ($input == '') { throw new Crypt_GPG_NoDataException( 'No valid GPG key data found.', self::ERROR_NO_DATA ); } } $arguments = array(); $version = $this->engine->getVersion(); if ( version_compare($version, '1.0.5', 'ge') && version_compare($version, '1.0.7', 'lt') ) { $arguments[] = '--allow-secret-key-import'; } $this->engine->reset(); $this->engine->addStatusHandler( array($this, 'handleImportKeyStatus'), array(&$result) ); $this->engine->setOperation('--import', $arguments); $this->engine->setInput($input); $this->engine->run(); if ($isFile) { fclose($input); } $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_DUPLICATE_KEY: case self::ERROR_NONE: // ignore duplicate key import errors break; case self::ERROR_NO_DATA: throw new Crypt_GPG_NoDataException( 'No valid GPG key data found.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error importing GPG key. Please use the \'debug\' ' . 'option when creating the Crypt_GPG object, and file a bug ' . 'report at ' . self::BUG_URI, $code ); } return $result; } // }}} // {{{ _encrypt() /** * Encrypts data * * @param string $data the data to encrypt. * @param boolean $isFile whether or not the data is a filename. * @param string $outputFile the filename of the file in which to store * the encrypted data. If null, the encrypted * data is returned as a string. * @param boolean $armor if true, ASCII armored data is returned; * otherwise, binary data is returned. * * @return void|string if the $outputFile parameter is null, a * string containing the encrypted data is returned. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified. * See {@link Crypt_GPG::addEncryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ protected function _encrypt($data, $isFile, $outputFile, $armor) { if (!$this->hasEncryptKeys()) { throw new Crypt_GPG_KeyNotFoundException( 'No encryption keys specified.' ); } if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for encryption.', 0, $data ); } } else { $input = strval($data); } if ($outputFile === null) { $output = ''; } else { $output = @fopen($outputFile, 'wb'); if ($output === false) { if ($isFile) { fclose($input); } throw new Crypt_GPG_FileException( 'Could not open output file "' . $outputFile . '" for storing encrypted data.', 0, $outputFile ); } } $arguments = ($armor) ? array('--armor') : array(); foreach ($this->encryptKeys as $key) { $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); } $this->engine->reset(); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->setOperation('--encrypt', $arguments); $this->engine->run(); if ($isFile) { fclose($input); } if ($outputFile !== null) { fclose($output); } $code = $this->engine->getErrorCode(); if ($code !== self::ERROR_NONE) { throw new Crypt_GPG_Exception( 'Unknown error encrypting data. Please use the \'debug\' ' . 'option when creating the Crypt_GPG object, and file a bug ' . 'report at ' . self::BUG_URI, $code ); } if ($outputFile === null) { return $output; } } // }}} // {{{ _decrypt() /** * Decrypts data * * @param string $data the data to be decrypted. * @param boolean $isFile whether or not the data is a filename. * @param string $outputFile the name of the file to which the decrypted * data should be written. If null, the decrypted * data is returned as a string. * * @return void|string if the $outputFile parameter is null, a * string containing the decrypted data is returned. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ protected function _decrypt($data, $isFile, $outputFile) { if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for decryption.', 0, $data ); } } else { $input = strval($data); if ($input == '') { throw new Crypt_GPG_NoDataException( 'Cannot decrypt data. No PGP encrypted data was found in '. 'the provided data.', self::ERROR_NO_DATA ); } } if ($outputFile === null) { $output = ''; } else { $output = @fopen($outputFile, 'wb'); if ($output === false) { if ($isFile) { fclose($input); } throw new Crypt_GPG_FileException( 'Could not open output file "' . $outputFile . '" for storing decrypted data.', 0, $outputFile ); } } $handler = new Crypt_GPG_DecryptStatusHandler( $this->engine, $this->decryptKeys ); // If using gpg-agent, set the decrypt pins used by the pinentry $this->_setPinEntryEnv($this->decryptKeys); $this->engine->reset(); $this->engine->addStatusHandler(array($handler, 'handle')); $this->engine->setOperation('--decrypt'); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->run(); if ($isFile) { fclose($input); } if ($outputFile !== null) { fclose($output); } // if there was any problem decrypting the data, the handler will // deal with it here. $handler->throwException(); if ($outputFile === null) { return $output; } } // }}} // {{{ _sign() /** * Signs data * * @param string $data the data to be signed. * @param boolean $isFile whether or not the data is a filename. * @param string $outputFile the name of the file in which the signed data * should be stored. If null, the signed data is * returned as a string. * @param boolean $mode the data signing mode to use. Should be one of * {@link Crypt_GPG::SIGN_MODE_NORMAL}, * {@link Crypt_GPG::SIGN_MODE_CLEAR} or * {@link Crypt_GPG::SIGN_MODE_DETACHED}. * @param boolean $armor if true, ASCII armored data is returned; * otherwise, binary data is returned. This has * no effect if the mode * Crypt_GPG::SIGN_MODE_CLEAR is * used. * @param boolean $textmode if true, line-breaks in signed data be * normalized. Use this option when signing * e-mail, or for greater compatibility between * systems with different line-break formats. * Defaults to false. This has no effect if the * mode Crypt_GPG::SIGN_MODE_CLEAR is * used as clear-signing always uses textmode. * * @return void|string if the $outputFile parameter is null, a * string containing the signed data (or the signature * data if a detached signature is requested) is * returned. * * @throws Crypt_GPG_KeyNotFoundException if no signing key is specified. * See {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ protected function _sign($data, $isFile, $outputFile, $mode, $armor, $textmode ) { $this->lastSignatureInfo = null; if (!$this->hasSignKeys()) { throw new Crypt_GPG_KeyNotFoundException( 'No signing keys specified.' ); } if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for signing.', 0, $data ); } } else { $input = strval($data); } if ($outputFile === null) { $output = ''; } else { $output = @fopen($outputFile, 'wb'); if ($output === false) { if ($isFile) { fclose($input); } throw new Crypt_GPG_FileException( 'Could not open output file "' . $outputFile . '" for storing signed data.', 0, $outputFile ); } } switch ($mode) { case self::SIGN_MODE_DETACHED: $operation = '--detach-sign'; break; case self::SIGN_MODE_CLEAR: $operation = '--clearsign'; break; case self::SIGN_MODE_NORMAL: default: $operation = '--sign'; break; } $arguments = array(); if ($armor) { $arguments[] = '--armor'; } if ($textmode) { $arguments[] = '--textmode'; } foreach ($this->signKeys as $key) { $arguments[] = '--local-user ' . escapeshellarg($key['fingerprint']); } // If using gpg-agent, set the sign pins used by the pinentry $this->_setPinEntryEnv($this->signKeys); $this->engine->reset(); $this->engine->addStatusHandler(array($this, 'handleSignStatus')); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); if ($isFile) { fclose($input); } if ($outputFile !== null) { fclose($output); } $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; case self::ERROR_KEY_NOT_FOUND: throw new Crypt_GPG_KeyNotFoundException( 'Cannot sign data. Private key not found. Import the '. 'private key before trying to sign data.', $code, $this->engine->getErrorKeyId() ); case self::ERROR_BAD_PASSPHRASE: throw new Crypt_GPG_BadPassphraseException( 'Cannot sign data. Incorrect passphrase provided.', $code ); case self::ERROR_MISSING_PASSPHRASE: throw new Crypt_GPG_BadPassphraseException( 'Cannot sign data. No passphrase provided.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error signing data. Please use the \'debug\' option ' . 'when creating the Crypt_GPG object, and file a bug report ' . 'at ' . self::BUG_URI, $code ); } if ($outputFile === null) { return $output; } } // }}} // {{{ _encryptAndSign() /** * Encrypts and signs data * * @param string $data the data to be encrypted and signed. * @param boolean $isFile whether or not the data is a filename. * @param string $outputFile the name of the file in which the encrypted, * signed data should be stored. If null, the * encrypted, signed data is returned as a * string. * @param boolean $armor if true, ASCII armored data is returned; * otherwise, binary data is returned. * * @return void|string if the $outputFile parameter is null, a * string containing the encrypted, signed data is * returned. * * @throws Crypt_GPG_KeyNotFoundException if no encryption key is specified * or if no signing key is specified. See * {@link Crypt_GPG::addEncryptKey()} and * {@link Crypt_GPG::addSignKey()}. * * @throws Crypt_GPG_BadPassphraseException if a specified passphrase is * incorrect or if a required passphrase is not specified. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. */ protected function _encryptAndSign($data, $isFile, $outputFile, $armor) { if (!$this->hasSignKeys()) { throw new Crypt_GPG_KeyNotFoundException( 'No signing keys specified.' ); } if (!$this->hasEncryptKeys()) { throw new Crypt_GPG_KeyNotFoundException( 'No encryption keys specified.' ); } if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for encrypting and signing.', 0, $data ); } } else { $input = strval($data); } if ($outputFile === null) { $output = ''; } else { $output = @fopen($outputFile, 'wb'); if ($output === false) { if ($isFile) { fclose($input); } throw new Crypt_GPG_FileException( 'Could not open output file "' . $outputFile . '" for storing encrypted, signed data.', 0, $outputFile ); } } $arguments = ($armor) ? array('--armor') : array(); foreach ($this->signKeys as $key) { $arguments[] = '--local-user ' . escapeshellarg($key['fingerprint']); } // If using gpg-agent, set the sign pins used by the pinentry $this->_setPinEntryEnv($this->signKeys); foreach ($this->encryptKeys as $key) { $arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']); } $this->engine->reset(); $this->engine->addStatusHandler(array($this, 'handleSignStatus')); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->setOperation('--encrypt --sign', $arguments); $this->engine->run(); if ($isFile) { fclose($input); } if ($outputFile !== null) { fclose($output); } $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: break; case self::ERROR_KEY_NOT_FOUND: throw new Crypt_GPG_KeyNotFoundException( 'Cannot sign encrypted data. Private key not found. Import '. 'the private key before trying to sign the encrypted data.', $code, $this->engine->getErrorKeyId() ); case self::ERROR_BAD_PASSPHRASE: throw new Crypt_GPG_BadPassphraseException( 'Cannot sign encrypted data. Incorrect passphrase provided.', $code ); case self::ERROR_MISSING_PASSPHRASE: throw new Crypt_GPG_BadPassphraseException( 'Cannot sign encrypted data. No passphrase provided.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error encrypting and signing data. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } if ($outputFile === null) { return $output; } } // }}} // {{{ _verify() /** * Verifies data * * @param string $data the signed data to be verified. * @param boolean $isFile whether or not the data is a filename. * @param string $signature if verifying a file signed using a detached * signature, this must be the detached signature * data. Otherwise, specify ''. * * @return array an array of {@link Crypt_GPG_Signature} objects for the * signed data. * * @throws Crypt_GPG_NoDataException if the provided data is not signed * data. * * @throws Crypt_GPG_FileException if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Signature */ protected function _verify($data, $isFile, $signature) { if ($signature == '') { $operation = '--verify'; $arguments = array(); } else { // Signed data goes in FD_MESSAGE, detached signature data goes in // FD_INPUT. $operation = '--verify - "-&' . Crypt_GPG_Engine::FD_MESSAGE. '"'; $arguments = array('--enable-special-filenames'); } $handler = new Crypt_GPG_VerifyStatusHandler(); if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for verifying.', 0, $data ); } } else { $input = strval($data); if ($input == '') { throw new Crypt_GPG_NoDataException( 'No valid signature data found.', self::ERROR_NO_DATA ); } } $this->engine->reset(); $this->engine->addStatusHandler(array($handler, 'handle')); if ($signature == '') { // signed or clearsigned data $this->engine->setInput($input); } else { // detached signature $this->engine->setInput($signature); $this->engine->setMessage($input); } $this->engine->setOperation($operation, $arguments); $this->engine->run(); if ($isFile) { fclose($input); } $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_BAD_SIGNATURE: break; case self::ERROR_NO_DATA: throw new Crypt_GPG_NoDataException( 'No valid signature data found.', $code ); case self::ERROR_KEY_NOT_FOUND: throw new Crypt_GPG_KeyNotFoundException( 'Public key required for data verification not in keyring.', $code, $this->engine->getErrorKeyId() ); default: throw new Crypt_GPG_Exception( 'Unknown error validating signature details. Please use the ' . '\'debug\' option when creating the Crypt_GPG object, and ' . 'file a bug report at ' . self::BUG_URI, $code ); } return $handler->getSignatures(); } // }}} // {{{ _decryptAndVerify() /** * Decrypts and verifies encrypted, signed data * * @param string $data the encrypted signed data to be decrypted and * verified. * @param boolean $isFile whether or not the data is a filename. * @param string $outputFile the name of the file to which the decrypted * data should be written. If null, the decrypted * data is returned in the results array. * * @return array two element array. The array has an element 'data' * containing the decrypted data and an element * 'signatures' containing an array of * {@link Crypt_GPG_Signature} objects for the signed data. * If the decrypted data is written to a file, the 'data' * element is null. * * @throws Crypt_GPG_KeyNotFoundException if the private key needed to * decrypt the data is not in the user's keyring or it the public * key needed for verification is not in the user's keyring. * * @throws Crypt_GPG_NoDataException if specified data does not contain * GPG signed, encrypted data. * * @throws Crypt_GPG_BadPassphraseException if a required passphrase is * incorrect or if a required passphrase is not specified. See * {@link Crypt_GPG::addDecryptKey()}. * * @throws Crypt_GPG_FileException if the output file is not writeable or * if the input file is not readable. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Signature */ protected function _decryptAndVerify($data, $isFile, $outputFile) { if ($isFile) { $input = @fopen($data, 'rb'); if ($input === false) { throw new Crypt_GPG_FileException( 'Could not open input file "' . $data . '" for decrypting and verifying.', 0, $data ); } } else { $input = strval($data); if ($input == '') { throw new Crypt_GPG_NoDataException( 'No valid encrypted signed data found.', self::ERROR_NO_DATA ); } } if ($outputFile === null) { $output = ''; } else { $output = @fopen($outputFile, 'wb'); if ($output === false) { if ($isFile) { fclose($input); } throw new Crypt_GPG_FileException( 'Could not open output file "' . $outputFile . '" for storing decrypted data.', 0, $outputFile ); } } $verifyHandler = new Crypt_GPG_VerifyStatusHandler(); $decryptHandler = new Crypt_GPG_DecryptStatusHandler( $this->engine, $this->decryptKeys ); // If using gpg-agent, set the decrypt pins used by the pinentry $this->_setPinEntryEnv($this->decryptKeys); $this->engine->reset(); $this->engine->addStatusHandler(array($verifyHandler, 'handle')); $this->engine->addStatusHandler(array($decryptHandler, 'handle')); $this->engine->setInput($input); $this->engine->setOutput($output); $this->engine->setOperation('--decrypt'); $this->engine->run(); if ($isFile) { fclose($input); } if ($outputFile !== null) { fclose($output); } $return = array( 'data' => null, 'signatures' => $verifyHandler->getSignatures() ); // if there was any problem decrypting the data, the handler will // deal with it here. try { $decryptHandler->throwException(); } catch (Exception $e) { if ($e instanceof Crypt_GPG_KeyNotFoundException) { throw new Crypt_GPG_KeyNotFoundException( 'Public key required for data verification not in ', 'the keyring. Either no suitable private decryption key ' . 'is in the keyring or the public key required for data ' . 'verification is not in the keyring. Import a suitable ' . 'key before trying to decrypt and verify this data.', self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId() ); } if ($e instanceof Crypt_GPG_NoDataException) { throw new Crypt_GPG_NoDataException( 'Cannot decrypt and verify data. No PGP encrypted data ' . 'was found in the provided data.', self::ERROR_NO_DATA ); } throw $e; } if ($outputFile === null) { $return['data'] = $output; } return $return; } // }}} } // }}} ?> Crypt_GPG-1.4.0/Crypt/GPGAbstract.php0000664000175000017500000004322612610161626015631 0ustar alecalec * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id: GPG.php 305428 2010-11-17 02:47:56Z gauthierm $ * @link http://pear.php.net/package/Crypt_GPG * @link http://pear.php.net/manual/en/package.encryption.crypt-gpg.php * @link http://www.gnupg.org/ */ /** * GPG key class */ require_once 'Crypt/GPG/Key.php'; /** * GPG sub-key class */ require_once 'Crypt/GPG/SubKey.php'; /** * GPG user id class */ require_once 'Crypt/GPG/UserId.php'; /** * GPG process and I/O engine class */ require_once 'Crypt/GPG/Engine.php'; /** * GPG exception classes */ require_once 'Crypt/GPG/Exceptions.php'; // {{{ class Crypt_GPGAbstract /** * Base class for implementing a user of {@link Crypt_GPG_Engine} * * @category Encryption * @package Crypt_GPG * @author Nathan Fredrickson * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG * @link http://www.gnupg.org/ */ abstract class Crypt_GPGAbstract { // {{{ class error constants /** * Error code returned when there is no error. */ const ERROR_NONE = 0; /** * Error code returned when an unknown or unhandled error occurs. */ const ERROR_UNKNOWN = 1; /** * Error code returned when a bad passphrase is used. */ const ERROR_BAD_PASSPHRASE = 2; /** * Error code returned when a required passphrase is missing. */ const ERROR_MISSING_PASSPHRASE = 3; /** * Error code returned when a key that is already in the keyring is * imported. */ const ERROR_DUPLICATE_KEY = 4; /** * Error code returned the required data is missing for an operation. * * This could be missing key data, missing encrypted data or missing * signature data. */ const ERROR_NO_DATA = 5; /** * Error code returned when an unsigned key is used. */ const ERROR_UNSIGNED_KEY = 6; /** * Error code returned when a key that is not self-signed is used. */ const ERROR_NOT_SELF_SIGNED = 7; /** * Error code returned when a public or private key that is not in the * keyring is used. */ const ERROR_KEY_NOT_FOUND = 8; /** * Error code returned when an attempt to delete public key having a * private key is made. */ const ERROR_DELETE_PRIVATE_KEY = 9; /** * Error code returned when one or more bad signatures are detected. */ const ERROR_BAD_SIGNATURE = 10; /** * Error code returned when there is a problem reading GnuPG data files. */ const ERROR_FILE_PERMISSIONS = 11; /** * Error code returned when a key could not be created. */ const ERROR_KEY_NOT_CREATED = 12; /** * Error code returned when bad key parameters are used during key * generation. */ const ERROR_BAD_KEY_PARAMS = 13; // }}} // {{{ other class constants /** * URI at which package bugs may be reported. */ const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG'; // }}} // {{{ protected class properties /** * Engine used to control the GPG subprocess * * @var Crypt_GPG_Engine * * @see Crypt_GPGAbstract::setEngine() */ protected $engine = null; // }}} // {{{ __construct() /** * Creates a new GPG object * * Available options are: * * - string homedir - the directory where the GPG * keyring files are stored. If not * specified, Crypt_GPG uses the * default of ~/.gnupg. * - string publicKeyring - the file path of the public * keyring. Use this if the public * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/pubring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string privateKeyring - the file path of the private * keyring. Use this if the private * keyring is not in the homedir, or * if the keyring is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * keyring with this option * (/foo/bar/secring.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string trustDb - the file path of the web-of-trust * database. Use this if the trust * database is not in the homedir, or * if the database is in a directory * not writable by the process * invoking GPG (like Apache). Then * you can specify the path to the * trust database with this option * (/foo/bar/trustdb.gpg), and specify * a writable directory (like /tmp) * using the homedir option. * - string binary - the location of the GPG binary. If * not specified, the driver attempts * to auto-detect the GPG binary * location using a list of known * default locations for the current * operating system. The option * gpgBinary is a * deprecated alias for this option. * - string agent - the location of the GnuPG agent * binary. The gpg-agent is only * used for GnuPG 2.x. If not * specified, the engine attempts * to auto-detect the gpg-agent * binary location using a list of * know default locations for the * current operating system. * - boolean debug - whether or not to use debug mode. * When debug mode is on, all * communication to and from the GPG * subprocess is logged. This can be * * @param array $options optional. An array of options used to create the * GPG object. All options are optional and are * represented as key-value pairs. * * @throws Crypt_GPG_FileException if the homedir does not exist * and cannot be created. This can happen if homedir is * not specified, Crypt_GPG is run as the web user, and the web * user has no home directory. This exception is also thrown if any * of the options publicKeyring, * privateKeyring or trustDb options are * specified but the files do not exist or are are not readable. * This can happen if the user running the Crypt_GPG process (for * example, the Apache user) does not have permission to read the * files. * * @throws PEAR_Exception if the provided binary is invalid, or * if no binary is provided and no suitable binary could * be found. * * @throws PEAR_Exception if the provided agent is invalid, or * if no agent is provided and no suitable gpg-agent * cound be found. */ public function __construct(array $options = array()) { $this->setEngine(new Crypt_GPG_Engine($options)); } // }}} // {{{ setEngine() /** * Sets the I/O engine to use for GnuPG operations * * Normally this method does not need to be used. It provides a means for * dependency injection. * * @param Crypt_GPG_Engine $engine the engine to use. * * @return Crypt_GPGAbstract the current object, for fluent interface. */ public function setEngine(Crypt_GPG_Engine $engine) { $this->engine = $engine; return $this; } // }}} // {{{ _getKeys() /** * Gets the available keys in the keyring * * Calls GPG with the --list-keys command and grabs keys. See * the first section of doc/DETAILS in the * {@link http://www.gnupg.org/download/ GPG package} for a detailed * description of how the GPG command output is parsed. * * @param string $keyId optional. Only keys with that match the specified * pattern are returned. The pattern may be part of * a user id, a key id or a key fingerprint. If not * specified, all keys are returned. * * @return array an array of {@link Crypt_GPG_Key} objects. If no keys * match the specified $keyId an empty array is * returned. * * @throws Crypt_GPG_Exception if an unknown or unexpected error occurs. * Use the debug option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Key */ protected function _getKeys($keyId = '') { // get private key fingerprints if ($keyId == '') { $operation = '--list-secret-keys'; } else { $operation = '--list-secret-keys ' . escapeshellarg($keyId); } // According to The file 'doc/DETAILS' in the GnuPG distribution, using // double '--with-fingerprint' also prints the fingerprint for subkeys. $arguments = array( '--with-colons', '--with-fingerprint', '--with-fingerprint', '--fixed-list-mode' ); $output = ''; $this->engine->reset(); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_KEY_NOT_FOUND: // ignore not found key errors break; case self::ERROR_FILE_PERMISSIONS: $filename = $this->engine->getErrorFilename(); if ($filename) { throw new Crypt_GPG_FileException( sprintf( 'Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename ), $code, $filename ); } throw new Crypt_GPG_FileException( 'Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error getting keys. Please use the \'debug\' option ' . 'when creating the Crypt_GPG object, and file a bug report ' . 'at ' . self::BUG_URI, $code ); } $privateKeyFingerprints = array(); $lines = explode(PHP_EOL, $output); foreach ($lines as $line) { $lineExp = explode(':', $line); if ($lineExp[0] == 'fpr') { $privateKeyFingerprints[] = $lineExp[9]; } } // get public keys if ($keyId == '') { $operation = '--list-public-keys'; } else { $operation = '--list-public-keys ' . escapeshellarg($keyId); } $output = ''; $this->engine->reset(); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_KEY_NOT_FOUND: // ignore not found key errors break; case self::ERROR_FILE_PERMISSIONS: $filename = $this->engine->getErrorFilename(); if ($filename) { throw new Crypt_GPG_FileException( sprintf( 'Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename ), $code, $filename ); } throw new Crypt_GPG_FileException( 'Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code ); default: throw new Crypt_GPG_Exception( 'Unknown error getting keys. Please use the \'debug\' option ' . 'when creating the Crypt_GPG object, and file a bug report ' . 'at ' . self::BUG_URI, $code ); } $keys = array(); $key = null; // current key $subKey = null; // current sub-key $lines = explode(PHP_EOL, $output); foreach ($lines as $line) { $lineExp = explode(':', $line); if ($lineExp[0] == 'pub') { // new primary key means last key should be added to the array if ($key !== null) { $keys[] = $key; } $key = new Crypt_GPG_Key(); $subKey = Crypt_GPG_SubKey::parse($line); $key->addSubKey($subKey); } elseif ($lineExp[0] == 'sub') { $subKey = Crypt_GPG_SubKey::parse($line); $key->addSubKey($subKey); } elseif ($lineExp[0] == 'fpr') { $fingerprint = $lineExp[9]; // set current sub-key fingerprint $subKey->setFingerprint($fingerprint); // if private key exists, set has private to true if (in_array($fingerprint, $privateKeyFingerprints)) { $subKey->setHasPrivate(true); } } elseif ($lineExp[0] == 'uid') { $string = stripcslashes($lineExp[9]); // as per documentation $userId = new Crypt_GPG_UserId($string); if ($lineExp[1] == 'r') { $userId->setRevoked(true); } $key->addUserId($userId); } } // add last key if ($key !== null) { $keys[] = $key; } return $keys; } // }}} } // }}} ?> Crypt_GPG-1.4.0/data/pinentry-cli.xml0000664000175000017500000000122512610161626015757 0ustar alecalec Utility that emulates GnuPG 1.x passphrase handling over pipe-based IPC for GnuPG 2.x. 1.4.0 Crypt_GPG-1.4.0/scripts/crypt-gpg-pinentry0000775000175000017500000000202212610161626017102 0ustar alecalec#! /usr/bin/env php __invoke(); ?> Crypt_GPG-1.4.0/tests/data-files/testDecryptFile.asc0000664000175000017500000004463012610161626020673 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) 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 5UNMRFSCudtMy/S5sRJocg== =ctge -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptFileDual.asc0000664000175000017500000004614712610161626021506 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) 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 KZDndsG2Ifjz49k+kYMws5azeXlBlIX+mKDg+NzFbrK7ltWF4WoJAZ+AkqS7xSE8 xBoKkjxKIINozDrOcQiY7HT05fbhT9HqlhLM48dspKp+zixTkR+hnb4+KS3x5+ol Z0d7+1sqpIMs6D3qzWnnFjalW9Rnu2TVrmrI8KGsvryr54hO1imIHrQOLKvMI/YS 4NulqfIR5VhY599nwFthIk7wIiAyH8v9GPOb0N1N27v5N4/3qwnzSyhPlw7o0bHw F2TtZ7wUVsZoqGKwmUK4osNVG51H7mPH74RGE9bDH698p0RE5/0KZSw6df0rlQze /dqvopJKxqllU/NQkeWoYuch0D+5SlXK+vYDQEofp0yXy8pQADeW64X7W+ZLYJjq WcCySQ/t8vY82xm4wnCjREd6zLrSAvKnCxVyHIOHbLfz1LKfTLcpqhgHKJlcpESQ /YBAr05pSNEU/ck3jgIB7BsNrLSujdjXuf5LHVlETGkq5qGVYCHuYNdCFkkHdwor kdlR/KfvYKNalg3RU5yI6YhwcZNlUoWdJKHcnmsvhnlz+Kf8m21Y/ZLKWILK//n7 wPgjQ++ku/bGN4+WEaj8T6EoD9DXPmI+FXbyFk+Sv4v2bkt2sjSn6XH5bUMZAfS6 T6JxJLNVEBrzdFpbC47cORaPxYfdQBrwMr0VMK8biMF5U1BSuRG2gR2gWCOHb52y NEPWlkJeqW/3whr5nuKga3xn55BdQVfNYRFkdTO6PWCBY8s84jeGiLhHlmmvhmZV 9d9CdnvpeAtbZZFZruFXzwnkXZMtyEwGdN0dxa/9jUot30Dz5A1GUmspN3Yck4HK dx9K2Aspi5nSFBSSl92T5BpQR9Kki8Gl4ZJV6nwQBRgDGPho+VKDiIUUaFzrvR8t TCR2qtEI2taX9xoRo3TqRvKfCZzHK4fyObVAZhuvUzpLPU/ufYy19nKUf6Bw8+y+ vUWAATTFs5ZbGJUzJ6nzfWjA7CZ7lSDKxVLJSRqCCFAE9BjCH+Gj7ks303UL6CZL +uofTznOnO0HFjGRPKDuTS69JtGxPLFj0R7wGMOZTP6ngszDCideGCLRsnTV8jWI m/ia1GYPmmI0o8Z/Fzy7zFAkMGlsGhAN9gGFYm4pyawKuJbCx4iQy6a7P4Mwt3/2 I9MLSusP4KJRNiuht+SsatuW5/Rd+ZTcvqlsPiWNfYhYNxo7pClT3ZDD3n6L2Ham PcLcwvtmUkarVq0YxFUxnyGkkHQiy/y63HASXps6aHg1TSf7f1fjJ8cSsJrqx67e UaU9tAvP9gWyBW5MyMeU6JGRogoEdu8MgO2MaB451Ot0StH0uQnNJS9eFQ9Xf3Eh hlHW9HXwgZp14TYKAnEfseMVc+Wp5+xvqQioBBVYwXJn93NfrlO8ryl97dhD6Hzu N+Oq3i3+OYEdeP9TtsBJh9Lexr7PNDQ9I+bhtxNNDAHa6p2f7rDBPLclRFB773Qz +5XdB1VYZPiL1askb1KWPlekI4EBjey5amt8KdC6l7xsoBTS9ULeGcEfeOfm6UkA zqciPVAvm12m0Zs5/8yRfULIuP1azO8S/DNzXJy097mgYkiLs9AUDHUH7LIbr/hV XWnKrhe0IfSFXPqkVNZR2cycwvzGGm5D4DrD/x2Wb/07F6Tj/p/plk3bDgHEfFPJ 9elX74HV3WOxfkwCUnq3hVcbLtotsYFfJWnvU+sQ2cSjOq6qVTYxipHpG/V1bRPt Tt5kB6wuR0q0Yl1YHVisFzuBZEndVwotvEYAxP3Bkvf5cp3h+jr0DsQzfoLK9pMF zbPlT5xNX9cF8GRvIf/mt3ZYZG1ooDdhJlYVzVPZ57a9rFkA8oboK5tVAj4Sb6KV Q6gE/DjTKw45+jgST2VSpGAAipW3rmNIKq+ZO3LJOW68xr92g8K0SCaQWytClTPf xqF2iSOvqKDVVDgI33UMjSsFZQi+PNAFiddTUVRZ1AKVdbsMr84nIefL6LqFil9C H6q4JdVnPSgCLcE+r07MpSxaIk6YAPXpD7/isRyRKcK1wgplTqYHkPtkqoM8G8RM 8FkcN0uT6JXAVk46XJKW3CjvAf5VTyKF5qMJyE2inpzw3JGjj8Z3IbtsG2gcHcQl y93dAmTIM2+4a268Poy7Lo6NibE= =YQVd -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptFileDualOnePassphrase.asc0000664000175000017500000004616312610161626024200 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) 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 71wBmFq9y72NvJ6XRA8jOYkCofrFdQbxK2N2jQc= =dl8Z -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptFileKeyNotFoundException.asc0000664000175000017500000004466012610161626024703 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) 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 =GNXS -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptFileNoPassphrase.asc0000664000175000017500000004464412610161626023227 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) 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 Wg/LWD+TfnkTpypivqSC8tWvIN+fBH31wJo= =61KG -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptFileToString.asc0000664000175000017500000000164412610161626022363 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) hQIOA5+T+RFnKO8SEAf/Z0WsgibKGysYfti9lfb2aY7vmAwCXnkrI8wZhqBAtfmB oe16PinT47AtnXl4CUgB5jBJq32uzaZKFd/dyCzOog1P/87OB6aa2w5mfxJKIIXc OevQgasWVSQw/1Ro90Fd/F9Q9fcHgHqCG2Q2BwkHG7IZ+V3zHlQpjj5flVTb7Te+ K5LM85t7kVEzc5vVzhMvoZluMA48YNL+g7qdA3oZDQ0rXRA1DnTVsQ74/RbIQaxZ LUR7v05TVNrcwK/p2NFzLOJcYSkOYGUpks1qvfUlnsuh346SLHXmebif4GLkBB37 WWy69+2OwJhlE0qakEJZu2EMFRwRTOrplm9YPs8Z6QgAlqKh5+KoSZTGyzBI8dHv lJJnlxBkzhrAj8g2kiUX5HfM+55jqtrdOo+PEd/nH56wTXaHqc7R0QE8ZdTyhmtd hlyzhdu/bHm09Q5WVAWkaA5nVldEtwIhss+YiWc+Ieu+rd5QkQiW9OAc4B7ZvPCO iDPpzT5rNe2hI4K9VkAKhcBDED+iCHkC4AZs3Rr/6tUCH+dY/roB0K1GtX2eYff6 UeeSRsyuYbwQkKZN6pC4JQFWW7z9semrTsHsQzE38EW0IxN8nGCiaAE5cxjtW7Pg k9slzsranQ+n7teucg/+qlArY11LJmvPc7aoZoRCa76hzzDOHskA0/9GRcBQJlTd ctJWAd9/Bk9NJkwWO+II22IQTWZZrRUN8FT6pnr/WxpWM8LL5nq1Lxf3SQX+H2Jq JspFzixPnaDl16sE082GSg0VctFMkCZhb/jghMIQYJ2131DoGXJ4QDU= =sjPP -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFile.asc0000664000175000017500000004516712610161626022066 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) hQIOA5+T+RFnKO8SEAgA5HXlbDH69omsR65k0yozXcNVvjCrFRjgSwa3YSUCabQF c3gd0yqcpbbW6f30GnsIREPakIn6Wy5wVY27RMR1ubbJBHq2U0/fg18ElZmCNLH+ FHEW3zgzHS8XMYvNBCvfJ8ajZ4prXb9Vq8OzoeQWEetH9iK035bJir4f4f+Cgu8n U+SsjcE7G39pt17cXEEBIviS502vMS9jY7Y4FlmpfXkldHUUS4MSmA7vzyV8oMxI 3rYkTod3em1AwEUdwqhDykavbQR/wfaEOoSLlA2k1d03w/fdzQ4MuLntwjXKyLNv ADpez609pOQtpy7GdQ+YkqjhzAUM9cj5C2KfTsnG4Af9Hkfej1OnikHeGyjy0Z1w m7Gwt4UF26HNeWoBgnoBia4DS8g7tg0vTtwhTnziXLtPUr/u9ySgfECRmzeedr16 Of4Yi2Es8v9cVdOcGFnkOTXw5H90nixP/SnTov0kNdOCuPUOr1gFJKm+6EzoreUd LYH2cpafmlvPk4ULEirGy0JXdd0tN/B4o+m1Q9gCUJHRZz+WrmCkE0UW2P+6pIYY vLlxhBsfB+Nuos00FtehWV8aUPVhr8GOaBNSGA/PCHrWgZwqWZ2knHPUBhBVPCNL x+sbdDwfrs/2MGHG+C3JGB+9yFUPhIt4CXMDF6FQgg6D3VlDy/fLcY8baflGEmGw YdLtAevrSS9vblaT50CGJuZ1oIXKLisr8vJ+HoFsVuKx2MEoKM6r+YRpp4ASqqgS EJfCQj5iDBt3/MjwblLcTdwO+sLe96T1S5zLkVgeYp9G0X8cejMv6E8ZxDnr4abf nYC/punam+MVEd6H7z0KVu2U1+pzzLObTt5d/GtJo5gZUxLF6Kt62vZt2t8k2AAD KQC0H6EpzeqktZedOSyk+ECxeA+YwPykFo7fbqzf+1g605/BX1EmxOfIIbj27dJy vRwqvepjXHLGnBRDYka7eZOqkZWdAD3jI5EZUQirWJ87gvNMrtaQnI+v2qd6dzp9 9kz+JZFAdPBi+mbXpyLnpBtIvuvvUF+CgvZ/Zzq2gjgr+7SBSVEMS4LNi+mBrTVR B0BUdiaBnGE+grMA0DMZKKwDI93SbtlZ9/GmGoudK/ERejU+gmXhTf9oMX2pgMBN jRmUiktzFdAT4V/iy76IAuyZ+4EIvtXM5fs06eTflbWSQSM/DYf5+WVM0+I1cEjM kyg8jvBPtWE/PXbeUKlfjqityB8k/k9P8rJqhBvHP1M9zF7l3U2PC8EApyHtLEiw hYLVifQgi+JX9olIlOVa4Mei+d1rSU98muZKMK7srIgUUC2GTdJ5lKBfxW9PQcKP FofdVj1+6nOis3uN6eZCrZHO1NifP8+ssMa2Jdn8Dr/S/1C7ezWceTAzDpzxkK8I 68KCXw18j9lCpmkvMc3Gwm0800g1661PYFgszGnnZUinByptZk+4rSXC8bGQusVC ApUzaF1fc+E5/8kTtdjJ5ftCCmtuGyzmtVwQMjh8EPKwZcz1Ud7UD5Nq4grNvVj9 4OB5+KbeA6cykHpF90LKVf1nXvMCHW9c3dhiZY+rOTcwAPwh2ckeRJhB1O6e+qUq 6JgxVczDWeROa7o3YgsKBVKZBOlflfEZ0YvduYbGD9zqu89y9rn/wBDvWP7WYtHI wULYfwdG6Ggt3Ozg4oz3Sn7r+kMR3i2RGNcKptHtJHFXFDFdf68L2lw4+PFMMYyv KEZonP9OUR4WE6wQ/YtDJJ6ciWsG40C/qZ1ill7t+QzkJxL7GZ+pAQQ2NIqjlZMM KjqvdMYe0GYETPe2A+8jizFD1GKu8k1ekQFQp7iU6DelFpWRuVtcIVs8Ke4TrC47 QgJyP54WWXqlbdmWjKiVW5OW+7x5rdYpXh5JgFaJ565mYcO0x4jvJUMRLNwhSRB+ +n/U42dydU+foRwJJCwRctUdk7NV2fx6ewZKdKj96wrqOyeuvuNGHluq7eHZqmYD Yi0wO4QvDVijRgdyoOSlAlHL4b6id/eK56+hqx2APdopLKptl3MF0y6LCfLVb9gl MWdbzF8fO0pFsOQXI1eM310TJhWT/q0x1eKwLWD4AwwfZFNsvYTSkMxCYRn8DqOQ 0/FyXSbBho7Kbt3l/duBi03ElVU4NbA13u7mz+3rlgXHoGvzd6t0wFZDTzZTsCjO MdSMiZdaxZHICdqtj80sBf12wxR9czJ+tFPhiTCcIcM6JkogItg3fsXf9y1GZO++ pWq4CA7YnJOlaCSFYjYUSTTvheGGaLs9QvexnHFa73X/KxHr9OxPwnTmZMr+dsVs VUCVand/xwJZ+1TRs/aK2olOAPI2A+BEKElM1fslNUQfumqq0oe1LNXoy6Zln2IE +8b1GmkRjo0PaZ45mgu6q0UO6a522CX/4eVlN2iDXZatpnXV2wZ1A2N6YwLb5Uuj 2iEH47CSzDS33k1G4nIrXRBsk2kSm0SCSs6/NFn2Ku6ECFNJf+pzgh1qkJ+vL5AS 48cUAVdOM07D3DQwx+DYAA/sUbzKljp6Ho+S8j3SDghH+5z0gavJPFB97bp40gHk LL0aU5kuEwOQ1me60WeBEfr1pTT5WA+MNMI6dGpESdwof1qX35V937ROrb/lhVF/ azd4SYFV5/xMiMA/dOLfjx4Q1YuP1jEbDGU+n7/rQ2sjgPSmi0gdaCALuZOVlyYg BZmT0m/gAY3qXFR4P9CO/BmSuZtDOFWn6dBurlmKvpEuRaweqZrWOTTCm0x6y482 TCLYra3tTeIFotS4yZc11b4b0RBA075dhaTrdNvEtbn9062rah7PoSo//0wxXZsm lNyN9zs6Mr9KGw7dLQ5bNkGdJ/OA4G+VCOJqvQI1RTOSF8E//ZeS1YUH2uy6bVj/ vcwiHy8qEi01CNSt+3ayrcCNEILbB/+y2P0BqOvZbHYXnLCOTyG3JBn2s09KJ83S 4tPv6vUR6GCcWdU5XHJInEmO2RdnuUqp++T9f9tkMQ8mNe+gMs+SsVa/oYNh0353 ForY58hG7b8l2SW1M9UvoM7VBmrVrBPyT+08Rq43BKh3uXetiTVQbbLeOTqKD/OC ZZ5LA5L3aUZNkT5yZkKliFQKWO7WqqoQc5JLzJFXSxuVpTY1kx5yM/4DLxH4Vkk6 D8c43TXushpZYDLs+ytKOImewm/8NE84kVdlQYsKnUJWR/kxqf+WTnD3kxTA1bAe s4+Hg/KjwgtL4JLqL2uOAygbm6XUVuZhSzlpdTbVjaVl49TYXCX3lQHvFelKeBKI 9gNoyylATkf2UFQ3bbE+dxValSpcRZGvakw7IjN4sHvPrtfKsi0CffSVdL2uIDc+ KhMrKDY6jiKDxLeGFl3Ur3CxjidU0bg2kMRbDXoS6EErzw4Hz3o/xNDKF3Veq0nx sng+EU2+FwiTnuYSmR7r9Td967iWodi7tQPWLgmG5FnhvKJ0uKJ3gTMZcg+kFO3X 5Lig27P/2PbVssvBsA8K2VCymApTceDFTbenVroZzIUSDn0M+6hYvl6CdSCrqjw2 a1DvMFMWvmeGHJq/B945quQWicft4F7vkanAjUnwwVQb1Xn6STsfYfBuLwXjV9gi 9gaimIkv8URSA6ezCroBJwwgaIscP82k4obgy34mZrTj4WAdCb2KSAEt2vBMXPZD vmAT3x3ikWNdQSlBlu2+/EKndoAFeqJGmIp74tFDvoFBvW0wu5OWbwiq8ohPFV2W veyPWJz9xlQ71+aqs/tCDJ4DLE2r2kapO+T4j4e6zvQdY/TBA8yfQZF7e3VLFz8u 5EwZsYlIspjt96SAzvORplHj9ct8r/iewvnAfMbt3zfJXNmFnp8rQHJIFnqpHUYE ZlWNZoLiuJs4f1DYBe5kbnUJr2jGZoST6YBMEFAxAKe5YTXkjlRrT+chqLvg/qfa 0OpnBIO8rfhyb+6BnFBJdjW1RjJ82FtgoV8Sv019OelMlZsfIldlqU4X0MAmftc5 hLnjXjd4gp33uvoVvqLDM5vXsg7TDMYzv+YRCpMe2RShWm1c99cW5T9CXNi/xMIx BDrQoC67UfCo9/eAHDVpIGQ4E1Z618ZjEy3YFkob9poSzdRI/FiWbi5DBI52JIfG jVrkahcUGhJh4iAYpeyRVwMxACrk/t4V2ynTSHKVAwgR3UfdZBCGIdPgKcQosbou HHpY6uLZqnI5pBWzUluQ0XU4Nm0/JPM+3R469VVpXRfvi2pWa+9PXjTyfSGddidk zJtXQzRe4nrJwpe4qJf49mzDB0yikeKYJdiDSg9HTi53Oz4suFQc82PvMuQVVIna hmTbeQo1JnmIkdmqobb+mB95MiwQaDUxIeSCz5THhYs6w5sv9OxCWVVf3fAFE0YW Oa43ikKe49kChe96ZgkGuPKTGw16qClRc6ztaxJox0io5zZZ1MEAMgDYnzVcOIfo yZE5G8PNndF34swaxhS67YRk7dWtzt09tnpcXWbh/DK3kgQ1gqEIqf5+zS8kRYxB /juxkkwFiTzemMCFouYE0Ha0ZVbX26IzGUnQDqPl3/Yo1GfJj6bdi+Z8F1NwF+1m kD8w5REFzbw3uyDFrCMvuYEGrTMwZVUsPNPU8i2J/wBYzUc6AjWuBGTKEuIUmdW0 3yQZdJD6B3ukHd0XajXVpKoXD7VNF9WZIAURh+CymiVMjSfLaUPtt98DPCHrZAZB hm1E2oGQjSN8FqgWzC1uX1t3l4EdNjJaUvczmvIffqCpPvxIDZhrGZSOp+kKANRM cJCspQiLdZlaL6/c+0EfX+4jKAPwgCOiO43sTYG6NbLO07Q7CvMa1nXr6TkNMiK3 1eCnmhXVUDXE/0Y/sS95vdLxKRUAeJCRyK996psidA3ynn/uARcdWOdmfdSddZrQ fjUHotqhisjqEURQZ3hPAoJPGYvkrMqg1rmIBsrD4dHWr1bhJ1niDe39YxbgOYeN 4B5R1BHs3avWkiD6jSX6eGfmdw5kbvlnV1wTlvYCxMNqBTrEojP4Rp/+wJ1l1ndj Do8i4YIzk6N+AF0SkD2W0EgXvRv1BIQWu0+7uhgojdnDaOTZfOKmK/e2XoLgHqrf NLZc8TVbXdCKxpLfZpAUybB98WwyTIlchTc4AaX8UpPbJzcAiOK2u1/Cedc1vChO rcBomd6cGwHBYFf2D4zy3rQ7gMd3J80ul3LZN8Ld/ou+td+tBw4mEf+n8mMzm638 ebR1J/j8ZIpOJ1rXbD56651QCOH+MKRTN5OxE/4Hu3789+CJ02QdAXBokKKtZyH5 KkCqeVpul2MixLMLu1777LC/h+c0bZ6awPCIPidstMgtNQIwci7FZSHAgeFdf2fE dFow68w0kGVMT4/IAkgLBBK5L23zax8oQK3G4V+YGG24+IettgLwJPFcZ6eHh6Zm ofk/+PGrDJpN830GEpXD7Y6qoWC0ETche9p5HiAihZyHVS0PXWIVRmNwUx55Ok+Y XrqpW+Ah92PjTm0i93aNV5mbZP40emYo/91ire/s9g2/XtHl0/x01er9Y4UKjO5a tT54ylNfmDvlnmK0fazXyjxkwFOOuOPwnGKcUc7lmGZu8dgtSdtRxxbU+LK+gq1U ohRJAk1WEoy+Bz33DW2FQOSrbFrROvK12nxIkD3fAlE+mmX0V34oUIHu34jyB70u 3IaI4TNN+4JD2JvCkFR1Ruto6OZuGstOwFDBOAvYf6yBDIWQ+i9uidpzQkleNJFS gFj65BgZzuDJ6htn6E6QilqSQyW2zLcWfqgdNoInYWrgOOmrnoGVoNOEjkjdbUfe 2T415BzKk1beqTQn5T9Jmzn7VWwraQwKoqYE5vcs535cYnw2mp1qVOckOi08FZaV 5ZZGXgrW9XSYFMFIKQ9JZt+i2XUJh/YUq8tYK0b73qX0ZWDgdFRBmdsBayBl2KiV KOBlxXxG34ajQ0f6X0O7ZdsPDt7Q21Asp0WOMflEwebeHFmNr9rSl3RBj6lRk5yI hbDdRG6lqi31NPCcBZ0VpljRWfvWvrhh8v5oCF2/35Lnb0joB5d1g27Xd3Fx2Smd zWpcXQ0Rgjh/OIy/BbzQ6vMlfmAw2gL2bPjO1SC7DyvVIPJr/xCWbTfI0ASzBdUH 0ss5Da1QGTbc8DjdSJZQ0yqisbOoO5PVf+Tu+dUKiGQ36Ae6W9C1OeG+qfU/Sa+j L8q/5KNhuv2bm3Ek6qaI5OE+SlcE80uatSg3U6VcYfdER1HbQ2odyakmAD2SisQU fgzmVeytHuFVJFPQb4rHMDXbxb8TkLe1snD/KzQ5cVxvu8LJSVy//mbFR/69JyWd cOPpDUIdElc+5TCHhkIyiYlh4pbbaRP9WwWOeD7/UyJFZMffdhhKMIprba8bpGwp 1BK/35CnW2srKcOInfl4kOk5+/EEYkMnFBbHkbLkbXOThev8yi/8friMRVLAkbfH O2u4V7kn1Nb/fTFJPWRMvQlaXuxVC1ZB2/px/hGEc1gEgy3LFDnZVASqvJf9JuzN dqWpxrOgUn2drd3u7ak8qNYgnPLRpuM6i+506HUfIHtzJaXiwDxoB+2IdVZ2P0ya 1jt8TFDAR4fcw92yY9J8SlFtr56rWp4Azj6mI751zqsNuq07kLmR1mQrWGIVMVWe aALexIAIbhKmLysRDXU63Xc4uvOWJve7eq6jzHQzBDh9n8XD90IbaYdapVEHjGHg 1dSvS7+8Nogb0oWAEcswip9EI/0eHvfnsAENvFxL393EcCtt1Z0zdHp6U4aDg5eL F9DlmY9vEdAJUo77SKc7aaY+MycNvIPPJ1DQ0iysp6pPP5N0FnbMN443l+AW8A2f SKDBO8X/Nn7N5iTghLeuJRy2W4Pwf8xrxKz7nNi3oq3tyoxo2FOXPNtw6u2Tol7y vTvuIFelTcimKp58p36+NLk3FfXoertys73jQfVWTm/L9ik78xK7kBpjIIqqdWbA vS/snFp7sn9mI/p+NizqeLep652SHDUlxPbFVbpIN/h8c1OWybo/aG4bfQris9HU mS/8JQ9IBlhJlK8OKiNh5hszvUNeOgCNTDRVd8WVl6zKOYElaDPr0o6Zc0iKWbBt d+LP4uxlwiLkU4HGQuNQ9kOXwqgcZGuE8gRDRm/KSb5Uz5ITPno1WCGgTQuRjG+t Zk6qUtH+5aGkB1q2CNZ9ueqs+1y9mwgfjjO9opa0FTICCWHygaH1DF4uTmR0I5Mb vewD2EbqAGkq+nA2odRjOEQkIdKZ7vlQrIQs72xbbOyk0mrUvSnW6lXEfV5k79YQ aKoNynWl2otDJP/DV75jgDADz7aK1rXCHnHFbY0t5PplOefhnWNjD6DO8lt0W8wU sLikSZmouDNyI08pv4S2LlIhglQmh/9hP1I3NO9vryqBR5tfPDcYlB6E0zd+CIIM v8N/uluTyscJFVoiZ9PPp9+uNobFHzzwf15MqneFESjEYLF6+//paFlJirZZwz1D uTxPQiHe4wg6oq+wS7y7EFwtISKI6pEk9FNI+zWUZedM8IsrxzRd22XmJZxsjl/T fL6Y5DbLWa6/6xCN8dEj2EhqCcYlSV9komsIQ3OBut0yCqAyk4Bt+4kcFtnZd50l J3fqrZbq6vgagf7et4+XEvHlL5I2FrX1kTl6yTmzvXDMo/e+wOa2bws3Ox8+fqc/ FaJnjhaIWktD1QnvNpAO52/f3JFZopSXKbo+pJP22+fmyG8lJ8yrLubCEmhJ5RfB 9hK8ZbfK3PCX+Vy/8NHA1PqLSzEPMUNk0BpYBOVkXh0rwG7IQh1sHebdSM0OD+F5 7AwNiNBvdP049Mmb+JVpf4knkXP0FmTPBYO8i13nsij8dM9Szown+00NLFESRoU3 d7QZ28ruEhyJBGBGr/iWXFrYjhBZpsj7isNQbgPZxEeCR7FcH7wEPL5qqcW+BTEC R2Qtkaj+ir1jGEHCngMt3a9zF3N8XbV8PEYnDjHzqpaW8q7BqClwIVpFjGp/igrk xsMzHURiIHVXQaI0Spxl0xGu51/FLKSuagurx1NVtpO5MjuVzUDREt4qzKtKZT3y j1gSRsoQ38iLC1l8J83lFrUujDVvHpnpQ+Gw50lfq7eT1xuwcZt4ffzZDJJUBkrw p0KTl2zqBE1ZjarOoqRwiC13a3Sl8o0HQVpyF/pGR1mDYYNmseJyCEuNCXmNecBD 4bFtr1/CTcT7mOUQabcmHcdTyAclZxXaOY91vCr10SbagyrnQ9efB3i2lo6m5q6D x7X9JroniuSOg9W7GCPJjWDL9UfqrARqKFIpD4jOstlcXGaowxcMv23xz3pN5iOJ HTyoczFvF7Ww6JIiQc6PGkqa0r9XGnWY28LprtkOChmPvYL0RByl1iSKFEcX5clR cKnVXzs6+1o6IfqtnvrtxW8YrlZVqSL+VhGZQ/5S+xXW2wFZQULnWR3VsikNqChc IASsY9xz0R1IRHD48rLal9LOasWg2PWyYpt0LEB1VFi/NcpMfFFBXcP+j9UX+f1q I49NqQ0W1AcYLKAV6xLiC5qD37MJEnL/7FedaIiWDkq6ocnHWJQ2fnuVbmL+PQEh 7HhCM25kTC95VTsJdpK401FDiBCYCVuMpHWnZ+xVoR6sdqGd10yuGkSQ5om+J5Wx bmlwJhF/ZZZrKzDKLS9Yt2HQTkD25PRnnONXoU4RjIs9eYsbdpZTXsVmAeNnKrn4 naMcX1YehUyuo7m0iXroMzhm4YlA0XeuKYAUqJ9tC+VBS3UmYYnQzX05Ql7Jjg19 aK5RNSeulkrTDSJ4uHqb86wHP4Y9H3FNdi+7rqvyAAo46oZMWpmHW4NaKmau9XLy qlDGYzHq13j/hdahKVw81xGipzylHfGvy/UKOjwGZDXE1wAfmQjEtqwps9kQ9Lpt qGsfZGokz9pmULrVCBv9E6escbNGQTHOXV36bv5gwq8PK/pPWTeXEDxa1Mg4cN6c HDszkBRc89/jSwSYww/tO5pt4CRNIW4JKnysb5GFnMWJt7oPbpLp7nJUT7S+EUAg IshF/EUuFYlgwipzvzEkNe1EUGUwbi21NM3XM4V1SzDf2AmfjbQ4tQHkrZROlqu3 +VvspEbuGvLWbEE8QSycymV90BxbZWdkFgX6JG2o40C3tI/EwlDTxD38sARMQgQz QfVBZ/x8oq4y+MgvhpvchlgS2xXrYM/0zIk5r7a2u6wIQymVGTzi5b2fXdvwV4Xu DBkk1IrooWVH6v/hBRHULjWBBr1Y/xzyKLVK+h/uGDAtxey/orILm7+xVEbrcP/Z ij91wsr8J8NpOpyFsAWdLlpCWvXmdqDhN9jpzRM/akK4vVXnI3nc7yZYBeo21JUQ ZcFWZxsOOYAW1KGln10wN10R3D2TiRy49NjMk7vgzkLJa/TyhUQPJe6uRkwL9v/0 MusAV8q9SM7vmuofjlKzEu6qh5xen15hj1UZF+cYvGKNeQleoCwtlJDm4fqUh0Pm dfEgfZcgT2W5EwjmdXDbF6ZT639+/1BXyy8r7PRnFscMJWD8P6WzHwI7VNJDd3be BtfBBYCiaE+4/EvPxobkTHvIvrIr6aPtzdStX2KWkL4OuPgOKOlmMB97zQU6ceks lkITkXgWJj8t46IXHdhVhX8/GquitSC0upqGRXISIdxpi+t6XDOgPC4iRJNNBUjF 0kOCGg1ITfbnMoxlBNBM+tZFCfy1Hf1eQ2nwDa+JJZyTlan8SgJaTdO5jYU73pQW /DJdGne5KxSFzmLzThIJg9Lqc96I/eDlt+0Mhafa6Heco4PO1dYeFW0GvM/hdlA7 zOCas8ZbcvKNEOvqkDwsmyhqz80M3FUk0gP0uApjMSoT/whXh84s8xxs56pnQK8S cbTeeKbyRteTuNzDJi6nypEXynC/U5LhHIQL8fQ41khYDEnezMY4mbJ3x2vRnRZP 64C/wCeT0uEfCtgKfojLM+XCRB6KS6V9dymk+AjEP34Nk5MwfirLeecMsEhscpds ierK1oOH22RQLO0X4lZQlSWV76rYq1BW+iuA0kkyZ8CnsIjvAM75Kg0exiLVEfFg yZRPqXpsmLemtOwyeHMtS2ZVkkMZUc9dZbOJ6wnlzW9ktRoBXht0Q/hzHEP7ZmH/ 3Mfo+5l+hag/Xdue8bcuC6owNB7jJzSkvaPS39CCsP10Wg5JJMd3Jw+6FxHEx3Sc ATJEKXgBI/R5vXt0cJkmDpOjsKXtIafO0+qGIBtkyPguJlMto0NoBEgVzBHr35V1 nMkbbPJqHkKHKkQAowT1zOHWwVxCJ0bJV0SAlWOg+fhZ0cOmopU/JPpwGswUKtyw sEKcyHw7bC+MWMfwoK4vqnHLLpVk6D2znWhRLWJnt0Se3OuO/bm8Gsd3byu52zfC gN/ppWH82+9rOVALPcwUZObruFRovPAy4mcYoVAGaZZ1vUv2wgiBE/bxakBCemhw +ZQEoxLROnWN05GcXhTPVfK9EYKg3s7E9FTJP7eX2ESEVITKg41M7s3czbdx6X1t 9383MQ+WNBaEiD6YH5MoXSAlgJoj7oQVbcpeAVhm46vHuEU5KzIkF6yiU+CI3Ddz aIutMcaX2YZjY6QIP2DyP3mRBYe00qk8FafDVOTHLIBMB0aapZC6+1vZnlms/QBP em70VskqGQMZDx4aK5i2ufUCm7ztXflMDVXIjK/sW3aFDnrz5pF5SuGEBWAiQ7uX /7iK8cgbljGu63KI7qmqbd6mIvEjTQ7XHz6XIFcp3h7vq7Qjq0EBsVvzZ4C+Cgc6 yfa/mKih6qjtr0F1PyJnXpQMyP+7aDnCbueyozvOqxEMNeGC55aopieSmn+8gCqO tp5n/yokRhIIHRFgTJv0LV0Bv7ubO/H9ci9IeFT+n4f10L/ASWd7w4G+8nS/ucSs x2EbaHKbLHM5Dd+4QFc3MQI9h6Kq5D3aRCe/fwtLeq/X9vR7Z0oTMRGNCerpEQQH s1jaTB+faxM2zy+DiYiZ0OkUjDeUQyReHdnuEluoyFD+R8qlyTm6OEI8PHPmyGnZ 9rT8BaqBdJgW7iHPPADB1dfBIEDfKG/4vn6YG4pDOzm6SeND0M7gASldY8cyHleo n+jOovp28ZUrH7xQRLivNOsg4zpG5ldZDNUcsnQgugKawlXZwvzy/Kxk7h1d+OO0 fy869/bojqC49eEBiJ3fR09SI9iIxTTkg3T8TF2ZLNDt/+1X0loZE2L7eFWdCVp9 O5o/td69JD/R0Bespo7A/RtKqvk6+efRcL0wG2nPlFGcPhjRtJj3+d6Q2EViK7RE grLwytCqjYvkiwhXrHVGuKw+uutSPsE5GXjVw1iIUMaRZ9FY75MZNdGDpS8oWaSB rnkBq916EKFRh08xv+UWMXR9txQokEQz+nlsyNoeRLqNhsVSI+duL7XhJ0xlTvS+ o/xkmChKWmAzp2xD07Txz84hRbq+AVqaKYQiJOWzEmAyHftsuMYS21/KDJpu/o5l 6L6fASahcx7lI1X5NfBcV4jv0/GhmnGDvAMy8pXLPqtR5DCJBVEKrDPw5EXqtx2y GOqGwadFlTcLh2MZn9gNYWwbNJMjyK1zSWmL09CUvBiSG4c9oMhUqYb/beAYIea7 x1stgGrLlDIu0o/9+ByNSzRrkEz+9ktrbamNBuh5QyPXSKKHOcBmicOTIsKOsQ5M RKiFpb1Maiv40M8dhzWcqBvI+LqFZm2Qx6QqXNL5weY1o+bsZC/tV49HCB5VwNtf pyKVuoTtMhEZ+dzKFBrNRzGmdxF0M+WK4xUEesHMGzRahi8ZfOIBT9QTghBIiSsw I1epyOSiRqlsPUUqpyR1JPzJx5R0W7DNnyzSE+YSyzhDYXGQYV8JZrG2CZqJYI55 q1LWYvRQV1MwYEbm0tYX259q0ffSFxOdXL2bW/sGtGatdOQ8tbVDWYkuuej9yEwH /7gqZZn6aS4qGLuW2KpU7XFtyH9+JIEKQuDnF/O8dIEYKDn+1PwGSBk727iahKKc 5Oq6YdzJTleAYniCN3cMwXZ6ETNTMBjNwZbK/teKLrBMnC86sxqmWNgDuNNeSclX 9CVMPzSQuTD5YiVZIAkEUPxrBzFXENvgCdlfZRVWThANl/lI22R9/0Ci6jhhzDv5 ypBXbjcWll0YxY55sF503gYDAY+Fo7wEBZ7SD4o+arJkJDJGE7HYSSrJMmH0Dc5N tjwHsMSUOQqfMY/+NS2neeC4+j1blzQvYkLGpCAoFeAcnJ5252V0viqykeBqiSbt l5Muu0Zx+ln7omcWhqKkMv6O189HGSYwL9pUZG5ef+o2iKy5Z2B24ljbtDs5+mxU EF6SpiRWHk5TyIJevBahr0kEXm3z6H8vLkwo3IXF6hOHEE3+hWVTKEgksCw46v2I GzDYmKyzhqvMP7L1lxNsrY1gjdAcQ69196pDusm5RkjLVEQIu3f1KxRHq6bUE4Ji D0oVMN9d/IrydXEw8ifj64YJKNDtcAJApM+earT41HkCs2gaMoPnenF5X+/TIY2O raC1kDVxo/R7wmjFr/OXsK3lT3FOzInVrr27kHP7lSvju26s7oFfzyqwUZNZkUMx xNi4Xd4H7L0vhGnMagWY94Bx2qiox9YapBStbb0uRVqnRIKlPxqpoC8TO+pe7+IV ItpPTPcJTJHk1vrqjeegvbagIGk6+ptFCE1ldoLjGe2DTO4ZjxaFY8OUjSc1X03X qwMAZTANvTqPbtY3rthSsYujZ1lWjmdgPXJPqCPZ81dw5KhpM0TzvieZFoUUf98O +99sAWt7x3Kv2li3/FvPTed8NaUjIh68Mxl8ejsEAgJwjkAsa5de/vMx/Nnpt5Zs hXGHVpbdzObxFFRvxwcj/hV2RP4nXk1xd/h9bWlx//b3Km6fG/Me9pDlkauOkCBj kZiS/C92mRQlSnkvyNm0b29x6XDrZEc5YzTWGXKNoDFWpms/RL2M1xIEJCdzhr5Q fxb1Tk4SvQcilFFXxg6pMwRcfUGpUZgtWxAANpC/FsiniPpybga/qnPcR8WvfUMz DX1+6MuMs3seoGz1JT2OdeCBrKC5CWahzaMFEhGMltr1f55WMpTBko9e24j4YHpC eNXco8TElZngg+b6PdXHjb0mFN7XY23fE+/nViH7Z2GiOPJ/O+wwzICdUosbseyR jkgeoXUPw9AhzIGLtKLH7mV2jPuTOVm+Wwx8QrAyDyxdCCV62BU4TYHn/8iN4Rko Jffh8emqEIRPAYooHkBYlHI7pVM5ykIurKnibe1ZWx8yOCKXH73WDjSnai58uG29 MOup7+LOq8WVjloBf/RvLtC8K8T/wxU8T0xOlXEQExhlVgNj5l2NgQCQYg6owZWA jORYXhc8ZVNVzwB9RSXLPUN5XZ/P+CrNOnbkOM0OTe2l1Kxp0sMwJ2G5/yPiJVxr crvTh5ntUd0d2otKVJVj4Al8tMqJWfThJWE4Zcr3HYgnaR3jAdIEh8uE4xrvsD2H p83wDrWydkeBwmeAK1KQhSYeRFoNDkd6f0dUDeDdhARhhNLC+uazNDSU7XDyvTym DagOqFpWTXAaCU+2tjSD8UJbhtxGuzE5QX0QmSCFp/qZTozpVUaV2vM+nImWCuqZ MrbBZLVWo9pmnpu43G7XFGNXroHvPqU5+yVZh9mW5arQGU8GTRglR4wkjJTRZTTP tRWSnwGTy3b/P0fUBVv+5eB8F1mT+SFMJL71D+DlTmDzuRXqMqP4BZ0q6joavtY5 lqitHffIwplXRr1R2d7dGbbextpoi64bbrxhIOO1BlMSbR0kw++953rtOMttXGCx RlVVee4+AHC0ekX+Mz1rNham04+WqYkzTLjqASe0QgHk2GZvQa3SMUVIb2FHUpbW RRTxrC3fo4STOazHEVYZK0JXa8+nvRdxUNn6T8jVIW+QnML4ErsD9r3KFpQojcpk R6OJyXuV2iDzgereBAocdDSGf+drHT7on+CwSmaH3Q///Wf2YvGEHi67jAHGoUqn ooYKlotBpg6b40nc8valDquijLZPSQKU0rsDG1Q75If8USUrKoN/Yp18Na++NaAf iIUwEKLmcGpDCyuAtDqJIqRONopztNGAwy2L4XE0waRIx9IsLemNFtkgWPVk6orK EyU9uxMZovi0aALw1tC0uY88PDBco/Y+BaX8fsImAqOsCmcDWA6mp/WuOF0NhzGs DymCenI2GnXkR/O7Dhyv/uSUeHnbeApjPdRNbWzxHCz0L/AkywuwjELbe1Z7mMsm Fq6D8yTLU2STbI5xq5oxj6yJrL0nAwScTVRIWF0AeD+gPqMiOdZf89XL6PEaR5Z9 ikEQFlWcUMi/to8GyoQukKNznnrF/sV2iZ04a8AjFq4M+1hwhVex6Fnc1IJ7xHKd SqG59iaK+cX8vHPFsuhR2JZxTx8kqQhvFgUS4vTDFYYLq4ztkXIoWeIk5fmBuE0p zjbAx8R/f9qqK41KnZWvBgE/7X0ceJmrtPzqQVIpbsoin4E+XxUB9eJxk1C2zMHa 0aPpvI+AafBYLgR1WURnVeCvI7Ox4SBUm8wo8VXANp3aQY6nt89sEi3siiqDuv1d KGTlFmeuoaFoP2Kvdi7uoiLZHEmrpdaNrU/y1mh4FpZ0YfnHmRK0iEiyxm+vWHsO AKRC4tGZfsnohY71Rk754pawp8wOzlSilupU/ZLog+jsrXIn0Chkq0jpm6gTEJ+S rS0lrzodj4Hh3zUfaRC8fvVgrvqpEUvztlAWBEE9WHXxz4PiYk2DlBzRYd7GQOw2 2ynBq9ROFDHg/g9Bp+sFU4ElOZGmOzm1/HoFadgMrNbjXa8iAuj5ncQNwMqMHp3G vMhYQF/SrMETC8NqtvrLc7B3vUorY5kJ8tBSeJAG9kU5AY1aREx0qLZuvlVmerem RQTKFX+IIbjgRWo7SxHaurhLfueS58pMvoTxgedE5B1RVbUT8Rh+lGh44wv8SRwy A2XCVTvuNKktomctXjiBzSxfctcFIFlFsAk8GujkObSgExOnGHQtksuK82T0I/gx +JjVjICFS8GhZ6B3MezWKfOaha70vHk4PmAhgu1DA1eaFeSx8nZPp338lrzNZ6DB YTS9GyhbvwQH9KwGQ3bECirYgRsQW1txsh47/pt0kUX9WWskoxAJJF7BkyuODrp+ 6jvQeZxf4MyoY1Ngdu41H/Op2JDpGVfwefE2/cCac9+OX+7Sod0dyn6pBXabD6Lx PrGOmM/x+kXQ6u0X/cOIkLUVy4qPZjskpoKvR4m7ZoHm3lFwnh2SE6mVgbP03hED 3x2GuzHCzAFHyi6tJvsKNYGXEA8sem9uL1OwQ66ycYP+uQAVV+rNQgmqp4YAxT2T x3QgqFJmW56Ybp118yUWKCQJVTCdJtm4gEHxgZ8dXljEGPO5c8VaBXy8BYVLjoHN F8Rk0+LJXp5w7SkvlUZastT2+AiEcVYrbfvhUVRvdmIAhW1djqGKpQufFAhc/n5h aaOqsaafnMc3+NG9C+3sW62uLU4FcmwuYtYtDO22qJdAhx0W6ZzoFTuRIqbEGHnf U8FBLJGz0JsK2FxnfWY2Ne1DBysf1Au62oJuh7TwkrC47tEUDy+CHS31NUqDEVdG n9PnIgJHTzc9PC3/kO9/ajGi4+NLrzEkLyGeAdFL9R01Ondxoe2cDkO7gdXv0tTV 9yK94+a1dQA/y7kDIUhc+IIPf2zmiqUWQ8Rykdv1a6ZsFkvU1mtUh41qUSnl56vW xxVQ9VwuXNFwzIA/HykHkIH1+yGUc715xCiUOPb5pfPywCmzL4NuNY9+Cq9332EN u2QQWr8MFtTIoqm+nDOhfQMzr7vJw79dY9IDIOlmPLneid7LD3BJcqF8a6I/1byw 04yzf9UtTVrwUG6R5UOseXU28hnO2Eq1hQ8HZVg/yQosCTo+3umnZBp8aXDq6h3M bHXi9H0xgJwmytEAL3X9r9O97fHr/ySHrHKCLtDo8US0rE4nthMwpOudztxB9k4I DwWqjm0pATmzbgTy/0isiK+76kNISDYpKrbG3WhmJI80MuPHN+7dEyrfYjDWpg0b DfpNODAEXQsOFCySWI0mExOmKOuH2uKcMWdk1My8x46HfiQ5nU5KteK69OGnU6CY ScBRV9sdq+0cSqEeHxzpvOfm8QTlzhgIaGGjei2y54f6NRCdQvKYW9txy9ukbCQ5 eGesPbfkREDvTxjqLsyD47SqFIy7ACMRKfX8dt0EtS/2QTXoMJLZJtkiE9jvpHY9 NWEXo6kymJ7KZhcCYXj/AH3mYMnM9m9YU8cCdNhEgJDXgHgzp0R8B5K0l/fodHvL YHpX0KkJ0c77pn+7+l8RMOFUhs7UpGWhdGwyER491/o64YTxcWzNXb8U/ShKgxUH znuJsnTktB8XreSqX1OvoHs4RYWmtzq+d9HY05pJ3TW5/O4ee2R0UKkSK43d/GFc Z5ZFrjo1G6OMe3E4icZUDYe1KLUWtbZc7bWbBF69HaTJWkTssIE35z+IvYmBhJha dXU2gGRG6EsPD3j1IjAp4ranbDG18sBXnvNGhzcqA1DqB4mhEkWihNTjIwELOVXj KHjH75C4novQCn3++GdNKTMUrmOMdBaQVO74n1kpPMgdICEzkzff6dH+rlMziPGX oC6YvMkCi41DpoCoylLFSUHVodhXIn8uJPW0Z4J6y1hMLNxwfvEmdVpKAHTCdcVo sqhgAnivb2pfNTBX93A64JLicqJ4EmuBQPzAI7pB1+21qp4UW2alDEV7gEJlc+C9 cXc8jJdj8oZDdLMNFxqJTxhpTeBQZ6Id3Cn7PdVXerEZI6QppUtbZOt1nPSA8roi AXH5ZkKj09KGzKb/s9DjP3Xcch9YnYmY4ocPveMFTykLjWUjLPNd1YIO12AVMYBJ NY9XWqgeo5Eb3hA6U9oNMTdW7ruZdqH2WTotAT1Wy05Eys8rty2Ju/Wopu9QEiSM IlK0Ps3pY0xHAmIQuRpyyOGskMJ1MXV+U+Sft7B8lRvvqUyEEkzQngDlcbpdMzpS Of/LOukawzJie2bB7DCKfJMArPtdy6PUxxEhXX4GfVER+Fk8oi93Y0hLb36TEwck jeVAPz7rmaVO05BpIBnzvek2NrK0vVqVDBsTTSDcGKNnqTUxYs1Gaa9HM3gzCBzR Ltg+OZ0fUcgSpVCBe4HWJzhHL3/jYgRS3Fi9Fn/u6Jvi+jZZkcTXMsG/QQ6fHPa8 BWHS/+oZToRCWhMAopnKsCtHjl/9cLMDKUik8W+sMyTUI6AXfekZrUZ/+B88ZBHX 9z/C3Rn9RVn0qccNR1sUEEZHDO8h0WpM4o7oXa8hKx6HkIudx1QLVnj82Ill7arF L1egyg9SsOpy2x03p4649Tcf/oS2Hpjs4ZYT70Fuwh8H5qLT4F7WkDrLDVlWQm6s elu7yFGMrx6bkTRqHZ4YmH8XEbaovuy9ML+zv/sWPP2XDiQLRX5Q7cCfh93iECgf AcLe6gmMVbRUuDnzVuHy2Z+ElOqniWHh9/1SIn+NY33S94bKv3n/g7o8UeRRKUEl nHmf4BQ5B7RF7lAWc7x0mPX68ePvO/+h1liaaD2JHuiQpMYLcAnv26Wm0ukHV7tz NoPDcTb8blWIFc5ORYuEEN34BOvvkfPGvJdFNpSyywVuNiS9sdMX9dAUnPWtuDI+ M/fKgoAmerivRoiCZWI719viVprhdzEqrnGLOL8LMWfqWTqRPDDv8fZd2CtdzCYs dmISXZ+vbPPKDoj7J4QdpfMmgt01+M14vOrQR5MLeWKWVY20vaJcpo+32FcOCGC+ wa3lwWvS+o2XskFQpDY08YxCG18hup18wWR+3vL0frkyWEMsim+U8jzG2hnN+s7T RyiIXPvcUTMcqwFljKYWQLAmifzKOnQLSUJZrommSxEfoc7TiAGcByW3xrydWoGq MhiSzueOzOddGhzhYyQgEVc4upebfcKp+JPYJyF2zXCNpjBE5Y1a4UM5EkWvtv3n KjSMhV8IhQciuGZDS6ZgrxlWirXcGw8lKKiVQQqlCb1vR3O1miHITnpBx8gGbcGp mU+SDsVTfOLEE5YGvWexasGbhM3Mg5sqJ4fTvi3oPWre24+Rj76FQSY+6y9C2l4P MKPZt8wO7KWcY0fHKQGQUhNM19zM5YRWOCvXRuy7PHOwtZqDOAPVombkHleRhpeP 74HGYbFaWre8WFw/rzMW0Z6BC8UWhGWCMvViqmj2WpEquotdc0AEbRfOEkz03tPX RABmvGk1I3QXeXkTq94hz5/1dTBhQlE5Vz8BqeMJnGmlEI/JKNvx2syBk2lVrrW1 0T9tbvpbpkA/k4po//x2lUJol45YNH28+cLtGagMRCjq/G04tj2yu6LDKeHR6gTC S/zZL2Y6OSEyzWqjpuiwbo5qIRtD9v6UjPr+J2XSoERxKr6Ft5gbdAjQqwOmJymV mxb1AiLkbZzSnf7qBg7b6K+rkFK5qgAkjIkxFpr91tNneeipzMPYTUa+hjWrx10I wXX1f9DjPa9kY06Wg21XCTMJaiO9DlNsZUjQrbR7YZL2luBSRgt+Mj+FCDBJ1Hky FKNV909IuTlHQMlKl1ZoQT9Ei6axn2p9cGYGLBXtqcLi2OH93cV7zuCm35tarFDS 9FoBSgSuabrLLF4yB6tdQ+QniATaMnm3GEnpZ5koBqp9jzRFcz9weALfBe/nn5Zg t47cpX7MefgfJYnYIgRhS+F0g7AAJjWieZ+rEfHUgMO7liV5e+wnNhyWGwznEuoC XSyvN/ajZhZKkx2TAMMixjyJYXoMNqcpkYwJTdmNCfQ55zaxHA== =0mKO -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFileDual.asc0000664000175000017500000004650212610161626022666 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) hQIOA5+T+RFnKO8SEAgAhwvHkFYJg0q4wI4yL54ErUBsBlSr37zvIPM/mgifKNNN j/aAr6PXARJVpSXLb+PvTFSV5bdwFFrCT0vnBBrHInM5KHfzEEbgnEsmYdAzYGQF y14dFUmfXqhX8JHglpjh86+wbgS2SvtyU4vwRrtuUKFIcd++CHsbe9XEzP1HHTlN 9ACQWzGo5Cnz/Bipemk7YJV++yyLHmPeLiWhrIOmMyNq0MLKwDwRw0f8FXKV+Wyf Z3Z0t8sh6TAQZt3GbrbzNr7/0YTqSGudfX32GoPevKya9UESEOk/hoPI9Nh1WYpN RZL1gIb5pxUKfqPOE4WOOVSqRTP1pBxLR8x5TcSBbAf8CdUSG6l1d+wekRVrhLDa IysItsjox7YyWzyR7bLzwYTdKco7CqubIV6YyMdAGfQL39oMsMCg+nXakfijMAD4 otivTCZcn2dXqHG7BJXeQcCTAG0t2JD4vryFJItH52ZqROotbXhoMMYbrXIFIjPO JyZc6pPx1AJJHtPuRGu+NxY24TzxF2Nw/AJ+tDUpjests/kFUy8lqs8ctdbL9UIo dGj5f6u3v+jVr7lUFUddz6ETkyd1DD5QGucfHKIqXjDDrvS9UPBisK2TZo1gvb5z hZBrDw3ltO3xPjhVhf6ZDUh2lq6H4mrLxRSCt0HEo53I2e5Zjv9AkBnmpfqL0kyU 8YUCDgOy9U5HV+IkUBAH/1VcCJJJma5z8pTR5sKKyjRKE/zuK7/LU11yfBU+iAW+ JGkP6XvUEvZvy9kqc5OrxpcBR/Yqb2nAbuhMtJoJv7OIQdmwYrIP5mn+fiQDK9Lb 64u6zhvq5NPu956JlZpg4emzW6d6WCy3mhrwAbW9WXjgtjMqM03obXWuwMtdcddY 6noQ+s3Z8WKDX1IyZTwdsen8iTCqWBPRxUeECjUI7lPn8cos9pgZzBGDOvSisi6I wJzGj/ufDaeO+8gflJ5+j9KW4T26sKsr0sI7sjI6jgrQ1rVbipnivcWo2Erg7AGM VNQNlSBrH1Rk0dXT8vu+9MH38qtlSr+z8pDoTOUeO1AIALqEuX3/02HTfw42mOSo 5TAkmg1v7TrAXhVQsmpI6pGZO8bKXV7VogGviRB26qTbypF4rQtCEE9OlLD/f0tz UG+9djXgcb/ttOPipeDr7J97uVn9w+8r9b8j60T0jpJbZUQO3Y9ryT6cJvHRC9Iq HE/LbjtkxJP1xs8WJifZHC75l8Swm7NyntfYgSzAynn+ps/9KCJdWzeKLlPhD3l3 GL7x5dESzs6Ov6yOj6sS6RFq8rO2ZeLeJWbYo//7YPPzSyLllG6wT0A74DK5s5kQ xSuoUldKISI45pX74ss8+sSLc1DR39ZOEeHzbVGP1QHd5N/dieaRy0eRSk6dXkon Ra7S7QFdNeA9ge1QXuz8t3RwleujpFEmw/8Nhd6le2My3Jcp/cDP+DTnHbj0qXAF UdsNsDNrnmnLhrJrmgalfVmdFjgW/Tge8OavIVMiOV6UP7PaKoj30SyO8SzrB+Vy fstTFCJKHagjoMz+gl9lX08uvmmGay/aWevlpjpG7gydFuLUPXsC5COFnqc7tA54 /Xf45GxMjIOPDMx35cJywEdy7Hd5pSNcll+CWrE1ZW4gvN1bfmMFevzN1wTpSzq7 qWxEptAddlehfYk6SG43+Mt6k/J9JnzKETpSf2jFz3cetrux2JsOO76MlyleZl/y onXocpvSEEIL0OWqCzo7WQVg+7KAuGP5xBziUuGW4j1CYX/i9ch3kYyZGusD7Cqg JBf2qqr03oc3wWhFQxL1RtyJbLvQRV5M39+zpdMPu3DBPGIJRpcS+hH51169XqhD 0Em25QSogjU7PThk3OUJXFLsn4MdGhV0ssUefDTbNe8I5CdC4Y4Q4gbgJRpAvvwe JxiKj0QeFvK7Ai6Aj7GraDZETubudgrCnR6aBM+oyAoh9tzRX03YAWJd/vPsYYfP ba32E47UNgXyOduUFsvGKJy/OPmJBTUyCLQk/tqMVU1AWNXrCcnseS6QxgeqfcH+ WvqGtS6JkBj8hEUoBkucwIw5xbeWMr+oal1IWDBARej9D4G+xWhYEUUszDtCHMlh TVzGr6QRgHYgBN3Jv2ogi1xi9ye4c/yqonpruweoW5qlI1BOIKq2Pc+biIerxxVk 8bzWPf7xFGx6ZjdVanIznUb3IQKJKdyyuFCaRJimnt7lMquo/MnIkdxJXWxERBSt j4Wl3DLA4VPN/y1LRQippinVSFrPgykSK0PuH7vzuaGD26f3hprrYyi86E15niZI lkJ6GhDP1HSNHuw7/0/ToGu6k2w6JE9Hfq4g8Yrg78A0ksz05joSstKhY0QoYbMX cbsNuYvQ5CprBGxT9BlKzT2jur7NTWPaggOck0Jbflk5pu8E01GjTuBG2D2izhmU 1s0uxO2KfB6Y5+oNF4TuGFVVC5rnanhtCscH0Bh3zifnGe4tB2KGgrdjkoDVCVLm NdeP/2pCYH25bx7jK1yhVGP7YFnyQSqvGQx1CQIQiVPbVYZeh12KL/rL0TtW9fz9 9QE2JFpIAZpGpGkpzbPlTJWw7DwPkSGe7nV47uqLZo5b68drqOAadyNw1dsLryqY Mm7uzWYTlKPORy1UNCBZ1SwhFqZg/zoHQ0+bcw0tekn0wRtDMBHpRRNKwQ/+S52y EgcwcxBUCorOIwOEPSyaOy4wgkFLTIA5de4tHs29+/0NfINKLdvYDJzgOuYeqxgc UQMQqvMh/kvhFhu70agUgOclwLPHiAQUOpd7+WfNs3nOL+xc12B9tQGXuErqAoOh XfPWCnAXFslviiMVYt5kVriPIPFe0rxrd2EYCOTUZY2voUa7AH+peEp9E9z+jibc CHs2/y0ZSI3a6ow5+4x4IVFoGBBMWbymqkVKrxHr0+iHxWYFLe1dpGvR0zLplbqp oqv/+cTEU3LIk5+3RfWpoePIIGsNvpNGRC28x6LBX2j8BKV280vDrtSWHxUfTw7G 7o7aRqqKSyFDKwfCp0GLOlRaCSLeTIitICTmOFKJwndDOJIcJWqW+rmvIyfTDTpW pTsH1jsCHP0G/b2npDvS9Le9qUQlLFfvj6Sm2/iodkGCceSdvzDr2uixK00DlEvp op0R4HaCgMLWfaD9RiNEsSXdD3W2ZUzkTDoE5UfficEx1i1gwU0W8jjjdam2UFE0 Kxw8i4q7vlUu1Xuc1Bizu3UnK1xNo7kWKEA0B35a8fruZE2N3qNr3PTZgSYmn6AE SzY4Z6Ji6SeOUgN0L9xP/dLyzUWYEg4q2u9s3C8evJm/dWMmKNNCFEpizW07sg1v ZSv9c2gtFS/mcmtKQ8Bj2MgiyxqN7Q5UbX2jRUE9Mzx1jlKojsc5wdcrn363Ju31 +rIv7fagL6KVtAzgTB8NBpG/J5YrTarpcrpvG7YR8IXoWnf9IJpmGePnHJALi4tx U/pDwkL8epdrm7jT1h9s/a+ouzt+v/wGFp+fGJVAr0PQ47S08qGtbX6gzpf8OblY bV0l6hiDspce2SIJ8d5VRNvCcd/w8YxQWFuR7JqoIiuoazVceBduLirX2+5XAvvw uSW3gNfzzmrGXVxQRNGWXLCHNHev1mcs8aezxuDJ2xMTyKkkqlHJ2jRkEwY03Ebm cApq6wW/50M5w+N00ETO9GpaI85ZhPgic0wSJxjDq1As+gBTFZNG30u7GgPpZe97 rHqb5B0ApPYKRywfv3IPCOpHXuXRLw6E92UsSKyiCHHIFXhqvt+4Nj1iueINYSv6 G6qqQGnKtS2uQcCWmVjIoAxqIPBfIPCcpXod9TBWeAioVcmNXuIgvWSJqy1mPBrc mEmEv9B7KPhkcrDLMWzHluIS/3ds1ECLtAvQQgbPDirHpLPfVTqOrEFolXBoNlE5 0di/cjcWB4jACqTENBOI5azShNZLmxNlKE1n1ntNzyfb3Tlg5Kecgc/S99zr8Lj5 Ly7P94mKRglF83gXE2kg54HHFgH2AN78bg4AlTF7qtRG+yNcRH8i5WecOOdZJSgP u7/IBa5bzjjzedLVX+hGRFGO4Z3ZzDnCOC0jX3AY5VuuPGHCR+4JVnJC8/Pw/cp1 a1pbBOnC3p92tlRtS3grUMkeUjvJTtXDVBNUMRzs/TbqOufE9DBBlPNKlYfUuMye lJum1ey7FEu+u64lPZex11mGBaaabK1l8e6KAADECVhyJdmzqMSvHdFQFMeNhlzL Y6acX11idY3vfRdcgg31w2vUxUORCtCyUXv6E/VmskgsRIgWX4IsEszu0Qc2PABH BS71imRs1Gu/wRzPa6QQxWlZd/CoyvNxVhzq8giKJhQUekr69RuyKp3y2QTQahJ5 hHnG3qvsxuaiRjv8sFSEtbCNPNtrD6fAanXvjo0WFmcbIaKBdPrQfPgwlWvTVEY/ H10Zn6ZtAh0wna4E1WOo4OrVAv1pou/hD5qHpiUqKNEO37R90XLn3UAHtlF1HFU8 ZKZUgxXoV0gdbxU+/U3T5EZmt8PWMRTpKi41AgV/bHTdfjDpgdjh4MB+Zv802R86 s7ZyxZ9PekDHuII14z91dkfjXI/HGLNAB2ucaZ2TNqGqaZA96HnttWJCDw5dphY6 LUnlEyAz+chaBJJAQR4RJwtheLH1WBqNY3qy2NyO51lq6/e2npiOFDsmY4fwM1lA ApnqhU4it8U5HOTbBZnODGwXvzONWMK4/yiYFeCjtFoVCma13kcwL04rExeV/ZFw 1H7RDmbm9s8MDsT9KwJ5ik1mY6e36+FNnphAefCMLzSxqC+LvngQCs3jRtiphs90 jaPVh9rTw/Ye8xx27rh1QZgv7Vef6m4FYXzuWUri6vkYfXWwk5l/f3Lj+Rh3RYY8 mg9KhCbXfzUNaUmXnPuOhszzcnRqcSznMefmv+U3n0WEW6RBgSCF8ziJelxcH0dG Cc5KMRi3M6Y8nqwKFtZTr7JyQssANaNx/LKWTvgMnFU4paiaJLd01OOiYuE+flDX bXy6ayOx1Yqhzj7w9YWi1giRtGTM3ggNYn947HoqMpNjnqKHnbrUkz7ctlGS4i2M MfvwHa+TSlhD1oGrCxDOVUp60QKjRdzRBooLQ1jSEpLYXbjfQJzZ+33BNouk7u8y uSsv8epUamgV8A0X5qZOEmMn4akLZN2Ieo3UJGWwTC0PgLkSAmUo2pBiVgESnwvH iPHLdvGL7I7/kMl63TMOIa4FIWjMldTdJaxlK4LCTXQINM4MH92Gc0pkfmDPLnbZ Sbat99dGcbXu+/9gIjNzDrB3lkLEH5eAwcvn8UDKE0nOKIJjKXSyUgs8SC4Iz/xZ E9dOvN3uNEWQaVAdBcd6oS9hgYp4GKq4TWDZH/3JQitv6YZHt5PrnF4wx3ETwAE7 790jYTyI0jIBCg31C7CoX+QwAUO4vsbsypIRyEaLMI7WU8AG/XvXTmSeGi3Mft68 xy7Pe0gPLq5Zcufj6rt/TlFRLl257www95i7xFyFyV9n5iD6F/9M4HRlCrxmjWM/ VxJjIS3miJ85YD4SRK/N3Pw4CUvb+o+vIrEg5P4PZ/OR35Z6TBQ4ATqaDnRx3k18 xO3eomrUnSUTKr+Z8KkB06VvLxCGx/l9a1RHoxKLQH7radlk4F8dC3wfLnjX7f9t 3bfcfcmfUri0zYBWlzzTtsBs+9WlwQO1AokJ4+aHEXmVZh2Wh6eb2ca6qRwEorX9 KQ1eDN/IeRENStNbiclS9Su140QJmLG7SJomJr82c01iyIcvJU9iZlPekUJEncAg x7VuXanLQ1+AbTSKur+XjlDYPIkow13jKUUXT7zhZ2NJunR61zZ8SzuyO/obGDGx wkW5wBjZwA4lrxs1+kfY/QWeaS6cw8iL62IYR3sil5NJ/R+QSwkVuQFb8eKNyINX 50xHTU/1ZXziXay2bEXeGbs0zs8Au5+FC/J/PoP7FTruz2NxcHP7/egHntig+5kQ vprE7u+dHe+flkewU7X9VWPG10zYi/QBK3MYLdXRlmVBaPUSANK9Ki40R5NLKlSw 8UUPm/L5CjK29nwXRcKT/pLk+/LOHYfnJ0ike8INNHQPC0ZNYmcYc3AqVtEzvPtp FzvsfyDIFw++FVbnNFO+ZD5y4Xi7cKsb+WQEPmDHNs8iOZi9jHn71YZJStqgD+Es FgUyrb5RG4/B/8T9ftvAGWZNIrPY8/juBOyWzPtS5Kc98RcR8YyneahLDGlCMGB9 sKPP4BjshTb/hZ98o2F1WjsO4fXIM7v97e6Fsx7SPacZT7Is479GX5oJgFyNK0Lz WxqBFLcaOYYoLkjsbT1ov39W4xmgTeWeBXo+dJR1OjJ6IZrvjm+CEhiy0YsJjR2R Uqw3gYi+zkQJFNBpkmTdeLVKGNG691DcBQ5A9cZnJ8STgbKW1lp4WAzQGTaLIuRX CyRUuzfX3p9bbuLPX7j8zAtVZNFux/fKzGAnk6dnE/IEOQjHCFHF7dCDSuaJ1oZ9 ZcYmXJei71/AwMl9O0+KTTlegBc11XmiSu4H2y8vpCc+Jvj2UrpLk61C2+3fqffj S2lyxjBF67pqEhS1z3z0VrohzqVSORic7PqwU06JZeQhwAidmgS/6Qy+5xXEmW+p 1ohW4zgIMy7YFSJ/uXTk05zNz45X7mymhsvXnl5ZRazgV4ErzclKg3c4HXGEWi0V rYga8HCGcrNoSbR93uvrBo2czRxk6LGHdWXzCZfI0bQm7bJFC+j/GZQrvzB/L6FT S++GPgyTP9FbUjYfDmY0xC3S+mI2Id5qGwiyroADhuykqGBy0NYorRbXHY/TAvae trGzgD9UX+MC1XT/ZMifHk2DCmAFj0nUAqJzovWS1LB7lQjnk0FuQ3OTfiTn/n48 DinKt6gaxfyYv6plYSB7s0zJmq/6glNSgwxpbQymVq0H8GWHXnnxgJO89OBn/CHu SEIzcwVPsFBufce3EqzwsRy7/9sAn5tITZqTyrxeiWT6UaoKpSUgd3eLpCxPPLoL cpdiWGHhJgsPfojerjtrjOROosCisUyGf/Z1l1i8w/D3QFrKsb+WGWiY2M4ukbl6 G+U+t5+yuzoGOcuqBoZZbi0p1io6uKlEiZBR2GWEsXMe6W6cQnAY4cBs3XaEMJE8 KF7RuzHFL8CBHqvCzyFC+A1FlA8rRoaClfwOGYtuYkjmxOWAULzhVALLpwmSiPCJ XKrubEtktbk87hi7USFj1T4WNCjaPktDaoxjllQqqa5nvH4SAVy5GtBVtTp74Wbb gOScGbrfRHKmLBx2k/3caWNXk/Yb4uoHKu8HVI1qVgcfznpWMGqRjjbhi7spfhwa 2kh+JuippK7xLb7Bw5LobVeKkMcUYXyq4nWBqOVHB/S8qxePgafW8QE6l2EMcGLZ KRW1DaxZ8WNbRxlAFNb/PigS494hhr+PFFi/c151iHZjywF1HFrO0Iq7Dw7bfOIx MMp3FyQDb6+IDK+7hicBWPJYhUkyNrXFA5loKrPXVRZnMzPIHw9bUYxe+pjuLy4H +BRqd6fXk6iPvYklnP6soYQ3iISF41BEPcTHq9Ba9iuN76DHCteqMANAlqdgNDQn wgqwNSvmU9YX6UBCyDR01WkNrOg+X/OU/k7cRHZF2x4n3BW/KpGpdfzXeU8QqaeT e2n5OaAa1NTRBT/TzN4DJZPhgjzWLtiT9QbZzsvo67GC3cfZKi7RWlwUQkdt2Mhw IxPO+FWShDG/yrxhjGJvuV4TWM9MRo/B9J5XLU+3Xf3ZAzK7adwTJMTGlV4R1RJ9 vnA4doYbnqHofZZkCDJgxCXwwYZMDXu2BF9iUTVml284HyfBt2F2HiEg+5rGj48g 7Y9AGb8rkaRKlRE663j+6kj3R4/W6ILS2umGl65n5sErOQVmYqbq09iKT7ooIZJR KoDKfG4VAKFuwENRUsJCUewPwu40dDUy7CnV5L2cPVYFO8QM2/GFoxYNJduM1k9S Tre41bFQFclMYlo+UuOW2ZenAOyjXfsKU3iJLDTdLHTQ8tuz4PMS+IP4fiS+ptav /LvyKs20ii0PEwt6EALcA5oDvUyE1KpUkBuaRU7EIMpgUNFP88qBMMlPI3s5mpUn 2B4ZdSv5irctIKcs4aQg5LHGi+udnzmt0GcQD+309KvhpwgAuyPnrxrh/ezyaV1J vih6ONigRjZUnGxbqbymrquJ4DHsOF+byKgmh0cobYx4vYHdOxXOXqmRFcvmlj80 t7R9Xx1Af3Q+sNuvqrOvlL1s6WcC0j4mHR5k0GcbSy1bcc3fq1OXGroWAcOuYKEO 08eV4W6UmLYx4v0hCJ4FTlbUjOf6B8bJu/JAbyHc5CwQOI1QDfFdP188F6dsX+3X SgRzlg4HFSlA7IG80iOOGYxBgoEzrYNofejKtNvkrVCi4vXSNdXGK4PveDoYT3tC WE/LcwLXkjChUW/gwwet4kjns1J7nCPGo81hnPX8IjIyA6C1N5ENUcTVXA3V0K4G vFElkw41Heh2pYV7urDjbZbtRd2W09hLUOlHX8iZxK0/LXngrSGRDzCDAMmaANzC hk+XR0pwtK++jMQ8J2RRqqIYakuVW8ue8XTC7PMA/BkCEnI+pPmvYip71ab+3cts tKggPl3nIReqYIPEud+9bpwnutpm+yNMt/zTuj2pnCCuqp5ZlifLWOokyUBMyyhM GV8BGS9G6uRreO2zhN1u8IRhj+y5Bum6z44kPqNC4YSZh70p5SN9AZryVfJeLyc8 dq86jl7JqG3I6v+8CboAYu4aRxckNg1B+10IVQ2ZN8faDOKsbGiBYo2M7CAY7V0N iT2j/WLk6CAXecAINk+EFeq9GgguP3XTisW2tkQjIkZqZWObBYuRZDUqkLnrQ/p1 vXj8CqCoXAdNXaG+llbpV7v59ilIegOW8fLcxaXmK8lU4OAcnZa+We8CWzp9QHUc 6bpqFcN0ZD9Q6ojygYXEagdkJq/T3XMr6V1OecJvxwva7nzNd3q+YLnpWTRS6iCK jEXLy3RAcK2DLluG8MdWQ8uIh0Dyh1nP4jd+B04nRlG44A4FgLsytd9RKYrQdtzw uuKdjK7iPe5ln7/l6XTX2vzZcJGkLIIMFFj5295GMusnauhtCMqVQ5tZLc5Iqaq5 IMFiyTrKdUPjUpKGShZAqANhWq76X0vQKUCDFBrATPuTTuawSCWnOE7su/VKw70Q xmv3wUxWJF8H5ARMWyUreg93L79N1rolcGXj1I/SawzDGDM8A/I3UfXMhOQ+oQG4 Q4ZCML2n00zGPIvg+PsFqBsB0UtE6AAMqEtwAcezhBtMOPSdmCoiNCVnTXMZZGUT GtKUGV6CxzOa+SW6KLxCykt/LcPF4ffytAha2GEvLG/6JUGGgWWucTO5iIaN/zqi kjQ1fBc1VgPHu6tgShpD/bGBDmjDASyFgI+cphZcjgsehdXpJL/6C3egY6ijemJt rsSnbooX0Q96CIDyhxwFPXHv7jVxabiNjonxrxNXciMFuqBN6BbrJIenx701CKAK roSn83X86/h9Q/NB568NDU1codM1pRDgr0aY4jRN6j6Hy2qMb9SLFQcLR/S7zomI KR6/7T7CqW7FU9vMUHaZjVwUtb5wxxZF/G5ZKbNzKlu5TJcoo9Z1awlxXg5+icRZ aBvD0gag0xU++zLKJ0xbQYpFNd9nefgrHuKxCLNBb3NNoPxX6mXqMeYeor3BnpMy tl5Rs0obQGGTQTp7LWWdaABkdmFz9gn0RbKeAtX4k9audcVxRwLJPDxxLwTfzYxv bZSzpzIIy88IDeN4RqCQB252UTgAQQBORpy0KZOQ7ZNFCcs3+G+pcpDzl3/oB4uJ mY7y+swlgcCb91WBM8tXMm3ndI/4b1jmwNsIxWTlG5jwtaDkCofUCLluSs+As2nC ouIoNqDBpxZ6i7vCg1JfGnlL0Et+ZrIwg8GOvcjT7Rand38iqH9jDcTMzRorvhyb EpmBlAe4JVafAyvukWDt+MHut4lc9lkjSWF7X4jYvVuC/jF6fjLvni2RdVduXzFV LDi3qLRlKoj9xd2Eakx6n0SW5PEIE01D4uNqxtsUVlz/sZAHbGvXipohAMj4Yytn f6j9iGHtcnoarHcNRtkhZ4apXXT+kLc/PkF4w7Da6VN8Bu5wbZTBK3fwtnBQ91dl 7nIsoINihZkkIWPaQFVpi2fo2FZJ/LBQhupgVoGUwWd1cmTbU08ugcRyqYsO+K+F 66BWCYOqGvp+mDMXzdSs/bWwAAby5x3n7HbrcjZATc5UAHJO4viSEmQhF6r3R5a0 sO+WsQKPRmoPFpNV1dwPJ78t2KMrvomlyk6X8NoVjBXT73eIYNatGZGGnHEVnrp3 J/iWWzrSmlqwGYj9Img0G4dH/H/mA4xeatT7UJ14OIutaN88OWd5tZDIR14ZZkoM /deOz9UD+q5VFDt9ESMswM3N4uuuglOgBovNB4qqU2ag8CD2cPpDmkt09WQueJjh DIVq1q+aYpeCUEQr0RuqqJ46mFnPsqHmXV0svsXg17dgWRCTXYiPAtYy8NqAfsX3 Dku1gWVNv4zG1bGa5yPlU97VMfz4beHMJ2ts995RYs8D+d3gEQvQ2IOvN0b8D7hT J9QQXqokYl9lYSA7vq6bpCkhyycixfWtKlhy6oJJXBJ4HfOyuyi9j2NQLV/P5jR2 IqGSs0+JDEouFrmXjHK+zSnJ9/MSxv4jos1IgXo0aJh/+qSp1Sthme7jYwXy3hrK buDL9Hljc2IDma3wCeNgSrQ7qFMrNisNylX7Xg7jzHpqZmDw94KrAI3TgLwYmkHd ndkzAuq/OyZ2u4K3lvyIexZeUeYbXyCxAP72M90YaKqLcXs9zBE6AyTJt1MCxSK1 xf3ir6EwktecQDrF2qhYD3zxJyhT2mVFM1rFXWYqt0+EHF+wB8lufoh8+R8tNkJu GkHSroBdtIPelQp4pmWliYkOJCoUJB6BwLdnosoHmL0Y52npg7FIH3f+F9JK4Rr+ 2EKuyq/uFajD0Yh6yZeeRHI/ASHDTA6J/UkuZMlgkjzheVytOZ6YZ1n5dCao/2sT ic6fyFAYZr+qv6yzKcB+YmP1Z20Mn0KI1vCwCKBeXSRzOWVz9RgkFReE+ODhG74D TnbDF3EQuj1gjBXs+NL/kKQK/f5ViBA91a4YyvUVS4Xwy4A6+NWSXC12kxzbdRYg OfS3Ji2xWzL1d7Aaa+fZ2+NpmCoJDhds6jaiaSX3NZPxcVBhasYb9lmYULAuVu4p OMe8H9yCyFOoBGLORl5aW0G8iknyc+7HstH26PY32PAEMOf/COrHzc9c6x/+OPQe IKs4M5OVVXnjTsz+dQKYEEYKtg1RKIW/iuWiPvBwVrveJVwYwRFSbcsG05C/bk8K e6enK/6/clpJHj+InSdhPAtILOsS6fMtAx08Ch+zheUHtYoTZQtUvsDiWqaiEh96 OfA8ohtgZk0a3hQV82miD4qsZoi7COIHn+GpCB7fCy7DAUHJiy3UU6ZETwYNd8qU km9ouQpKEIYFb87wgLUUOaYsZV2ATU+4GTWTLvDwCe7ej97T8XO5M73SxwcGjhj0 aP9Gmhl9ulxoruNSDRQe/qU6ovSKm+RQeYssbZymnODRydJGFu4/mgWS41wUco6G 4NJLAURw86j2314LbwNmCX5T/EGZIjAndNW9NykzkMaODsgkK7K8wquEahBvVmc9 7GVpUfpT1RoyBgexwPhDFS6MmJ3Lcgz6pS1vtoopHGYuO1lZGdB0v3JnYhZpOO5d TZhptVhqfOhjQUxwQitoj4KED3tfP04kEPo4aRyLzi8ERx+14Votqkv+RmRAhaIK QnufIN0ChRyD8ffeCYHPwexPCzN7Bu+P2/5iwsmGWLpztosZDuHunao2VwKYe3G6 QG5kECQe6Pm0ML3KjPkPYYJ+p5VAKmuHnWlawYHCdgYyx7U8L2LAecBQLkGCgFaf qARMl5ZrlECeDM5fMI+Z2/vjZQMXsTBFpRIe15Yn7Wvnu/RIz6y6a3N3dLnfN18m dq0iRrx8LNCQ49KsT+wayzTUGKCvgd/DqKrJ96OZc9MmE6CJtv9Hl5X4aVhcEtSe MCVDgNzeVDD2R33MRiJy3QyAD0dhjBp//fvW5s3yWd+jhx9IVsAwa3tppR4nkzfn PHYvoaLWbkgHIZYwvoqWRRR6mIESOFfg2epfPoXhlfr0EaZtjopopFu4DHY0+WIN HkDKyXLoq11xvWNRtKmkErUbH7eEoMsiTXTE+eFbjHsUcDOcNpqh1iXxzrZBaZLo hADNkRIooK9qOAvWRxmdyJP711MwJpG3L9zHMB6LJ36P48gY6KVN6d8sNyADjqoe IdNfpDhPb4hKHG2g+ymGYeQe69TL86rtbnABNm/vJivPsyGE7OH0QY1YxAYIOfZn VtTgzeVYitWaEPOhFtsW1i1vUBPWSiE7YysYORyY5UGk5f314IWIhOLbXUnvzJLJ nlX6EAyMi7KvRYfjjn1DP9te/oNmhbcjifMItcqC1MyvxN6IA51zYHpHRfe+7ciy ilsw4I/IrIltIH/kyCJgKDM7xcCJs5uxmxy21N9WVapC2A4ijMMDfn3CXj/h8p4W +OmrWohDEjuARpty2fiwG+ryQ/c7Vesxk1pwjCp96aRz/Fxp5iJRgwuvtJYPPYqJ VZBfFoC1NKlkhvP7R1EDDQ5DXyf+aIQCp1A+hLNJ4uavZP+u+f6jJJxghlKWdLS/ BNmr7vqkcVCVDRWbiUeJ6+3JqRGuPW3qRTJILSnaRY83UUgqPcO+y20kQsO+WkzV ONWwdoZm4lHwBH7rL/2OIObkaIdDTBBkeTYONmKaE4pZREUArb9FWRGWV1svobW2 dtJyjlNP1XTLQDoVfieRKmQ4Nrxo/aawX4mAERcqHBdqcts7OIEGlwP1Ck1//MN7 ioE1egpJrgbawfjJwvzxvgHm4o/uio1BOb5m8dDMRAKaQnK4P88kxAk5EBWwzgzw 0ehlsC58CFxeXjvrB6I/cQOQj4WMRUs9C/a/X5Jr5EmpCYJsLe3nRzv167qG7W1r ulP7POVULxqVPBo9WXQP2Rn6mHc7O40+0JgrBhns+cF4MYev2hVmY5TjqeRFw06u jvoDYeQTpXbCcxodhcyigF2Ht5SgvmbR/kQ78WAtBqLIv3cqzrTVmzW7OiQwkIVv 3PTFy5F6HclTS4Y+j39zBAPQfH5Ywx+Dakvz6wUqiNFuamCc9DNvJWuNMy7Dyskn ATWx7PbAQbRA25wxTGc72DkWMygHzB6J5E8vgykVc8oWDQnFWs7gAme746QqnjCK 6D5/lr2qb2oLYdT/bpNIDVKp/O5Ugk+Sl/V+eaMsS59+4i5le2v+Np/Hl0NuEwD1 ubbG6AmHOc9Z0RR8yfIt/bmL4uYmgGmfRZp4Zr8sCEupGss1OHtKoec/DDAMoF6l 6jxwF8ocE8sjY8dZQihBeSPdg/BfPVHS9HgGEZ4YdQ/lKK2B+zbPrjuFLrxTvQJs /b6m3CMh9Gob4D7J0Mwtlyxh1c7/6ho09Kk4+EndBhn81uwfcE8FAtOZVmWlvMku zL7IYQ600/p1ismVQlZYm8f+FlKUqiaHsTIrv+wHLM5+ugA13m2OKCehi0mvSYwD OHLwx99iR4asydlw6M+vGzNSsu8iBEpLDoCKX5xiRYs0cJIScgb4Q+yoovJpK/wT Ft5R3HWq4DiLLYXamtLieTggq5nsOWQs6of4b+6L0o5084rpJCBoD8RzvgmbIW4d XS4tbNgIdhQ7ABZaIPzsryGn1KMe00/9frouni6et1697rvhimkfa27jnuhrswwm cSAB+uQs6kyqxkH7rGdNFmmwFbrXqseliJRb8lauwWTaCBfX3RfPyADZFMtTsr7z ip57ysm8ApHJNb7ieXGfqSjs+goLFs6Z6NDASU5MXxHkDkPgdvBzpWBZa8SSk60p 8WLs4JFq9O9Kjv0Y3/f5kYgelLwkY63PGkZoHW1ab/OXFN2wXNy4ddWv8uI/q3Hx jveni2HMT6fJO43RgsLssc0ugmpMlbxR6+BXkRREdIxo4fCTZViga11BmC3Xf/S5 UP2kRHBjy+BOzpCFDT/54lRQMbYmwbGzcDvgTNOOvNkXY/6V6vD9b9tntW0klTtP ID+uoDV86dS3GUMuHla7aFOXqWXVP3ZWnSeRv+2P7qsVMFaXHWwp1ugsmk0uYpaf D7+/FWjDcahBc9Tl6xbtmY+VOqroGPwND3hBwbR+59cLOoDzIKVlqMlWp0Sl79hj e2V9lwVG0n4EDkW8yPnvfc8j0pWjxZA3NHEc5dHHI3vCQV4tG6R5eDr0zfg7E6wl JO5YDobyrlLNUv+ComiRCoz9nFqvHh3Koo8G3ukFnEDH0CzlsYCpSqGv+2a28Hek U23LzKxmlneC+roHdOypKz5aGNK6AMqewjNX7CkjynkifIQHOP4fh/7QCSKb4+Na /uzLvWdllwU6UGuCB6LuAfgIaJNN2NpTJWu0vXYSKxZma+Jk+WRqjvN++9dC6eV/ bO6xN+TNcb22Sme5KXCWORAcsGpvXt1CpjSuIQ4H0s38qc89I20EMX9N3aImpAbT +L5qmOkqmYpVZ2bECQiGQO3I6iAZQOHdmb9ROYMsltJxi/b8GKOXajd5X6Fjbgkk 6muIW5eYoTnq58l9PUV+ZKX2bTZ1P5kd0PK5+d/NsoZ5kuhBI3a1lIhuV9eXL90L KV1cObUrsMrf23Q/uY8GLWDPE5Yy2W4R2duZNNHUTwp5WMTRDb4RmDLb24YHxgn7 qTrotSINn5ZVGKHVxz9Npc3mQgUVd7GqYluEOffU5QcXlR8GhixrshGUyZiFwQDG K5a++3EO982F1emdmEeH9+mNdjxTS+LjkV+2hbnVpGi/xXVKAz2Q25WRoWwTaRiE WKIRCewdNPqS2wJrK8fxWtmHIeRzQ7Yxmm7Fchtr/KgfPyr52OGBDAJ3YxxHItAv X/yMgHUe1o/3TR48zCbyJr2Q1CFruqvnh2vLdU1ws7JKSIMl4ClpiB6bWj1ggwUk /o2St82ZpVzMkg2ejzH8hELbw3qP4QSCg2ZgpkXY+KfilcCZcEkn+6vgTjyZty/h VkG63SuOGVjsoX88A27KgbJSG6O+g67MOTkhONbXzPEYEuJh+QNIi07gL4gxcto8 QpNGALBRlg9VFwoeWmbaNSVj+MxqyaPvwe2EJD+eHNxKbFpJmvJtJ3UeR1C2xPbb YA3WIM2E/5hkR9aFaG6ECfeTRmGAZc1k7dhv9klW9iIZ3PJZmjjBldcokPKLP8Sl lqnh63SUthRtMns+12+gH2QxlYWe/eFp6XizXt2TNjMkt5kOwMTQ6yWTa1AFzDlP dqT4oGnh0NAE1UtYe/dToOHclf5TUxgZb4/iL3dl1zkeiUSIX4psSDQOxPpI1Vp3 aCV2k4PeA4WEw+i9UwBVC6RZ4JWDUJEkiKmQ3Zm0o36YpxH4brkQKKl5ub7SQnYh 9ejDQQRKXX6LbSM2Xpr401BxhF0o3up8tWKAiIM4IoIkU1U0OlPB8lE/wZfpsTrH E+8Oi1pnC04JqPdHYeyRCLdMSJam15V6/mBpdxNc4OnLWXAdIIJPNPCU410ykJrO yKXrFsnO6XlqS4mJZrqshgHQmZ6RTnqf/bjZoXL7nlKfufMOcBUgZDmQZrbVQdl5 GpeBZNn+UGy/+r26eeTTxk7MBAn7QXlNGc1YAAaKt32phmMhJ75LfiNI9JOYvZzw lI4ZGyV8xZpc5y415WtrmcZuSisqBDEIuwggmVfy5QygK0JRQF3KsKX/xCfrfh85 Lk2XnsMPKyV48sk2ahA+GQHDFDVtdsHPMYXoPJcb1DP/A1LgQRGMT3D8ASfGRrjY fPi2yngJ6QBz2eyynpRDMkDpm+m6mgoqI45zq0vVkNtYTyB356s4TrZy11cQxogh lEJifUHoBFxQTuxWeZa6KgScvzMR5Xg1USqPgKKbC4LitRuf6aaRZGsA8Z3vXewG 0x/NRGpNBGK0vEYFxIqmxl5DwEyXnRHFUczZzwlMNQXD+lKtvD0Y1H7z1CzzHz1o 00/8dh45GYXwjv8lOCeiqVwBkSsbZnXsjpTJoH/yt7qsWFsfMS0J/ru3diaXFTXL ckzJxDTuEtGAPUjOMS5/PWKAu3Se5lXdsYIfDopkGCum1vT5o7sG19CWO7RSqon9 ZTcnJ8CmO0CwW92eYVtRBae6yI2DbpK25G9UH/F4fx0tTFhMlo7/gsLarLzI3vvM lRytx3S6Flfao1PYohdC06VACP7WhqW89L5OnHtI4DfjmmhEChhXtHbrq2d4BHm6 brcPahVsOZRtftB7EG3w1wldH3B+q786meMOCPgT7FrJUbJ9nb+yp4nqsSeku6J8 Htbx9rAmAAIXPvIawVFvlGH2xhW/x1eM/GOZmx06+0UeErDSesNEdghtbaa8quLd DvjbnEqXDKLPPXbuTPj8rJVQzpCRml7IHf0lFjQEmTZ6yX+2zZWXfZb7vxfeiw3p +hQVHPSKqb0aYqVe+hSquiX2PX0Ju35EHOD0xIQ9Md5Z7QQJxz8JwePHEk5OPduL wZqtqK/xgAIQ0xb7V5c4nshhcAXEOEEvj31st4cFdE/1CTUpSJflg4YE1do1co6Y hneqmIo2OclSWThvG4SDWW2OgZykhN3Sx+WVP31guWKahES2cSMlSdqB3uJ2yrjj J5/h2Z4Oe/XhUjgSrv/nDb5M5kv7OJRXIDD6cdXXpgMHWMfHroyM99ZVXAlxHvHN WGWJoO9oB1Y6Z+U3ZSrDynacexNkFrDv+ySimh0VkyWO1bWi0PGK52jhQAwWyK9i qDmigpbDavWz/5gDkaRK+OX/R7n75OgZ0GhKgKEJOqRaKxMaLo3r4jMlLO8Jz0pk aLAAH3wgOImzi/n/FmUbbdLMFORbovgCpmcuLX5cMCSaMZpr9Qv12enf8gxdzD+v LH0t0eYn18+tZUKslTDCA8D8F1++uPdHg0MSmNxdTBfIyW1MJok6z7fgNdm1svWC 742PT9H8BtOg5ZCiehbT/Tr+mVU8Pr9NjjIOx1A1mzGoeBu7IYtc+hRD7ZVFEAa9 6s3KUnxA9iKSBp55eZa8a4aiZjFmXUEbIsjA3XtvK2kf0WH/8FtcV2prnXiZcVR7 Yf7vw73jy4mZjno3avK4wxJr/QMBDo20iSj17Vlz550p8vm7vzc9an6Fzmxw8KNr yDPlJNs8rmulsqCGb4ynIHvJJ9ILDDphVPS4IjpNp3G+Qs7oT1bRt9nC4XbmrxOv gE1oFpzfzHCtRHV1VD9Sm8fafu/XV0dfivEGhMr5ycyqBqvx2V9gDW7wyUIsVmJw NtwPPEp+yBs2Brnn768AbWdahbzQJLusg1Zf8kTtKcPrv4Pekbgq5dPheceDhsb1 Cqbtd4AfryMQi0tRYDZ/P+oKKREo4fuXN1lKUwWMggZbG01/tcEIS0o7WocVwM+D UR+f36nVNpKXonXRBE6Q1DbReb6Dh07sC2MZSDiWqLy+79me+FTHqOlesOqgWNHP +z6aNMUBWWzOGJGikRJPsO99UObfH5W3nIZR9FHjIE1y0b4o3JSoEzG0TYDrVCGA +DvUC2FmR1Z0e5AabcJzB2lrHmJOaIDkVWTSI4z8zrWhh/hLrWiwkqUAbYIKgUQe QbxbnfwXUs+4/ueoSn9RoKg/IsjbFMA0esHTfojhO3g33Liw0WseTDjFOQ0Mb2NI OLD8IzJ3/Gu16L3BBf0dbjkZ58bS9BrWf869ZGb29gCF9ZbVxeZa2gA/4IRKfFxZ BGSOwoznTdO6sr2OiKnWmdEsajpSwo7T2srp3FNuSe7aMemwLyQk489hvV5DxMdi k70papTqnmCahb+/xP8J9KjhFReVvoTTw/Tg76GaLk+setBijeqbS9bh37Y0eFhq zjUdYsHqeyecqeBu/X2+uXzYSM9Tgn17PSk+cEcI//AYdOpZgSxf1JIRobEViZub tkcweXa9XL1/3bPQkq22xDA/q4EyWscKSkw3w0GNT+xfgkS6dY4D77i2zu22EgsY j6qDrsEmdbBpTIs5zaCnjOt90r9CFEs74hWHZCbV2t6sRNvzrhPy/RFbpfaY6iQ/ w8ZZ4Q6E7FMS6gyxt46cijy/AvizuNVVYUnC/H2yM8vKkkgKYiumAKk5nVDyYPzW 3v4NE6Bd0KazvsHuSKjB+RzBueAr71tbFOJSxf3xbPESVjD1A3fQIevyYjFFc1IQ VUK8fS9Bxi0awvuvME0OGX1MXC3/tCezmddzAbboAAwjNL3IRcvllMYlt4Az4NL+ 84e8u1KJ/7sEXY90prg5Sg5cQ2kpqL420WHmtAGjHcHExbraxTaDiFIsJOwaeow9 ghxXCDB0tZXtgvpObgHzbQO6uATgj5P72Mv1WV8SIBF9jQPBHcoY79NAGYzN3bJf 10c7tyZ2TqLPAR7kVV8iBfwukG0KovTcr7moTvoRDR5FE/Hu6EImDq3K2tgejUbY ZOrZULWYDnREQ6B2o9gl1lRZ/d1k2Zf9S6u5qBHRgkhp5p9JG26umTTwbK8Xn3Er bf+RlU/TtXbrrnBPhH7we1HPx7BS/UIkwALf9UjiJ/kRroSlSvnggwTURsBvRxVu kQABLbi5W/iQIWHwvYuJrL7mK4frbvwVyVQTp6n7k3XvMQZwiBz4mfSR4tDQ1w56 AtXDdT3G/Luj87IIeRLzA2gK3dBDafUp9xjlZsI/b+0tDWDoyms9Keajg50IgfUI mdVicYlC5iJMZ8vk5qzr/RiHJGXsZRE8By3e3n25qDGMLduQVZ8fjOo5WoX+O/K8 A4o7iFZc4GGHr2OfOdmYgZq1kTYbXgwmfc+cmR0vGFAhSiz95Q1AScchu6n2DmF/ icQf4kd2UT1mhs7d8rkePsEZEmhCI5Ys0LyA830UliHTg1Joe7zjmWrbxKeVIzI8 TGXkRshqhPs5dm/Nl8rl2AtMblqVT9B3C+uox5Yq1RdKFr5lAZtta5CdeOMjXIP2 d2YXa92+tvuVD6xO+cNEp1ODeV2IbU3YXQOugP0XX9BEfavvZ3yNmPZ/MTT4oO09 +p5ryCvYloyIpu/XbkQc/XF5JmOFuUsFUAqbazsIYZ4JjvqB/kQzejvzDgD3o+7P L1LDA1pX5LnFsv3TGsJbfgLvCBKRyz4TTrpGBd17irD0YDuQFDSIeKsaL7VBmnzq 9bHWwR11MBCybrA5X07F3niRRLyZ6J9RfzvV3Xdut0i6mfQJL5pIbhXmx6GLcQe1 DQvm54NzXgZ+aYP9PUyX+S2QVnYcJD92CfcJ24fmO6TJGKfOFchHTSALHZ6t2Bmw eb4MJh0klW5pIvrZMT8jLQGRMkAFENPhzolDqv+v+7qYOAbfhrSh6nPYY5faNIvm 9dby5VNj22a9XbVrOke4VDzZNM6gklSjUbhnlK4WiX+kIUbIMII= =0M/D -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFileDualOnePassphrase.asc0000664000175000017500000004650212610161626025362 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) 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 =YlwY -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFileDualSignatories.asc0000664000175000017500000004542212610161626025076 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) 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 rW5YqUDVQaR2 =/muA -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFileNoPassphrase.asc0000664000175000017500000004516312610161626024411 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) 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 =Kbhy -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testDecryptVerifyFileToString.asc0000664000175000017500000000205612610161626023546 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.9 (GNU/Linux) hQIOA5+T+RFnKO8SEAgA1bmDFmLP1hXxeURROoAY0fGpOv8CkdPUBUs9A5ERh/lg lIz5JpVqM72A/QFjg+SxLSca4Yp7RRrKHhZU3Dt+VbLKGIfCRSoZg1ob7LsQHKlb HjTUwVaRHUCl7oAqMqqnQ3BIoP0s1p4t8NafsDsoMMD4FWOhh9lI37/kQV2ZUloz Y54XiPppy9cIGLuiKmufjCp1j+/nGIgx/zWWarIMrCm3jxdbV2ZQWfNI4cYvpCvg QKCtsLUo/8ccCJa1K681E6UwEVTvk3FgGVPPDzX6eBilFI+IM1ZqRkVsmchSAzSZ B1z0wI2qOxmZs3dJEf6zfoIsNYCsdNMIiJjf22RTewf7BgkxNrRrVf43KGdxLfuv rUJf2LRDNA1S+aa1jL8cwwVw7BVFCsEU5LtdHm6LVJJYM8l023WaHsqr+d74gcWt xYnDcX8GsV/Q1LnqH/A4wh+auKpxihZxD9wNMZE7LpNIEE0u8bKlIGz3EeSpNlJN b0Bvs+HP8i2ZiizHQIrb3IC5wkzTDzt2WMmduhzEJOtxfJNf2gj/K2xT1Q+CF8bL 0el8Jc79JkfkQqPDmbREXsj4Ddd3hNKTrYvbS0pjRwvF3a1AkPfxsyjNOH9oRTF1 c908Iyy58pFz8kln8xXj1nk2aUO5REQymOiUtijkGUN4lFtS/VPtTMGCSe9o2yhs lNK7AUw+8e3ynBzffPwlqLFarkcvKTTmGxKcrkcRjirHGP4KZdfAtcschr9vDewM Z2w+CcA7mom8yeXmtVmi4MMcJkGem7VOCueK6RjHkhdd6Kcf9N/O0upUdew12Uax QOmkWykIB9IsgIiRsTAAqKAQYp2liqPZ76XRvXV4nFeRVcXQU4BcA29uZukuQe7J 6+d7nc2BE2zjw1cGEW/8Yj9RoKDExNmTwtvUob+7MKIr8veV5a7jz90hnm2gow== =PmRs -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testFileEmpty.plain0000664000175000017500000000000012610161626020673 0ustar alecalecCrypt_GPG-1.4.0/tests/data-files/testFileMedium.plain0000664000175000017500000014023412610161626021033 0ustar alecalecLorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus luctus placerat erat. Curabitur euismod arcu id eros. Maecenas accumsan pede in orci consectetuer tristique. Ut nec felis non nunc euismod ornare. Ut dui eros, euismod sit amet, condimentum nec, varius sit amet, leo. Cras ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porta. Donec neque magna, interdum eu, dictum non, viverra a, est. Praesent vel neque. Mauris vitae nunc. Praesent commodo eros eget eros. Nunc congue. Maecenas quis massa sed ante dapibus vestibulum. Sed at dui. Duis mauris nulla, sodales vel, tincidunt ut, sodales ac, tellus. Donec ullamcorper. Maecenas sollicitudin sagittis leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus leo. Maecenas posuere. Morbi massa. Maecenas dolor felis, dignissim nec, vulputate quis, auctor vel, lectus. Sed libero. Cras mi. Proin placerat libero vitae dolor. Donec non nunc vel nisi sodales facilisis. Ut a tortor vitae neque eleifend rhoncus. Suspendisse vehicula, lectus vitae elementum porta, diam eros scelerisque sem, et accumsan massa orci a urna. Vivamus posuere, massa sit amet sagittis pulvinar, leo erat congue metus, eu congue lacus tortor in mauris. Vestibulum dapibus lorem in turpis. Curabitur aliquet gravida purus. Integer quis felis at velit varius laoreet. Pellentesque aliquam consectetuer lectus. Nunc at sapien. Cras faucibus dignissim dolor. Sed id diam ac augue aliquet convallis. Proin feugiat, lectus elementum venenatis aliquet, nibh lectus porttitor tortor, sit amet aliquet erat sapien eu nulla. Morbi sagittis libero sed tellus. Sed purus turpis, sollicitudin vel, dapibus eu, vehicula vel, dui. Nullam fringilla tellus in lorem. Integer dolor. Mauris interdum tristique neque. Nullam ac magna. Nam vel eros id enim dignissim sagittis. Suspendisse pede. Aenean et lacus at sapien molestie consequat. Vestibulum sapien. Aliquam erat volutpat. Duis vel felis ac risus consequat tristique. Curabitur porta enim. Phasellus auctor consectetuer justo. Sed rhoncus congue turpis. Nam consequat massa ac elit. Nam aliquam. Nam velit. Aliquam condimentum vestibulum risus. Vivamus id nunc ut ante consequat hendrerit. Donec sit amet ante ut nisi vulputate malesuada. Aliquam id nisi at justo ornare imperdiet. Curabitur ac felis eu pede posuere pretium. Cras sed justo et enim pretium mattis. Maecenas nec metus. Fusce sed odio. Vivamus aliquam dictum nunc. Nullam aliquam magna eu massa. Etiam sit amet lacus. Duis velit mauris, ullamcorper sit amet, facilisis sit amet, ultricies id, neque. Aenean ut arcu in magna suscipit ultricies. Nulla mauris. Morbi sed purus. Maecenas vel augue id lorem tempor volutpat. Sed congue porttitor mi. Mauris fringilla magna quis enim. Sed eleifend, nibh ut ornare lobortis, augue mauris egestas sapien, sit amet rutrum risus sem non felis. Pellentesque ipsum augue, ornare et, lobortis sit amet, aliquet ac, nulla. Aliquam sit amet massa. Morbi nec odio ut diam ornare pellentesque. Etiam iaculis purus quis neque. Cras gravida velit at ante. Curabitur a justo vitae nulla molestie molestie. Pellentesque sed urna vel enim rutrum tempor. Sed lectus tortor, consectetuer ac, aliquet ac, commodo id, elit. Sed eleifend turpis. Maecenas turpis dui, vulputate in, euismod id, dignissim eget, massa. Integer id mauris. Mauris a diam. Curabitur scelerisque, arcu ac aliquet eleifend, nunc elit egestas libero, ut luctus ipsum enim in risus. Quisque a pede. Sed euismod ligula vel lectus. Aliquam erat volutpat. Curabitur quis ligula. Vivamus justo odio, scelerisque ut, feugiat id, dapibus quis, nibh. Aliquam et ante vitae risus mattis iaculis. Aenean pretium ligula et magna viverra vehicula. Proin felis. Proin malesuada fermentum sem. Vivamus suscipit. Aenean et risus. Quisque vel urna. In hac habitasse platea dictumst. Ut vel quam eu odio semper congue. Aenean pulvinar, quam eget faucibus consequat, purus est tristique tellus, quis iaculis lectus nibh a neque. Cras diam. Vestibulum est enim, pellentesque vitae, sagittis id, semper non, sem. Maecenas iaculis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam quam massa, ultricies a, tristique quis, luctus ut, enim. Ut hendrerit tellus sit amet diam. Mauris eget tellus sit amet tortor lacinia mattis. Praesent eros enim, iaculis id, ultricies sed, ultrices id, eros. Donec libero nibh, accumsan id, vehicula vel, bibendum vitae, est. Morbi ac velit vitae nibh pharetra semper. Aliquam eros turpis, porta sit amet, bibendum quis, porta vitae, ante. Fusce ac turpis nec nulla euismod fermentum. Integer imperdiet lorem consectetuer libero. Quisque luctus. Nam erat augue, ornare vitae, accumsan vitae, molestie id, massa. Integer cursus. Suspendisse libero. Nulla sed magna. Nulla suscipit, urna a varius aliquam, mi nulla posuere eros, fermentum consectetuer dui orci vel ipsum. Fusce varius erat in libero. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi lacinia. Etiam accumsan ultrices erat. Integer eu mi. In vel purus. Integer porttitor. Fusce pede enim, venenatis sit amet, varius rutrum, convallis eu, orci. Phasellus dictum lacinia ante. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut non tellus eget metus rhoncus condimentum. Praesent consequat augue eu erat. Donec accumsan, turpis a ultricies venenatis, neque tortor porta velit, sed sagittis velit sapien a tellus. Pellentesque eget diam. Phasellus luctus sagittis sem. Pellentesque ac risus. Sed ac velit. Maecenas sed justo. Sed ut sem. Morbi elit massa, pretium eget, aliquet sed, ornare ut, ligula. Etiam vitae mi eget nisi facilisis molestie. Phasellus varius mattis mauris. Suspendisse ut nunc. Praesent nec arcu. Nullam in lacus. In vitae est. In hac habitasse platea dictumst. Mauris ultrices. Nunc vulputate, augue quis imperdiet vehicula, libero orci cursus lectus, et mollis velit lorem eget lorem. Ut id dui a purus porttitor varius. Nulla neque nisl, vehicula et, venenatis at, pretium in, lectus. Pellentesque at lacus et sem dictum laoreet. Vestibulum quis mauris. Morbi fringilla cursus diam. Phasellus id neque. Aenean magna sem, facilisis non, luctus vitae, egestas a, sem. Ut lobortis urna pulvinar diam. Fusce in velit eget nibh mollis vulputate. In lorem ligula, commodo ut, tempor non, egestas quis, leo. Nullam sit amet purus. Integer pellentesque sagittis orci. Quisque neque lectus, porta euismod, tristique et, dictum ac, arcu. Mauris congue consequat dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc ut nibh nec nibh facilisis elementum. Maecenas vel metus. Etiam id orci at nulla consequat volutpat. Vestibulum vel nulla et leo sodales fringilla. Phasellus eu nisl et quam fringilla molestie. Aenean eget metus. Donec diam arcu, dignissim vitae, fermentum dictum, accumsan ac, purus. Proin tempor aliquam lorem. Nullam facilisis odio a ante. Aliquam dui. Nam id leo et massa fermentum tempus. In pellentesque elit ut metus. Fusce mollis est in libero. Donec orci nulla, scelerisque non, elementum id, semper accumsan, ante. Phasellus nec risus porta nunc molestie vulputate. Etiam justo sem, sagittis lobortis, laoreet scelerisque, ornare nec, arcu. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc laoreet sem mattis massa. Cras porttitor lectus vel metus. Integer tellus felis, sodales sed, pharetra vitae, sodales sit amet, nulla. Maecenas vulputate vestibulum nisl. Donec sollicitudin sollicitudin ante. Curabitur sed ipsum. Nunc odio eros, consequat vitae, condimentum luctus, auctor at, tortor. Morbi nisl. Vivamus gravida metus vel justo. Aliquam eget quam sed nunc faucibus vestibulum. Nullam in erat. Etiam volutpat nunc quis turpis. Pellentesque blandit. Praesent sagittis urna in orci facilisis varius. Donec ultricies. Fusce lobortis placerat urna. Quisque mattis, enim id venenatis mollis, elit metus ultrices quam, id commodo libero nisi sit amet sapien. Quisque sagittis porta odio. Maecenas ac tellus. Etiam ornare nibh eu arcu. Quisque euismod facilisis lorem. In mauris. Vivamus urna. Sed nisi. Curabitur convallis ultrices arcu. Nullam sit amet mi. Donec at arcu. Etiam hendrerit. Phasellus ullamcorper, orci nec fringilla convallis, felis purus tempor eros, tempor venenatis massa velit sit amet velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec libero. Fusce aliquet. Suspendisse at purus in augue lacinia tincidunt. Vivamus tempor pellentesque mi. Aenean consectetuer ultrices ligula. Nam turpis nisl, congue at, semper vel, dictum nec, elit. Sed lorem odio, bibendum eget, dignissim sit amet, cursus vel, erat. Donec cursus nisi ut lorem. Morbi quam mauris, hendrerit nec, egestas congue, placerat ac, nisi. Morbi auctor, risus in pharetra ullamcorper, enim tortor vulputate massa, ac interdum est libero ac purus. Mauris faucibus turpis a lacus. Proin pharetra magna vitae est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin iaculis, tortor sed pharetra sodales, turpis nunc mattis neque, ac porttitor ipsum lacus et tortor. Nulla eleifend luctus nisl. Nulla fermentum elementum dui. Cras dictum sem vel lorem. Nam pulvinar, elit in hendrerit hendrerit, turpis arcu accumsan sem, id elementum lorem ante ut augue. In pulvinar lacus sit amet nisl. Aenean venenatis, tortor at hendrerit venenatis, dui erat posuere urna, eget pharetra diam dolor pulvinar tortor. Pellentesque consectetuer. Sed orci. Morbi lacus ante, mattis et, ultrices sed, scelerisque sed, pede. Nulla eu nisl dapibus purus fermentum varius. Etiam rutrum vestibulum sem. Fusce libero. Duis laoreet. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum arcu nisi, mattis vitae, blandit non, venenatis eu, purus. Fusce fringilla, dui id iaculis luctus, mauris ipsum vulputate libero, quis posuere lectus ante a arcu. Mauris imperdiet libero venenatis odio. Integer varius laoreet turpis. Vivamus fermentum. Vivamus dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur at diam. Nulla suscipit gravida erat. Nulla enim massa, bibendum ut, pellentesque id, sollicitudin sollicitudin, massa. Integer varius, arcu ut condimentum commodo, neque neque blandit pede, vitae adipiscing tortor nibh eget sapien. Proin volutpat urna eu diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed quam pede, gravida sed, semper eu, fringilla quis, sapien. Fusce tincidunt nisi. In eros odio, vestibulum et, dapibus quis, tincidunt ac, est. Fusce eget purus id leo adipiscing varius. Fusce euismod lorem id turpis. Phasellus tincidunt blandit sapien. Integer sagittis orci at pede. Aliquam accumsan. Morbi ac orci sit amet magna scelerisque dignissim. Quisque vitae lacus quis neque convallis ultrices. Vestibulum ac arcu at mauris ultricies mollis. Nam id nulla. Nunc sed ligula. Sed nulla lectus, hendrerit ut, convallis ac, dapibus nec, odio. Ut blandit sapien nec libero. Duis tempor fermentum pede. Suspendisse imperdiet tincidunt risus. Integer lacus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque id odio eu nibh placerat adipiscing. Suspendisse quis leo eu velit laoreet hendrerit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec euismod nibh nec leo. Nullam sagittis fermentum ligula. Sed feugiat cursus elit. Pellentesque id tortor. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec vulputate leo ut neque rhoncus tristique. Aenean molestie, nisi a venenatis accumsan, mauris risus interdum tortor, et laoreet velit metus quis dui. Ut sed nunc. Quisque tempor. Suspendisse metus lectus, congue id, blandit quis, cursus eget, urna. Sed ac purus. Suspendisse sed eros sit amet risus eleifend pellentesque. Donec diam. Vestibulum vel mi. Aenean sagittis magna quis libero. Nunc scelerisque gravida metus. Aliquam nulla ante, rutrum vitae, vehicula et, pharetra sed, nunc. Nulla nulla enim, commodo vel, euismod id, convallis at, purus. Nulla pulvinar. Praesent et elit eget justo varius laoreet. Nunc ornare feugiat nisi. Aliquam vel felis eget erat semper sagittis. Aenean vel nisi. Aenean vehicula adipiscing enim. Nulla at sem. Sed commodo pretium erat. In turpis. Cras ullamcorper, magna non placerat vehicula, lacus justo condimentum leo, a tempus lorem leo vel nisl. Aliquam ut magna. Donec eu neque. Nunc semper quam vel est. Quisque eros tellus, vehicula sit amet, ultricies ac, facilisis vitae, dui. Morbi gravida, ligula vitae vestibulum facilisis, metus ipsum fermentum nunc, sit amet vehicula nisi urna non nunc. Ut non est vitae urna bibendum faucibus. Praesent at risus. Morbi nisi ante, ultrices tincidunt, accumsan et, lobortis quis, ligula. Proin nec est. Ut varius mollis dui. Etiam tortor purus, facilisis quis, viverra id, tincidunt vitae, dolor. Sed ullamcorper. Ut nec lacus. Phasellus ut metus a felis vulputate sagittis. Praesent magna. Morbi pretium placerat pede. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam at tortor sit amet sapien adipiscing lacinia. Aenean vitae enim. Vivamus adipiscing, mauris vel venenatis scelerisque, leo ligula lacinia orci, sed commodo dui nisi sit amet leo. Integer a est sed lacus pretium accumsan. Mauris scelerisque pulvinar leo. Vivamus tristique dui ut est convallis consequat. Phasellus turpis pede, fringilla non, sodales vitae, eleifend ac, lectus. Vestibulum eget nisi sed eros dapibus pretium. Fusce tincidunt pretium neque. Aenean elementum pulvinar lorem. Vivamus sit amet velit. Mauris quis arcu. Curabitur pede purus, suscipit sed, elementum in, dignissim at, dolor. Morbi eu odio. Ut ipsum nibh, egestas eu, tincidunt quis, lacinia quis, lorem. Vestibulum sollicitudin sapien a dolor. Mauris sit amet augue in diam condimentum semper. Etiam est. Fusce sit amet leo eget elit fermentum faucibus. Praesent ipsum quam, tristique ut, tempor eu, facilisis sed, sem. In vitae nisl. Nunc et pede vel augue malesuada tincidunt. Nulla felis. Etiam vel dui et nibh fringilla rutrum. Duis aliquet dui. Proin sed turpis ac tortor aliquet porttitor. Pellentesque congue venenatis est. Vestibulum in libero ut nulla condimentum porta. Aliquam erat volutpat. Vestibulum tincidunt. Donec at augue eu risus cursus venenatis. Suspendisse potenti. Ut consequat sem. Aliquam gravida est ac eros. Vestibulum sit amet mauris non diam tincidunt condimentum. Pellentesque commodo egestas diam. Phasellus semper risus at tellus. Duis eu enim. In ac augue sit amet sapien commodo tincidunt. Morbi convallis enim non tortor. Aliquam turpis. Quisque tellus nisi, porttitor in, consequat in, elementum quis, ipsum. Nulla id turpis ac nisi sagittis luctus. Praesent ipsum magna, vehicula at, luctus nec, accumsan convallis, odio. Curabitur non augue et risus commodo laoreet. Suspendisse commodo lacus sit amet orci. Pellentesque molestie tristique arcu. Aliquam erat volutpat. Praesent sit amet lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ornare risus in tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi luctus, nisl id laoreet aliquam, eros leo sagittis pede, vel venenatis dui odio venenatis quam. Quisque justo justo, lacinia sed, facilisis vel, dictum eu, erat. Proin ligula dolor, dapibus id, pellentesque id, consequat et, erat. In posuere. In sed est. Nam volutpat orci id nibh. Morbi convallis magna vitae mauris. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas felis. Donec condimentum. Sed pretium eros et est. Curabitur vel mauris. Sed tellus. Aliquam tristique facilisis metus. Nulla elit justo, sollicitudin eget, pulvinar eget, hendrerit vitae, est. Nulla semper dolor sed lorem. Morbi nisl. Proin pretium, ligula vitae pretium congue, turpis lacus bibendum magna, suscipit aliquet odio ligula nec risus. Mauris vestibulum. Pellentesque vehicula dolor sed nibh. Pellentesque id massa. Mauris sit amet justo quis turpis mollis tempor. Nullam vulputate velit at pede. Aenean fringilla ultrices magna. Proin urna tellus, faucibus in, blandit in, iaculis blandit, quam. Vestibulum turpis. Donec ornare aliquet justo. Integer velit. Sed at felis a arcu viverra congue. Suspendisse laoreet tortor at diam. Suspendisse quis arcu eget sapien condimentum molestie. Proin iaculis aliquet ipsum. Curabitur lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque in tortor. Curabitur imperdiet. Maecenas bibendum vestibulum nibh. Nullam vehicula lectus ac lectus. Morbi et lorem. Aenean sed metus. Cras commodo. Vestibulum a tortor. Duis pede nulla, posuere nec, hendrerit quis, faucibus id, nisl. Integer id purus nec quam aliquet ornare. Fusce euismod nibh ultricies pede. Quisque eget est hendrerit arcu mattis sollicitudin. Vestibulum viverra, lectus porta scelerisque venenatis, elit diam tempor ipsum, eu euismod nulla tortor eu orci. Praesent vulputate arcu vel magna. Maecenas blandit lectus. Aenean nunc orci, ornare vel, aliquam molestie, mattis non, sem. Fusce ac turpis et felis suscipit sodales. Nunc sollicitudin feugiat mi. Sed mattis fringilla magna. Quisque ut purus. Nunc tempus velit sed quam. Quisque mollis laoreet lorem. Integer eu augue. Morbi lobortis urna aliquam est. Maecenas eu tortor. Etiam commodo porta lectus. Ut vehicula, lorem id congue ultricies, augue ante pellentesque mauris, quis bibendum ante dui a dui. Aliquam varius mauris et neque. Vivamus consectetuer mauris eu elit. Cras vel nisi. Cras mollis sapien vitae tortor. In quis sem. Sed malesuada, eros non bibendum viverra, leo turpis iaculis ligula, nec auctor enim sapien nec magna. Vestibulum cursus, risus quis tempus aliquet, pede magna volutpat diam, tempor rutrum dolor dui a lacus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum euismod varius elit. Fusce et erat a leo ultrices semper. Vestibulum a ante quis neque lacinia laoreet. Nullam nisi ipsum, vulputate a, molestie quis, ornare sed, felis. In posuere ligula non odio. Nulla eleifend viverra arcu. Sed mollis metus ac massa. Quisque vitae tortor sed est laoreet sagittis. Donec et justo. Pellentesque porta mauris ut turpis. Ut diam. Nulla neque lacus, commodo egestas, iaculis quis, porta a, nibh. Integer ultricies, libero quis hendrerit imperdiet, quam purus consequat ligula, vitae dignissim elit nisl non turpis. Morbi ut orci in diam luctus convallis. Vivamus ligula. Sed magna leo, aliquam at, hendrerit ac, feugiat non, justo. Sed lectus. Suspendisse elementum pretium tellus. Aenean egestas. Aenean faucibus porta purus. Nullam lorem dolor, iaculis vel, lobortis et, euismod a, eros. Donec eget mi. Sed vitae ligula eu massa cursus luctus. Nunc ullamcorper. Nunc purus nulla, feugiat et, vestibulum quis, hendrerit at, tellus. Sed risus massa, porttitor elementum, rutrum a, posuere sed, nulla. Etiam blandit egestas ligula. Proin rutrum dolor at odio. Quisque et nunc. Maecenas sed dolor. Donec suscipit mattis magna. Donec sit amet leo. Aenean lobortis dolor non elit. Cras vulputate consequat tortor. Etiam sodales porttitor ante. Morbi ut leo quis lacus lobortis eleifend. Nunc fermentum, nisl sit amet pretium egestas, velit eros tincidunt lectus, non vulputate ipsum urna vitae erat. Integer sit amet sem quis turpis varius posuere. Proin in metus vitae neque commodo tincidunt. Praesent iaculis fringilla justo. Vestibulum nec sapien. Curabitur eros. Duis commodo, diam non congue imperdiet, risus nisl auctor nunc, eget sodales magna sapien egestas sem. Vivamus id mauris. Phasellus dapibus, lectus at ornare lacinia, mauris sem imperdiet ligula, bibendum imperdiet lorem dolor at purus. Quisque ultrices nisi at augue viverra scelerisque. In vel risus. Fusce quam diam, luctus a, pharetra ac, tempor ac, lectus. Fusce neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam eget augue. Quisque in tellus vel lorem vulputate iaculis. Integer a pede. Integer vulputate molestie lorem. Donec velit magna, iaculis id, pretium in, aliquam nec, felis. Fusce nec libero sed velit egestas molestie. Maecenas turpis tortor, molestie in, hendrerit eu, tempor sed, enim. Fusce non orci. Suspendisse eleifend neque vitae odio. Quisque bibendum, justo a tristique gravida, sapien ante adipiscing nisl, non vehicula purus mi sit amet metus. Donec pharetra, felis nec interdum imperdiet, dui ipsum tempus diam, ac aliquam lorem libero vel nunc. Integer tincidunt adipiscing risus. Maecenas ante. Nunc vestibulum, nibh nec laoreet commodo, nibh erat tempor erat, ultricies mattis pede turpis luctus leo. Phasellus egestas ligula ac massa. Quisque tincidunt, erat ut volutpat ornare, neque eros tristique ante, sit amet bibendum turpis enim eget lectus. Pellentesque hendrerit lorem sed sem. Pellentesque semper elit non velit. Mauris nisl. Proin sed pede ac est mollis vestibulum. Nullam faucibus, lectus vel mollis accumsan, ipsum massa porta quam, id egestas turpis ante quis sapien. In aliquam ipsum in neque. Quisque id sapien. Morbi vitae elit. Nam leo eros, ullamcorper at, molestie a, mattis sit amet, augue. Pellentesque convallis suscipit elit. Nulla viverra. Nam ut erat. Duis metus. Mauris neque. Nulla eu odio elementum dolor adipiscing tincidunt. Aenean convallis, eros quis hendrerit luctus, dui tortor hendrerit ipsum, nec egestas nisl leo id tellus. Praesent eu turpis non tellus sodales semper. Duis quis enim sed nunc vulputate posuere. Proin leo. Proin mi risus, dapibus id, pretium sed, pharetra eget, diam. Aenean risus lacus, placerat quis, dictum dapibus, ullamcorper at, ipsum. Ut egestas sem sed quam. Nullam gravida lectus sed mauris condimentum accumsan. Nam ac pede. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris varius bibendum ligula. Aenean neque. Nulla facilisi. Sed ultricies, lorem laoreet tempor ultricies, erat pede volutpat nibh, eget blandit quam massa hendrerit dolor. Fusce consectetuer, mauris id cursus eleifend, justo libero ultricies sapien, sed consectetuer odio mi eget elit. Vestibulum id arcu. Etiam tortor erat, accumsan vitae, pulvinar a, fringilla non, ligula. Maecenas venenatis semper urna. Quisque ac dolor. Nulla tellus. Quisque varius. Vestibulum non lacus. Phasellus iaculis. Duis pede. Praesent viverra lacus quis massa. Mauris eget dui. Proin aliquam, mauris eu dapibus viverra, pede nibh accumsan enim, sit amet aliquet nibh diam bibendum est. Nam dui. Morbi porta. Fusce scelerisque turpis ac arcu. Quisque quis erat. Nam sodales tellus et velit. Morbi vel arcu. Vivamus at nibh at odio congue scelerisque. In hac habitasse platea dictumst. Maecenas sed dui. Nulla turpis. Nulla rhoncus, quam lobortis tempor convallis, justo diam tristique erat, ut lobortis massa pede id magna. Donec purus. Cras tempus ligula eget nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse adipiscing sapien vitae enim. Donec egestas metus at sem. Sed in massa. Proin vulputate risus et nunc. Cras ut purus. Ut posuere semper eros. Praesent diam. Donec at lectus ac odio fringilla mollis. Mauris pede eros, faucibus in, cursus sit amet, adipiscing eget, ipsum. Donec malesuada laoreet purus. Sed mauris tellus, scelerisque eget, semper quis, vulputate non, leo. Sed quis dui sit amet enim facilisis faucibus. Sed sem. Quisque sit amet odio. In pellentesque scelerisque elit. In hac habitasse platea dictumst. Maecenas mattis massa quis lectus. Nam arcu. Nulla accumsan magna et ipsum. Donec felis erat, tristique ut, tincidunt a, elementum quis, metus. Aliquam erat volutpat. Vivamus ut orci pulvinar nisl condimentum varius. Etiam condimentum dui quis lectus. Donec ut sem sed nisl dictum pulvinar. Maecenas arcu enim, pretium vel, tincidunt quis, tristique pharetra, risus. Suspendisse pede lorem, luctus et, eleifend vitae, eleifend et, purus. Cras pretium est at tortor. Aenean ac ipsum et dolor dictum suscipit. Donec et magna vitae lectus malesuada facilisis. Cras dignissim. Morbi eget purus. Nulla in tellus. Ut turpis. Nunc imperdiet. Donec pretium pellentesque diam. Aliquam dapibus. Cras eu tellus ut erat tristique pretium. In hac habitasse platea dictumst. Phasellus lobortis. Proin a enim malesuada nunc luctus suscipit. Maecenas eu risus imperdiet ligula hendrerit tincidunt. Nunc egestas varius turpis. Proin sollicitudin ipsum. Maecenas hendrerit vehicula mi. Morbi sed magna eu libero egestas imperdiet. Fusce ullamcorper ultricies quam. Morbi quis ligula. Aliquam erat volutpat. Sed luctus. Duis eu risus. Mauris et turpis quis nisl sagittis lacinia. Aenean faucibus venenatis risus. Morbi tempor condimentum dolor. Integer sapien sem, scelerisque quis, tincidunt ut, fringilla sed, eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec eu lectus. Suspendisse malesuada leo eu ipsum. Aliquam condimentum nisi eget turpis. Ut nulla turpis, scelerisque in, rutrum in, sodales eget, turpis. Nullam pharetra euismod odio. Proin elit risus, pharetra vitae, ullamcorper in, posuere nec, magna. Donec semper lectus at sem. Morbi vitae libero. Quisque erat lectus, tempor vel, venenatis sed, dictum placerat, mauris. Integer malesuada. Quisque eget lacus. Aenean vitae enim in odio congue scelerisque. Fusce pellentesque accumsan erat. Praesent ante velit, sodales eget, tincidunt in, ullamcorper et, nisi. Sed vulputate. Sed fringilla, libero at aliquam tincidunt, odio lacus sagittis lectus, in volutpat est dui ornare nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Etiam id ligula sed ante congue pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur ornare adipiscing tellus. Suspendisse mattis. In vel elit laoreet dolor placerat elementum. Integer auctor nunc non tortor. Fusce accumsan metus vel tortor. Suspendisse vehicula mi vitae magna. Donec in purus vel libero hendrerit rutrum. Nunc rhoncus sapien ac sem. Nullam convallis malesuada arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum sapien. Cras sem. Sed enim metus, porttitor in, imperdiet eget, placerat ac, sem. Mauris ipsum. Maecenas vitae lacus. Sed semper facilisis velit. Nam dignissim, felis sit amet tempus lobortis, libero metus dictum nisi, sit amet suscipit lorem odio non justo. Curabitur euismod, purus ac ornare egestas, orci massa tincidunt metus, et porta nulla nulla fringilla nibh. Aliquam id ipsum. Maecenas ac lorem. Nullam diam tellus, ornare ornare, convallis id, iaculis vitae, mi. Phasellus hendrerit. Cras malesuada pulvinar felis. Nunc id turpis vitae nisl vestibulum sollicitudin. Fusce elit risus, posuere vitae, mollis ac, commodo placerat, libero. Integer libero ipsum, congue ac, placerat non, sagittis nec, nibh. Vivamus sagittis, quam nec ullamcorper malesuada, libero magna dapibus dolor, in ornare enim leo non est. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec elit. Curabitur tempor sem vel lorem. In ullamcorper. Curabitur eu odio id mi commodo pulvinar. Nam ut nisi. Nulla consequat lorem ac lectus feugiat elementum. Integer tincidunt, leo et eleifend tempor, augue ipsum ullamcorper sem, pulvinar faucibus velit lectus a dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec mi sit amet lacus facilisis porttitor. Nam orci ante, dapibus eget, interdum in, hendrerit eu, augue. Aenean vehicula, ligula in porttitor volutpat, dui lectus mollis metus, sit amet tincidunt orci enim at nulla. Proin vestibulum vehicula orci. Aliquam erat volutpat. Fusce sit amet erat. Vivamus vestibulum pellentesque lectus. Fusce magna ante, pharetra quis, molestie sed, molestie vel, massa. Donec in erat at nunc sollicitudin euismod. Nunc et massa ut quam posuere vehicula. Cras fringilla ante vitae orci. Vestibulum mattis congue ligula. Duis eu pede eu odio tristique sodales. Curabitur sagittis venenatis ipsum. Etiam vitae lacus a mauris feugiat ultricies. Nulla convallis tortor et erat. Nunc nunc. Phasellus porta eros at dolor. Morbi placerat. Aenean non ipsum in libero euismod euismod. Maecenas vel justo. Proin sit amet orci adipiscing tellus tincidunt interdum. Pellentesque euismod nulla vitae est placerat lacinia. Donec malesuada, elit laoreet tincidunt sodales, lorem ligula consectetuer purus, ut rutrum mi neque eu sem. Phasellus ac odio. Vivamus lobortis. Aliquam erat volutpat. Nullam rutrum ipsum in dolor. Nullam vel libero. Duis lacinia lectus vel lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed sodales dolor. Proin rhoncus, lectus pharetra faucibus facilisis, diam ligula hendrerit leo, ac aliquet sem ipsum id arcu. Ut non erat eu risus ornare rhoncus. Mauris non lorem ut magna convallis rutrum. Integer est purus, venenatis in, euismod quis, feugiat vitae, leo. Suspendisse laoreet tellus eleifend neque. Sed vitae arcu nec pede tempus hendrerit. Mauris commodo, leo ultricies venenatis consectetuer, turpis tellus hendrerit diam, eget lacinia diam tortor in leo. Etiam luctus orci ut sem. Donec sed mi sit amet erat pharetra ullamcorper. Phasellus dolor diam, euismod et, pharetra ut, convallis sed, orci. Nam vitae lorem. Vivamus et nulla. Suspendisse vel tellus sed quam blandit rhoncus. Proin convallis erat vel dolor. Proin ut leo. Quisque ut pede non augue vestibulum egestas. Donec interdum justo eget dui. Nunc malesuada neque et felis. Donec eu dolor. Aenean in dolor vehicula diam bibendum auctor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed molestie laoreet nisi. Mauris condimentum magna quis massa. Nulla faucibus. In leo. Morbi vitae dolor. Aliquam erat volutpat. Sed euismod. Fusce pede. Nullam ipsum mauris, ultricies tempor, laoreet eu, pretium ac, sem. Praesent accumsan risus quis mi. Curabitur id nisi. Fusce imperdiet. Proin vitae velit. Vivamus eget urna vitae metus ultrices sodales. Mauris vel mi. Phasellus nisi metus, auctor sed, facilisis id, volutpat a, nisi. Nulla sagittis. Duis vitae nisl. Phasellus felis tortor, cursus vitae, convallis et, fringilla egestas, eros. Pellentesque nunc lectus, mattis laoreet, sollicitudin eu, imperdiet auctor, quam. In hac habitasse platea dictumst. Integer lectus nibh, tincidunt accumsan, sagittis nec, viverra vel, pede. Integer porttitor varius nulla. Aenean consectetuer leo a nunc. Suspendisse vel risus. Pellentesque sed eros. Aenean consectetuer diam ac diam. Sed varius semper tellus. Mauris condimentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam eget enim. Vivamus felis ante, porttitor a, cursus eget, cursus eu, quam. Aliquam consequat consectetuer lectus. Cras non tellus. Aliquam bibendum hendrerit ipsum. Phasellus auctor ullamcorper nunc. Suspendisse tempor neque at sapien. Quisque malesuada libero quis ipsum. Sed pellentesque pellentesque est. Aenean rhoncus magna eget arcu. Praesent dignissim. Duis magna. Praesent nunc nibh, sagittis vitae, iaculis sed, facilisis a, orci. Nunc eu lectus id velit porta commodo. Aliquam a tortor. Nullam hendrerit lacinia velit. Curabitur et velit ac libero tempus sollicitudin. Praesent aliquam dui eu enim. Aliquam erat volutpat. Duis quis risus. Sed sit amet metus eget odio porta iaculis. Duis lacinia, nibh vel hendrerit malesuada, odio quam eleifend sem, non aliquam nisi lectus ut nisl. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus sodales. Cras euismod ligula quis velit egestas commodo. Vestibulum vulputate ornare quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus convallis ligula id nunc. Nam consequat felis condimentum pede. Etiam nec risus. Mauris vehicula laoreet enim. Quisque nisl urna, tincidunt eget, congue non, rhoncus eu, odio. Ut quis velit. Aenean semper purus in tellus. Duis sagittis auctor sapien. Ut dapibus mi in lorem. Ut nunc. Phasellus id purus. Etiam ultrices. Sed nec nisi. Praesent ac augue nec turpis sodales cursus. Praesent et quam et turpis tempor mattis. Ut a velit eget enim feugiat pharetra. Cras blandit enim non ante. Aliquam erat volutpat. Quisque nulla arcu, eleifend ac, mollis a, congue at, leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin malesuada imperdiet sem. Cras a justo. Suspendisse volutpat mi in nunc. Vestibulum placerat sagittis arcu. Vivamus pede. Vivamus ultrices risus at leo. Nulla egestas adipiscing mi. Quisque cursus mi non arcu. Nulla congue. Donec dictum imperdiet diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin quis mi. Duis odio. Morbi tincidunt enim in mauris. Duis mi enim, dapibus a, suscipit ac, porttitor eu, leo. In aliquam, dolor vitae congue hendrerit, lacus risus consequat risus, ut molestie mauris purus a ligula. Nullam sit amet diam. Etiam congue malesuada dolor. Integer dictum. Fusce facilisis. Quisque neque velit, feugiat a, egestas quis, tempor a, magna. Fusce ligula. Praesent tincidunt mollis diam. Aenean libero neque, suscipit nec, volutpat in, ultrices sed, turpis. Etiam consequat bibendum arcu. In turpis. Pellentesque et odio. Proin ac lectus vitae elit malesuada sodales. Aenean bibendum enim ut nulla. Suspendisse turpis est, tempus non, cursus eget, pulvinar eget, nibh. Aliquam erat volutpat. Etiam risus urna, accumsan vel, pellentesque in, commodo sit amet, nisl. Nulla eget sem sed nulla porta egestas. In tempus est nec justo. Aenean placerat. Aenean commodo nulla nec magna commodo luctus. Nunc mollis sem sed metus. Sed vitae libero et felis varius dapibus. Maecenas at orci. Etiam quam turpis, interdum vel, interdum vitae, dapibus sit amet, pede. Suspendisse consectetuer velit dictum arcu. Vestibulum dui dolor, vehicula et, ultricies ut, facilisis et, enim. Duis eu neque id diam tempus ornare. Phasellus luctus faucibus ante. Morbi id enim ut dolor interdum volutpat. Nam non nunc. Nulla sagittis enim vitae mi. Fusce sit amet odio. Nulla elementum, massa ac tempus suscipit, leo magna tristique urna, ac gravida eros nisl sit amet est. Curabitur posuere mattis mauris. Integer pellentesque sodales velit. In scelerisque metus. Suspendisse potenti. Duis felis. Nunc vitae enim eget metus tempus egestas. Suspendisse potenti. Integer viverra sollicitudin nunc. Curabitur lectus. Sed faucibus. Fusce justo. Nulla facilisi. Donec viverra lorem sit amet ipsum aliquet imperdiet. Maecenas quis est. Cras nibh nisi, pellentesque sit amet, porttitor vitae, adipiscing vitae, massa. In hac habitasse platea dictumst. Etiam dignissim. Integer neque libero, consectetuer quis, egestas sit amet, feugiat sed, tellus. Nullam sagittis erat id purus. In erat pede, cursus ut, posuere eu, laoreet non, urna. Sed elit enim, placerat eu, rutrum non, consectetuer vel, purus. Curabitur eget magna. Phasellus ultrices velit at ipsum. Praesent posuere consectetuer lorem. Donec dapibus libero a eros. Phasellus convallis luctus quam. Vestibulum est dui, viverra id, feugiat eu, malesuada eget, mi. Fusce bibendum arcu vitae justo suscipit ullamcorper. Sed a augue rutrum nisi gravida volutpat. Maecenas consequat rutrum felis. Aliquam neque libero, dignissim ut, ullamcorper vel, luctus eu, enim. Donec mollis consectetuer ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur sed nulla ac libero dapibus pretium. Proin auctor imperdiet justo. Curabitur est mauris, tristique a, rutrum vel, vulputate vitae, augue. Proin purus nulla, pharetra id, faucibus quis, venenatis a, nunc. Sed tincidunt elementum turpis. Mauris nibh tellus, accumsan et, mattis eu, pulvinar eget, sem. Nulla facilisi. Mauris pulvinar dignissim eros. Fusce nec orci vitae lectus feugiat lobortis. Etiam velit turpis, aliquam sit amet, lacinia eu, mattis ut, ipsum. Praesent ut massa a quam scelerisque gravida. Suspendisse ullamcorper faucibus pede. Vivamus turpis. Mauris suscipit. Integer vel dui. Curabitur a enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut dapibus molestie dolor. Curabitur at mauris. Nullam luctus risus ut lectus. Phasellus imperdiet tellus et massa. Cras vulputate, arcu sit amet tempor suscipit, libero orci pharetra nibh, in pharetra massa lorem nec mi. Aenean sodales auctor orci. Aliquam euismod tincidunt velit. Maecenas urna nulla, congue dapibus, semper at, faucibus ultricies, dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis tincidunt aliquam nisl. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce commodo, eros ut adipiscing luctus, libero risus mollis ipsum, et vulputate lorem purus vel lacus. Nullam lectus neque, vehicula eget, eleifend ac, aliquet eu, enim. Praesent orci tellus, convallis vitae, aliquet eget, suscipit vel, ligula. Curabitur eleifend elit non sem. Fusce ut quam. Mauris at ipsum eget justo mattis pretium. Phasellus eu enim. Vestibulum suscipit purus at libero. Fusce vitae leo. Aenean cursus. Nunc ullamcorper augue nec enim. Fusce et est sit amet nisl sodales volutpat. In malesuada enim sed mauris. Aliquam et felis. Pellentesque euismod consequat erat. Aliquam pharetra diam sed erat. Nullam placerat, neque quis condimentum semper, lectus purus auctor metus, nec luctus nibh lectus in elit. Nullam faucibus pellentesque nunc. Suspendisse potenti. Curabitur commodo metus eu odio. Nulla porttitor consequat diam. Nam pretium ornare ante. Integer congue, elit ut commodo pellentesque, lectus urna luctus felis, et rhoncus magna libero pretium est. Mauris diam. Curabitur fringilla justo vel tortor. Mauris justo eros, adipiscing non, laoreet et, mattis in, tortor. Vestibulum vel justo non augue lacinia sollicitudin. Duis et libero eu nibh adipiscing sollicitudin. In sem. Quisque dictum ultrices lacus. Mauris quis orci. Ut aliquet eros ut mauris. Pellentesque ultrices. Aliquam erat volutpat. Nullam feugiat blandit lacus. Fusce vulputate, ante sit amet eleifend viverra, arcu augue feugiat urna, porttitor interdum sem ligula cursus sapien. In vitae augue nec sapien tincidunt dignissim. Morbi tincidunt aliquet mauris. Donec pellentesque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras ligula sem, eleifend sit amet, iaculis quis, varius ut, ante. Morbi dapibus eleifend magna. Nullam dapibus rhoncus tellus. Nam quis tortor. Cras arcu nunc, sagittis eu, malesuada varius, tempus et, lorem. Etiam sit amet metus. Praesent arcu. Aenean et metus. Quisque sem enim, posuere id, feugiat nec, gravida ut, neque. Maecenas semper, justo sit amet dapibus dapibus, purus justo facilisis purus, non fringilla eros ligula a neque. Donec nisi. Integer mattis, lacus in ullamcorper lobortis, risus massa aliquet ligula, eget auctor leo orci sit amet nisi. Aenean diam. Ut tristique quam eu velit. Curabitur sed mi eget arcu sodales aliquet. In sed risus. Sed et mi. Etiam sagittis enim tincidunt est. Cras vel est vel eros tincidunt consectetuer. Etiam eu sapien ac orci vestibulum dapibus. Sed ut est eu est euismod hendrerit. Pellentesque vitae orci non libero varius dignissim. Praesent iaculis, ligula id euismod interdum, lacus risus porttitor quam, a adipiscing mi augue at diam. Nulla iaculis iaculis turpis. Vivamus nec nunc quis libero ornare ullamcorper. Praesent imperdiet posuere dui. Etiam vulputate vestibulum urna. Cras cursus hendrerit ipsum. Praesent felis ante, posuere sed, mattis quis, sollicitudin ut, lorem. Donec nec odio. Sed luctus odio eu risus. Sed sem nisl, tincidunt quis, hendrerit et, facilisis non, mauris. Aliquam non felis. Integer sed lacus vitae dolor pulvinar condimentum. Etiam lobortis, libero quis tincidunt lacinia, nibh nisi iaculis quam, eu condimentum massa purus a turpis. Suspendisse potenti. Morbi vitae lacus ac tellus pulvinar mollis. Nam auctor fringilla sem. Morbi lacus elit, pellentesque at, mattis nec, volutpat feugiat, lectus. Phasellus eros ligula, molestie at, pulvinar id, eleifend vel, ante. Fusce facilisis, diam luctus interdum condimentum, libero justo venenatis tellus, molestie ullamcorper ante diam ac sem. Pellentesque tempus, ligula ac pellentesque vulputate, eros velit aliquet lacus, eu dignissim urna leo a diam. Suspendisse quam ipsum, ullamcorper sed, dignissim vehicula, facilisis ut, tellus. Fusce convallis, odio a malesuada pharetra, orci risus sagittis urna, sit amet tincidunt ligula pede vitae leo. Quisque augue. Phasellus scelerisque nisl sed purus malesuada pretium. Pellentesque condimentum tempus ipsum. Vivamus auctor metus sed sapien. Nulla tristique congue magna. Vestibulum iaculis urna ac risus. Nullam fringilla suscipit ipsum. Quisque euismod. Quisque ullamcorper pede tincidunt risus. Sed tortor pede, rutrum ac, varius sed, sagittis nec, orci. Phasellus arcu orci, bibendum quis, tempus id, consequat eu, velit. Phasellus commodo congue purus. Sed malesuada, pede eu volutpat tristique, tellus mauris vulputate nibh, a faucibus lorem enim nec nulla. Nunc semper, nisl iaculis rutrum consectetuer, leo eros egestas lacus, sit amet venenatis dolor ligula non lorem. Morbi feugiat. Donec vulputate. Vivamus at sapien sit amet est feugiat elementum. Donec nisl erat, tincidunt ornare, pellentesque vel, aliquet sit amet, eros. Duis sagittis porta sapien. Etiam a dui. Praesent lobortis nisl at lorem. Sed malesuada. Morbi viverra dui eu neque. Nullam sed ante sed diam malesuada vehicula. Morbi ut metus et dolor hendrerit vehicula. Integer in lacus nec dui aliquet dictum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse et mauris vitae dui lacinia ultrices. Mauris neque sem, sagittis sed, lobortis viverra, pharetra vitae, mi. Nam dui nunc, iaculis id, dictum at, porttitor vitae, diam. Donec tincidunt leo quis augue varius rhoncus. Nam risus. Vivamus dignissim. Praesent viverra, neque vitae vulputate blandit, dui massa rhoncus lectus, quis accumsan neque quam sit amet augue. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut congue pellentesque velit. Vivamus at elit. Cras risus metus, elementum ut, tristique nec, commodo in, sapien. Etiam metus. Maecenas congue, justo vitae egestas volutpat, orci quam aliquam mi, vitae pulvinar tortor pede vel nunc. Integer mollis, massa sit amet vestibulum fringilla, nulla tortor pretium nibh, eget porttitor nisi elit sit amet magna. Proin dignissim, nisl eget posuere posuere, velit diam ultrices turpis, a lacinia nunc dolor quis odio. Nulla egestas. Nam consectetuer. Pellentesque enim libero, viverra eget, dapibus ut, iaculis ac, neque. Donec vel tortor. Sed eu urna ut libero pharetra viverra. In hac habitasse platea dictumst. In dictum. Morbi non magna sit amet elit dictum facilisis. Sed ultrices porta urna. Vivamus tincidunt. Ut ante orci, pellentesque a, aliquet ut, dignissim eu, velit. Integer ultrices congue felis. Sed faucibus vestibulum augue. In lectus urna, vulputate non, dignissim id, placerat in, ante. Aenean mi erat, eleifend at, faucibus in, gravida eget, massa. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse potenti. Donec dignissim elit vel felis. Vestibulum gravida tortor ut massa. Nulla facilisi. Nulla imperdiet urna sed nibh. Suspendisse volutpat, nulla eget dignissim elementum, leo velit bibendum leo, ac viverra mi nisl nec mi. Vivamus et libero vel erat mattis semper. Cras hendrerit porttitor sapien. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc elementum condimentum orci. In hac habitasse platea dictumst. Donec massa quam, laoreet in, sagittis nec, porta eu, tortor. Integer eget dui. Nulla quis purus in justo tristique adipiscing. Ut eleifend placerat orci. Sed neque. Sed ultrices eros vitae eros. Praesent venenatis laoreet orci. Vivamus non elit. Aliquam varius tellus non erat. Vivamus ullamcorper magna sit amet lectus. Mauris venenatis, elit vel lobortis dapibus, eros lacus feugiat erat, in tincidunt dui libero a orci. Duis non nisi. Nulla aliquet, nunc vel vestibulum lobortis, est lorem luctus mi, ut sodales felis dolor vitae dolor. Fusce eget felis. Pellentesque tempus eros ut justo. Curabitur aliquet. Duis rutrum sapien sit amet lectus. Curabitur tellus. Nulla laoreet sapien at ante. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce lacinia venenatis sem. Mauris sagittis. Proin posuere nibh id pede. Maecenas hendrerit placerat nisi. Sed vitae justo quis ante pellentesque sollicitudin. Morbi in est. Nulla velit nibh, tempus non, tincidunt eget, ornare at, dui. Praesent fringilla magna id magna tincidunt mattis. Morbi vestibulum. Donec ut nisl. Duis turpis nulla, feugiat vel, commodo at, hendrerit eu, purus. Cras nec libero. Nullam vestibulum dolor et metus scelerisque vestibulum. Aliquam sed felis. Nulla dolor diam, placerat vitae, gravida eget, tincidunt consectetuer, pede. Maecenas auctor, felis vulputate placerat sollicitudin, sapien purus dapibus purus, condimentum sollicitudin sapien purus eget magna. In at est a mi placerat congue. Maecenas et leo. Praesent ac nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vel mi quis lacus congue consequat. Duis laoreet ipsum et odio. Duis pede orci, aliquam eget, rutrum et, faucibus tincidunt, dui. Donec aliquet enim vitae diam. In hac habitasse platea dictumst. Integer pede. Phasellus feugiat ullamcorper sem. Maecenas eu turpis. Maecenas dapibus leo varius neque. Mauris convallis, velit ut interdum pulvinar, est dolor elementum lacus, ut placerat neque est at dolor. Donec aliquet purus. Etiam quam urna, pharetra ut, consequat at, lacinia at, velit. Curabitur metus lacus, tincidunt sit amet, pharetra non, suscipit vel, quam. Ut lacus ante, ullamcorper porta, malesuada venenatis, vulputate et, dui. Nam posuere lacus eu urna. Sed ac erat vel nisl venenatis pharetra. Nullam egestas lectus non lorem. Maecenas mi neque, sodales a, ullamcorper aliquam, semper in, elit. Donec nec risus ultricies libero tincidunt accumsan. Sed rutrum neque tristique lacus. Fusce nulla ligula, vulputate et, pellentesque eget, varius ut, odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In quis risus non pede egestas imperdiet. Maecenas faucibus, purus id pulvinar sagittis, libero arcu pharetra lacus, sit amet auctor lorem tortor non urna. Suspendisse semper, sem vitae consectetuer molestie, nunc erat feugiat quam, non placerat augue mauris eu metus. Aliquam eleifend, justo sed ullamcorper auctor, elit sem rhoncus turpis, quis pellentesque nibh risus at enim. Cras dui. Vestibulum eget dolor. Sed faucibus. Praesent a odio feugiat quam scelerisque egestas. Fusce a ante non ante blandit congue. Aenean vestibulum. In hac habitasse platea dictumst. Ut consequat. Nam tincidunt est nec libero. Maecenas quis odio eu nisl vulputate pretium. Phasellus fermentum feugiat metus. Curabitur convallis fermentum erat. Donec ac lorem sit amet augue fringilla fringilla. Vestibulum neque ligula, consequat vitae, gravida posuere, vulputate ut, metus. Suspendisse potenti. Phasellus blandit. Quisque commodo odio at mi ultricies aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec condimentum, leo ac aliquam vehicula, metus augue lacinia tellus, ut dictum nisl orci ac neque. Nam a tellus. Praesent vitae nisl non augue laoreet adipiscing. Nullam at justo sed dolor placerat mattis. Nam varius nisl et urna. Sed bibendum, augue lobortis vestibulum ornare, nibh odio pharetra purus, quis eleifend est sapien sit amet lorem. Aenean viverra ante non libero. Ut posuere. Mauris arcu lacus, sodales in, condimentum ac, accumsan vitae, mi. Aliquam sodales dignissim purus. Donec at arcu. Vestibulum eleifend. Pellentesque dui. Phasellus sem. Sed ornare nisi lobortis ligula. Etiam est. Etiam leo lorem, auctor ut, molestie facilisis, tristique eu, sem. Morbi lorem. Mauris pede dolor, aliquam bibendum, facilisis sed, vehicula eu, nibh. Integer aliquet. Aliquam posuere, odio in sollicitudin luctus, nibh arcu vulputate mauris, sit amet eleifend risus magna ut leo. Nullam consectetuer semper dui. Donec dignissim justo interdum nisl vestibulum egestas. Donec sit amet arcu nec tellus sollicitudin eleifend. Ut auctor leo eget turpis. Integer commodo mattis neque. Vivamus vitae orci. Morbi quam quam, convallis vel, dignissim pretium, ultricies eu, dolor. Cras non est quis nisl faucibus sodales. Mauris euismod vulputate mauris. Duis vehicula feugiat orci. Nulla facilisi cras amet. Crypt_GPG-1.4.0/tests/data-files/testFileSmall.plain0000664000175000017500000000003312610161626020653 0ustar alecalecHello, Alice! Goodbye, Bob!Crypt_GPG-1.4.0/tests/data-files/testImportKeyFile_private.asc0000664000175000017500000000365412610161626022737 0ustar alecalec-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG v1.4.6 (GNU/Linux) lQHhBEjS+OIRBACPl023p+jInWiUtc7zSBU1D4mv42zSOwPdC37Pn/4x9FyhIOXE LCRTpsnAw9rT6R3BvAC4uO68fxjxFCwTpsa60RsHw4bwpSAYuf0t5Xg+GQIritlm XHVYwku3Hkh4Svv0quemooGuJ9lLwIHacL/4W1dTHLB2rzon0T4kx7ExZwCg/XKl RD9zbbnQOgjn0EaS8fcSm+ED/1IMfkCz5ac9Y3jBUlcArOZcOlTrzxst+iMZm4f0 fh8dFCCaRN0iaVLSdCNaFvbKbJYZad1w3jFAMU9bX83flqgV1wMPO/NenfMidBIq sKzgttaQo5VmjWPtwyOJXODR2lHKQR2hFCkIKlHMPLV3awCGV8iTyiTZMJirdtvf s26oA/9STYro+yB9yrHufdfjM1u8SbSIhK6jUoq2ajLPHaLF2nRZZyv1gnkzRFd+ /Vxcx6cwp8Qd6L4z+0sU3pMS4X8rt2vqilK2msg1VrHnjGgFIfmfIvY5EmrhNzEx 6X82fbR9f8lwLy5N/gPm326e0xSw1rWdR15VukJPbmK6nf/pL/4DAwIZF3WLmXaM DGCHa6b36T1VZ+bgYYcoQUanh3OSfLO0NwJ5ywFiML26DYZ7M3aivlfXj/8lOKy0 8tcg/rRcUHVibGljIE9ubHkgVGVzdCBLZXkgKGRvIG5vdCBlbmNyeXB0IGltcG9y dGFudCBkYXRhIHdpdGggdGhpcyBrZXkpIDxwdWJsaWMtb25seUBleGFtcGxlLmNv bT6IYAQTEQIAIAUCSNL44gIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEKuo HvVOjA3r8DYAn1/DrF5jw31P3L6MlWdelLuR4POnAJ9It7IynfJalYIHoAWtY2xk kTsT+p0CYgRI0vjoEAgAp65R578Es8qtASDAgIbYfJlJTwMovEnA4KJ69mpVt3mz cFWMtJCvuilvwSQQ+VfKxjemtbe/IbMe9ssj4nTSLw/mweUB89tRj8ZzaS+/9312 AS8ra/xIDr6kTSfKcRKjXgMzkJ+A13rYwG5LFWnyumg36xglmzXKhecEkRVPfWn3 ISoq3zirZlQOWcKYdyA2Z685SKJC/N+3nUqKOJ7qrA7eT608LFksytBHeOfNf5m7 CC4wAE3RAz+ZkJvWRbE2G5pUalZktq8uKMT5WQgvuFP3hnvku5yilpo2ELTnYkO3 ltc3NHCc9v+jhikayPr7RvUdVPbaITT80yYKBPygCwADBggApzR1vW/fvzmrO5pW zAvd4umVh/Yp34n3vWyXMu+JIHA7s08rkTzlMXzamICQmkjwAuCwJt0t7BA28Lny goh2joxo8tE/OowFk+IzbeA2Vrz71d/T5SMDtC2mePE0m3bmCOLBscu5aJIfgi1X /fzr44f4i+6hqVDCuOOmnVtbL4xBBnS6KXdcWP7QbVhxG3SpH9Agd/QXvSQm0Obz 9iKZ11FEXzgnVZGXaCM0GBsFE9JuNY5+hi6A72rccjhC0V1Cy43veeIhOE+v3pK0 a/BGUlgDSdgVopE9zUSQwzuo87UbY3EoDWBqDRSRCRMfmv8S2b9VJIRPdCOHZGCI R49/0f4DAwIZF3WLmXaMDGCvSMKxFAt3zGZVEsfwS67ilWw0kq9wgmDpTmbrz1pe 8tUgmHxgiVc3Xo86ItXGr69udzSODYw2wO6JGdgOKsZDKAv7zJHi+3GISAQYEQIA CQUCSNL46AIbDAAKCRCrqB71TowN6zbAAJ4qBrdmAYuAbY5txsc+Tmv9quOpzwCW NN5B7Vl2JdxBuwWJrdfUb9UQzw== =51qc -----END PGP PRIVATE KEY BLOCK----- Crypt_GPG-1.4.0/tests/data-files/testImportKeyFile_public.asc0000664000175000017500000000334712610161626022542 0ustar alecalec-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.6 (GNU/Linux) mQGiBEjS+PgRBADbDdRN9iwESSyJvjnfgk7ZWUYKdHdSER7yJ0aM4LQjVDdw9y/f QGidipXxVD2lW28gRtzcmLufxv3DzjZp83VaXvlJs9jbTtHDIYFyDW9kH1HTRbZT WKWfuInd0AXzHy5o77qQ+mW0AIXbyke5suSHdvcmv1hiWI9OnXcIHpmavwCgt4Hm +j3FpRo9qs4fJM887c796qUD/iPkStU9sM/0KCJFZNaPCGBaamCEi7UoAHNlim+B dv3rfSQ2VcDRq9/3GoCEJ2c62XpgQxt79mojJLdWZsTWvr6ESnWOm7W6GIjv/Zc3 +OXgi7QdH5nwpZl6kBMkuzZxczFuwh9dqlXml+bND0JawS38MvQpDUkwMb592v5U i9WIBADBacg6nixiTR+4kaHFE1Ww8QxT+vQ4S1SOx47cm8R6FxTRQA7FvK+vMxCt Ps9GOzhjrCgIoF/6X10IZ7qB5jCYIH+kvHrp90ZbNwJ4pIa7phCPhqUF9mEyMbC2 AEIGp/Aw26yXKskQJJ3vFji+VaeCui21sXjg5EHfoayt79xT8bRfRXh0ZXJuYWwg UHVibGljIEtleSAoZG8gbm90IGVuY3J5cHQgaW1wb3J0YW50IGRhdGEgd2l0aCB0 aGlzIGtleSkgPGV4dGVybmFsLXB1YmxpY0BleGFtcGxlLmNvbT6IYAQTEQIAIAUC SNL4+AIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJECaKtxA0NeZdqHwAn3AF EEhX1Tyba0ovCV2DwUytKM0CAKCnu6VzRy1Y8jp9fiy3ScwmaCI3FbkCDQRI0vj8 EAgArBRh0YpPhE1vvKoPuhGDa//96YqrYt9rmBo3AR1WmF3CKtspjXdOK2bCqdJh H6kaoNi+0Ors00n2NfPj9Am2cTV3h2/KpAWOxQGfkmpzU3xXTVCUo/HoKDXIfWqk /TPXRqbwFV489GRBtVov4IoZM0KqZXhaFD6cXBsEl/BVSvVdBqmBzUoJ2bOzYiSW eg/ml65jbtxjDYMbxTLi7xRcTSAsareoN6/PcbAvcCE5UeCMu8p52wxHOTrAkI4/ 6elpziVpIGn07zJb//4qIoZdhIzwfsMl73tPfdoL9jEC66SiWAN+BEDxceGR5E15 2WsT5tkxuz/pQUC1L3JW4WCC/wADBwf8CsevcPsk2XxT2XZj0lfmAOuhXxuqBczW TXCimnRxvC8+uAacv1RgVRH6emW3BVjt0dr9vwRT0n54JA+7ZwXVMOo4/tqNwmJs C6SThBXGBQxEaZwv19WC58DjblbvYa81cUaXrUdHi1OyoHwgalx0xZQ57IUXW6+7 qdLRfzyqbDBph9ogB0ta3AhSikAqqYImTrI650v/KWBLjrI+N925r0TvnfSOsru7 JrftccY2LntVnQUcXjuaFViZ7y8ocW8f92zmGj2zUN8z2GsMKiGQtNNmoX51TcQl sJPsZF0RKduVkNUQa9cfzSIMjjhUSzspA2qHLUKafrS3e38s2Y4CNIhJBBgRAgAJ BQJI0vj8AhsMAAoJECaKtxA0NeZdOFQAn15X+eYzFgVERrFkddsHvAE00OnSAJ9h A7Lcv7M+9WeZ6cjeHkZfLB6LLA== =AV/P -----END PGP PUBLIC KEY BLOCK----- Crypt_GPG-1.4.0/tests/data-files/testVerifyFileClearsignedData.asc0000664000175000017500000014061012610161626023453 0ustar alecalec-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus luctus placerat erat. Curabitur euismod arcu id eros. Maecenas accumsan pede in orci consectetuer tristique. Ut nec felis non nunc euismod ornare. Ut dui eros, euismod sit amet, condimentum nec, varius sit amet, leo. Cras ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porta. Donec neque magna, interdum eu, dictum non, viverra a, est. Praesent vel neque. Mauris vitae nunc. Praesent commodo eros eget eros. Nunc congue. Maecenas quis massa sed ante dapibus vestibulum. Sed at dui. Duis mauris nulla, sodales vel, tincidunt ut, sodales ac, tellus. Donec ullamcorper. Maecenas sollicitudin sagittis leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus leo. Maecenas posuere. Morbi massa. Maecenas dolor felis, dignissim nec, vulputate quis, auctor vel, lectus. Sed libero. Cras mi. Proin placerat libero vitae dolor. Donec non nunc vel nisi sodales facilisis. Ut a tortor vitae neque eleifend rhoncus. Suspendisse vehicula, lectus vitae elementum porta, diam eros scelerisque sem, et accumsan massa orci a urna. Vivamus posuere, massa sit amet sagittis pulvinar, leo erat congue metus, eu congue lacus tortor in mauris. Vestibulum dapibus lorem in turpis. Curabitur aliquet gravida purus. Integer quis felis at velit varius laoreet. Pellentesque aliquam consectetuer lectus. Nunc at sapien. Cras faucibus dignissim dolor. Sed id diam ac augue aliquet convallis. Proin feugiat, lectus elementum venenatis aliquet, nibh lectus porttitor tortor, sit amet aliquet erat sapien eu nulla. Morbi sagittis libero sed tellus. Sed purus turpis, sollicitudin vel, dapibus eu, vehicula vel, dui. Nullam fringilla tellus in lorem. Integer dolor. Mauris interdum tristique neque. Nullam ac magna. Nam vel eros id enim dignissim sagittis. Suspendisse pede. Aenean et lacus at sapien molestie consequat. Vestibulum sapien. Aliquam erat volutpat. Duis vel felis ac risus consequat tristique. Curabitur porta enim. Phasellus auctor consectetuer justo. Sed rhoncus congue turpis. Nam consequat massa ac elit. Nam aliquam. Nam velit. Aliquam condimentum vestibulum risus. Vivamus id nunc ut ante consequat hendrerit. Donec sit amet ante ut nisi vulputate malesuada. Aliquam id nisi at justo ornare imperdiet. Curabitur ac felis eu pede posuere pretium. Cras sed justo et enim pretium mattis. Maecenas nec metus. Fusce sed odio. Vivamus aliquam dictum nunc. Nullam aliquam magna eu massa. Etiam sit amet lacus. Duis velit mauris, ullamcorper sit amet, facilisis sit amet, ultricies id, neque. Aenean ut arcu in magna suscipit ultricies. Nulla mauris. Morbi sed purus. Maecenas vel augue id lorem tempor volutpat. Sed congue porttitor mi. Mauris fringilla magna quis enim. Sed eleifend, nibh ut ornare lobortis, augue mauris egestas sapien, sit amet rutrum risus sem non felis. Pellentesque ipsum augue, ornare et, lobortis sit amet, aliquet ac, nulla. Aliquam sit amet massa. Morbi nec odio ut diam ornare pellentesque. Etiam iaculis purus quis neque. Cras gravida velit at ante. Curabitur a justo vitae nulla molestie molestie. Pellentesque sed urna vel enim rutrum tempor. Sed lectus tortor, consectetuer ac, aliquet ac, commodo id, elit. Sed eleifend turpis. Maecenas turpis dui, vulputate in, euismod id, dignissim eget, massa. Integer id mauris. Mauris a diam. Curabitur scelerisque, arcu ac aliquet eleifend, nunc elit egestas libero, ut luctus ipsum enim in risus. Quisque a pede. Sed euismod ligula vel lectus. Aliquam erat volutpat. Curabitur quis ligula. Vivamus justo odio, scelerisque ut, feugiat id, dapibus quis, nibh. Aliquam et ante vitae risus mattis iaculis. Aenean pretium ligula et magna viverra vehicula. Proin felis. Proin malesuada fermentum sem. Vivamus suscipit. Aenean et risus. Quisque vel urna. In hac habitasse platea dictumst. Ut vel quam eu odio semper congue. Aenean pulvinar, quam eget faucibus consequat, purus est tristique tellus, quis iaculis lectus nibh a neque. Cras diam. Vestibulum est enim, pellentesque vitae, sagittis id, semper non, sem. Maecenas iaculis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam quam massa, ultricies a, tristique quis, luctus ut, enim. Ut hendrerit tellus sit amet diam. Mauris eget tellus sit amet tortor lacinia mattis. Praesent eros enim, iaculis id, ultricies sed, ultrices id, eros. Donec libero nibh, accumsan id, vehicula vel, bibendum vitae, est. Morbi ac velit vitae nibh pharetra semper. Aliquam eros turpis, porta sit amet, bibendum quis, porta vitae, ante. Fusce ac turpis nec nulla euismod fermentum. Integer imperdiet lorem consectetuer libero. Quisque luctus. Nam erat augue, ornare vitae, accumsan vitae, molestie id, massa. Integer cursus. Suspendisse libero. Nulla sed magna. Nulla suscipit, urna a varius aliquam, mi nulla posuere eros, fermentum consectetuer dui orci vel ipsum. Fusce varius erat in libero. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi lacinia. Etiam accumsan ultrices erat. Integer eu mi. In vel purus. Integer porttitor. Fusce pede enim, venenatis sit amet, varius rutrum, convallis eu, orci. Phasellus dictum lacinia ante. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut non tellus eget metus rhoncus condimentum. Praesent consequat augue eu erat. Donec accumsan, turpis a ultricies venenatis, neque tortor porta velit, sed sagittis velit sapien a tellus. Pellentesque eget diam. Phasellus luctus sagittis sem. Pellentesque ac risus. Sed ac velit. Maecenas sed justo. Sed ut sem. Morbi elit massa, pretium eget, aliquet sed, ornare ut, ligula. Etiam vitae mi eget nisi facilisis molestie. Phasellus varius mattis mauris. Suspendisse ut nunc. Praesent nec arcu. Nullam in lacus. In vitae est. In hac habitasse platea dictumst. Mauris ultrices. Nunc vulputate, augue quis imperdiet vehicula, libero orci cursus lectus, et mollis velit lorem eget lorem. Ut id dui a purus porttitor varius. Nulla neque nisl, vehicula et, venenatis at, pretium in, lectus. Pellentesque at lacus et sem dictum laoreet. Vestibulum quis mauris. Morbi fringilla cursus diam. Phasellus id neque. Aenean magna sem, facilisis non, luctus vitae, egestas a, sem. Ut lobortis urna pulvinar diam. Fusce in velit eget nibh mollis vulputate. In lorem ligula, commodo ut, tempor non, egestas quis, leo. Nullam sit amet purus. Integer pellentesque sagittis orci. Quisque neque lectus, porta euismod, tristique et, dictum ac, arcu. Mauris congue consequat dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc ut nibh nec nibh facilisis elementum. Maecenas vel metus. Etiam id orci at nulla consequat volutpat. Vestibulum vel nulla et leo sodales fringilla. Phasellus eu nisl et quam fringilla molestie. Aenean eget metus. Donec diam arcu, dignissim vitae, fermentum dictum, accumsan ac, purus. Proin tempor aliquam lorem. Nullam facilisis odio a ante. Aliquam dui. Nam id leo et massa fermentum tempus. In pellentesque elit ut metus. Fusce mollis est in libero. Donec orci nulla, scelerisque non, elementum id, semper accumsan, ante. Phasellus nec risus porta nunc molestie vulputate. Etiam justo sem, sagittis lobortis, laoreet scelerisque, ornare nec, arcu. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc laoreet sem mattis massa. Cras porttitor lectus vel metus. Integer tellus felis, sodales sed, pharetra vitae, sodales sit amet, nulla. Maecenas vulputate vestibulum nisl. Donec sollicitudin sollicitudin ante. Curabitur sed ipsum. Nunc odio eros, consequat vitae, condimentum luctus, auctor at, tortor. Morbi nisl. Vivamus gravida metus vel justo. Aliquam eget quam sed nunc faucibus vestibulum. Nullam in erat. Etiam volutpat nunc quis turpis. Pellentesque blandit. Praesent sagittis urna in orci facilisis varius. Donec ultricies. Fusce lobortis placerat urna. Quisque mattis, enim id venenatis mollis, elit metus ultrices quam, id commodo libero nisi sit amet sapien. Quisque sagittis porta odio. Maecenas ac tellus. Etiam ornare nibh eu arcu. Quisque euismod facilisis lorem. In mauris. Vivamus urna. Sed nisi. Curabitur convallis ultrices arcu. Nullam sit amet mi. Donec at arcu. Etiam hendrerit. Phasellus ullamcorper, orci nec fringilla convallis, felis purus tempor eros, tempor venenatis massa velit sit amet velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec libero. Fusce aliquet. Suspendisse at purus in augue lacinia tincidunt. Vivamus tempor pellentesque mi. Aenean consectetuer ultrices ligula. Nam turpis nisl, congue at, semper vel, dictum nec, elit. Sed lorem odio, bibendum eget, dignissim sit amet, cursus vel, erat. Donec cursus nisi ut lorem. Morbi quam mauris, hendrerit nec, egestas congue, placerat ac, nisi. Morbi auctor, risus in pharetra ullamcorper, enim tortor vulputate massa, ac interdum est libero ac purus. Mauris faucibus turpis a lacus. Proin pharetra magna vitae est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin iaculis, tortor sed pharetra sodales, turpis nunc mattis neque, ac porttitor ipsum lacus et tortor. Nulla eleifend luctus nisl. Nulla fermentum elementum dui. Cras dictum sem vel lorem. Nam pulvinar, elit in hendrerit hendrerit, turpis arcu accumsan sem, id elementum lorem ante ut augue. In pulvinar lacus sit amet nisl. Aenean venenatis, tortor at hendrerit venenatis, dui erat posuere urna, eget pharetra diam dolor pulvinar tortor. Pellentesque consectetuer. Sed orci. Morbi lacus ante, mattis et, ultrices sed, scelerisque sed, pede. Nulla eu nisl dapibus purus fermentum varius. Etiam rutrum vestibulum sem. Fusce libero. Duis laoreet. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum arcu nisi, mattis vitae, blandit non, venenatis eu, purus. Fusce fringilla, dui id iaculis luctus, mauris ipsum vulputate libero, quis posuere lectus ante a arcu. Mauris imperdiet libero venenatis odio. Integer varius laoreet turpis. Vivamus fermentum. Vivamus dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur at diam. Nulla suscipit gravida erat. Nulla enim massa, bibendum ut, pellentesque id, sollicitudin sollicitudin, massa. Integer varius, arcu ut condimentum commodo, neque neque blandit pede, vitae adipiscing tortor nibh eget sapien. Proin volutpat urna eu diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed quam pede, gravida sed, semper eu, fringilla quis, sapien. Fusce tincidunt nisi. In eros odio, vestibulum et, dapibus quis, tincidunt ac, est. Fusce eget purus id leo adipiscing varius. Fusce euismod lorem id turpis. Phasellus tincidunt blandit sapien. Integer sagittis orci at pede. Aliquam accumsan. Morbi ac orci sit amet magna scelerisque dignissim. Quisque vitae lacus quis neque convallis ultrices. Vestibulum ac arcu at mauris ultricies mollis. Nam id nulla. Nunc sed ligula. Sed nulla lectus, hendrerit ut, convallis ac, dapibus nec, odio. Ut blandit sapien nec libero. Duis tempor fermentum pede. Suspendisse imperdiet tincidunt risus. Integer lacus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque id odio eu nibh placerat adipiscing. Suspendisse quis leo eu velit laoreet hendrerit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec euismod nibh nec leo. Nullam sagittis fermentum ligula. Sed feugiat cursus elit. Pellentesque id tortor. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec vulputate leo ut neque rhoncus tristique. Aenean molestie, nisi a venenatis accumsan, mauris risus interdum tortor, et laoreet velit metus quis dui. Ut sed nunc. Quisque tempor. Suspendisse metus lectus, congue id, blandit quis, cursus eget, urna. Sed ac purus. Suspendisse sed eros sit amet risus eleifend pellentesque. Donec diam. Vestibulum vel mi. Aenean sagittis magna quis libero. Nunc scelerisque gravida metus. Aliquam nulla ante, rutrum vitae, vehicula et, pharetra sed, nunc. Nulla nulla enim, commodo vel, euismod id, convallis at, purus. Nulla pulvinar. Praesent et elit eget justo varius laoreet. Nunc ornare feugiat nisi. Aliquam vel felis eget erat semper sagittis. Aenean vel nisi. Aenean vehicula adipiscing enim. Nulla at sem. Sed commodo pretium erat. In turpis. Cras ullamcorper, magna non placerat vehicula, lacus justo condimentum leo, a tempus lorem leo vel nisl. Aliquam ut magna. Donec eu neque. Nunc semper quam vel est. Quisque eros tellus, vehicula sit amet, ultricies ac, facilisis vitae, dui. Morbi gravida, ligula vitae vestibulum facilisis, metus ipsum fermentum nunc, sit amet vehicula nisi urna non nunc. Ut non est vitae urna bibendum faucibus. Praesent at risus. Morbi nisi ante, ultrices tincidunt, accumsan et, lobortis quis, ligula. Proin nec est. Ut varius mollis dui. Etiam tortor purus, facilisis quis, viverra id, tincidunt vitae, dolor. Sed ullamcorper. Ut nec lacus. Phasellus ut metus a felis vulputate sagittis. Praesent magna. Morbi pretium placerat pede. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam at tortor sit amet sapien adipiscing lacinia. Aenean vitae enim. Vivamus adipiscing, mauris vel venenatis scelerisque, leo ligula lacinia orci, sed commodo dui nisi sit amet leo. Integer a est sed lacus pretium accumsan. Mauris scelerisque pulvinar leo. Vivamus tristique dui ut est convallis consequat. Phasellus turpis pede, fringilla non, sodales vitae, eleifend ac, lectus. Vestibulum eget nisi sed eros dapibus pretium. Fusce tincidunt pretium neque. Aenean elementum pulvinar lorem. Vivamus sit amet velit. Mauris quis arcu. Curabitur pede purus, suscipit sed, elementum in, dignissim at, dolor. Morbi eu odio. Ut ipsum nibh, egestas eu, tincidunt quis, lacinia quis, lorem. Vestibulum sollicitudin sapien a dolor. Mauris sit amet augue in diam condimentum semper. Etiam est. Fusce sit amet leo eget elit fermentum faucibus. Praesent ipsum quam, tristique ut, tempor eu, facilisis sed, sem. In vitae nisl. Nunc et pede vel augue malesuada tincidunt. Nulla felis. Etiam vel dui et nibh fringilla rutrum. Duis aliquet dui. Proin sed turpis ac tortor aliquet porttitor. Pellentesque congue venenatis est. Vestibulum in libero ut nulla condimentum porta. Aliquam erat volutpat. Vestibulum tincidunt. Donec at augue eu risus cursus venenatis. Suspendisse potenti. Ut consequat sem. Aliquam gravida est ac eros. Vestibulum sit amet mauris non diam tincidunt condimentum. Pellentesque commodo egestas diam. Phasellus semper risus at tellus. Duis eu enim. In ac augue sit amet sapien commodo tincidunt. Morbi convallis enim non tortor. Aliquam turpis. Quisque tellus nisi, porttitor in, consequat in, elementum quis, ipsum. Nulla id turpis ac nisi sagittis luctus. Praesent ipsum magna, vehicula at, luctus nec, accumsan convallis, odio. Curabitur non augue et risus commodo laoreet. Suspendisse commodo lacus sit amet orci. Pellentesque molestie tristique arcu. Aliquam erat volutpat. Praesent sit amet lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ornare risus in tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi luctus, nisl id laoreet aliquam, eros leo sagittis pede, vel venenatis dui odio venenatis quam. Quisque justo justo, lacinia sed, facilisis vel, dictum eu, erat. Proin ligula dolor, dapibus id, pellentesque id, consequat et, erat. In posuere. In sed est. Nam volutpat orci id nibh. Morbi convallis magna vitae mauris. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas felis. Donec condimentum. Sed pretium eros et est. Curabitur vel mauris. Sed tellus. Aliquam tristique facilisis metus. Nulla elit justo, sollicitudin eget, pulvinar eget, hendrerit vitae, est. Nulla semper dolor sed lorem. Morbi nisl. Proin pretium, ligula vitae pretium congue, turpis lacus bibendum magna, suscipit aliquet odio ligula nec risus. Mauris vestibulum. Pellentesque vehicula dolor sed nibh. Pellentesque id massa. Mauris sit amet justo quis turpis mollis tempor. Nullam vulputate velit at pede. Aenean fringilla ultrices magna. Proin urna tellus, faucibus in, blandit in, iaculis blandit, quam. Vestibulum turpis. Donec ornare aliquet justo. Integer velit. Sed at felis a arcu viverra congue. Suspendisse laoreet tortor at diam. Suspendisse quis arcu eget sapien condimentum molestie. Proin iaculis aliquet ipsum. Curabitur lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque in tortor. Curabitur imperdiet. Maecenas bibendum vestibulum nibh. Nullam vehicula lectus ac lectus. Morbi et lorem. Aenean sed metus. Cras commodo. Vestibulum a tortor. Duis pede nulla, posuere nec, hendrerit quis, faucibus id, nisl. Integer id purus nec quam aliquet ornare. Fusce euismod nibh ultricies pede. Quisque eget est hendrerit arcu mattis sollicitudin. Vestibulum viverra, lectus porta scelerisque venenatis, elit diam tempor ipsum, eu euismod nulla tortor eu orci. Praesent vulputate arcu vel magna. Maecenas blandit lectus. Aenean nunc orci, ornare vel, aliquam molestie, mattis non, sem. Fusce ac turpis et felis suscipit sodales. Nunc sollicitudin feugiat mi. Sed mattis fringilla magna. Quisque ut purus. Nunc tempus velit sed quam. Quisque mollis laoreet lorem. Integer eu augue. Morbi lobortis urna aliquam est. Maecenas eu tortor. Etiam commodo porta lectus. Ut vehicula, lorem id congue ultricies, augue ante pellentesque mauris, quis bibendum ante dui a dui. Aliquam varius mauris et neque. Vivamus consectetuer mauris eu elit. Cras vel nisi. Cras mollis sapien vitae tortor. In quis sem. Sed malesuada, eros non bibendum viverra, leo turpis iaculis ligula, nec auctor enim sapien nec magna. Vestibulum cursus, risus quis tempus aliquet, pede magna volutpat diam, tempor rutrum dolor dui a lacus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum euismod varius elit. Fusce et erat a leo ultrices semper. Vestibulum a ante quis neque lacinia laoreet. Nullam nisi ipsum, vulputate a, molestie quis, ornare sed, felis. In posuere ligula non odio. Nulla eleifend viverra arcu. Sed mollis metus ac massa. Quisque vitae tortor sed est laoreet sagittis. Donec et justo. Pellentesque porta mauris ut turpis. Ut diam. Nulla neque lacus, commodo egestas, iaculis quis, porta a, nibh. Integer ultricies, libero quis hendrerit imperdiet, quam purus consequat ligula, vitae dignissim elit nisl non turpis. Morbi ut orci in diam luctus convallis. Vivamus ligula. Sed magna leo, aliquam at, hendrerit ac, feugiat non, justo. Sed lectus. Suspendisse elementum pretium tellus. Aenean egestas. Aenean faucibus porta purus. Nullam lorem dolor, iaculis vel, lobortis et, euismod a, eros. Donec eget mi. Sed vitae ligula eu massa cursus luctus. Nunc ullamcorper. Nunc purus nulla, feugiat et, vestibulum quis, hendrerit at, tellus. Sed risus massa, porttitor elementum, rutrum a, posuere sed, nulla. Etiam blandit egestas ligula. Proin rutrum dolor at odio. Quisque et nunc. Maecenas sed dolor. Donec suscipit mattis magna. Donec sit amet leo. Aenean lobortis dolor non elit. Cras vulputate consequat tortor. Etiam sodales porttitor ante. Morbi ut leo quis lacus lobortis eleifend. Nunc fermentum, nisl sit amet pretium egestas, velit eros tincidunt lectus, non vulputate ipsum urna vitae erat. Integer sit amet sem quis turpis varius posuere. Proin in metus vitae neque commodo tincidunt. Praesent iaculis fringilla justo. Vestibulum nec sapien. Curabitur eros. Duis commodo, diam non congue imperdiet, risus nisl auctor nunc, eget sodales magna sapien egestas sem. Vivamus id mauris. Phasellus dapibus, lectus at ornare lacinia, mauris sem imperdiet ligula, bibendum imperdiet lorem dolor at purus. Quisque ultrices nisi at augue viverra scelerisque. In vel risus. Fusce quam diam, luctus a, pharetra ac, tempor ac, lectus. Fusce neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam eget augue. Quisque in tellus vel lorem vulputate iaculis. Integer a pede. Integer vulputate molestie lorem. Donec velit magna, iaculis id, pretium in, aliquam nec, felis. Fusce nec libero sed velit egestas molestie. Maecenas turpis tortor, molestie in, hendrerit eu, tempor sed, enim. Fusce non orci. Suspendisse eleifend neque vitae odio. Quisque bibendum, justo a tristique gravida, sapien ante adipiscing nisl, non vehicula purus mi sit amet metus. Donec pharetra, felis nec interdum imperdiet, dui ipsum tempus diam, ac aliquam lorem libero vel nunc. Integer tincidunt adipiscing risus. Maecenas ante. Nunc vestibulum, nibh nec laoreet commodo, nibh erat tempor erat, ultricies mattis pede turpis luctus leo. Phasellus egestas ligula ac massa. Quisque tincidunt, erat ut volutpat ornare, neque eros tristique ante, sit amet bibendum turpis enim eget lectus. Pellentesque hendrerit lorem sed sem. Pellentesque semper elit non velit. Mauris nisl. Proin sed pede ac est mollis vestibulum. Nullam faucibus, lectus vel mollis accumsan, ipsum massa porta quam, id egestas turpis ante quis sapien. In aliquam ipsum in neque. Quisque id sapien. Morbi vitae elit. Nam leo eros, ullamcorper at, molestie a, mattis sit amet, augue. Pellentesque convallis suscipit elit. Nulla viverra. Nam ut erat. Duis metus. Mauris neque. Nulla eu odio elementum dolor adipiscing tincidunt. Aenean convallis, eros quis hendrerit luctus, dui tortor hendrerit ipsum, nec egestas nisl leo id tellus. Praesent eu turpis non tellus sodales semper. Duis quis enim sed nunc vulputate posuere. Proin leo. Proin mi risus, dapibus id, pretium sed, pharetra eget, diam. Aenean risus lacus, placerat quis, dictum dapibus, ullamcorper at, ipsum. Ut egestas sem sed quam. Nullam gravida lectus sed mauris condimentum accumsan. Nam ac pede. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris varius bibendum ligula. Aenean neque. Nulla facilisi. Sed ultricies, lorem laoreet tempor ultricies, erat pede volutpat nibh, eget blandit quam massa hendrerit dolor. Fusce consectetuer, mauris id cursus eleifend, justo libero ultricies sapien, sed consectetuer odio mi eget elit. Vestibulum id arcu. Etiam tortor erat, accumsan vitae, pulvinar a, fringilla non, ligula. Maecenas venenatis semper urna. Quisque ac dolor. Nulla tellus. Quisque varius. Vestibulum non lacus. Phasellus iaculis. Duis pede. Praesent viverra lacus quis massa. Mauris eget dui. Proin aliquam, mauris eu dapibus viverra, pede nibh accumsan enim, sit amet aliquet nibh diam bibendum est. Nam dui. Morbi porta. Fusce scelerisque turpis ac arcu. Quisque quis erat. Nam sodales tellus et velit. Morbi vel arcu. Vivamus at nibh at odio congue scelerisque. In hac habitasse platea dictumst. Maecenas sed dui. Nulla turpis. Nulla rhoncus, quam lobortis tempor convallis, justo diam tristique erat, ut lobortis massa pede id magna. Donec purus. Cras tempus ligula eget nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse adipiscing sapien vitae enim. Donec egestas metus at sem. Sed in massa. Proin vulputate risus et nunc. Cras ut purus. Ut posuere semper eros. Praesent diam. Donec at lectus ac odio fringilla mollis. Mauris pede eros, faucibus in, cursus sit amet, adipiscing eget, ipsum. Donec malesuada laoreet purus. Sed mauris tellus, scelerisque eget, semper quis, vulputate non, leo. Sed quis dui sit amet enim facilisis faucibus. Sed sem. Quisque sit amet odio. In pellentesque scelerisque elit. In hac habitasse platea dictumst. Maecenas mattis massa quis lectus. Nam arcu. Nulla accumsan magna et ipsum. Donec felis erat, tristique ut, tincidunt a, elementum quis, metus. Aliquam erat volutpat. Vivamus ut orci pulvinar nisl condimentum varius. Etiam condimentum dui quis lectus. Donec ut sem sed nisl dictum pulvinar. Maecenas arcu enim, pretium vel, tincidunt quis, tristique pharetra, risus. Suspendisse pede lorem, luctus et, eleifend vitae, eleifend et, purus. Cras pretium est at tortor. Aenean ac ipsum et dolor dictum suscipit. Donec et magna vitae lectus malesuada facilisis. Cras dignissim. Morbi eget purus. Nulla in tellus. Ut turpis. Nunc imperdiet. Donec pretium pellentesque diam. Aliquam dapibus. Cras eu tellus ut erat tristique pretium. In hac habitasse platea dictumst. Phasellus lobortis. Proin a enim malesuada nunc luctus suscipit. Maecenas eu risus imperdiet ligula hendrerit tincidunt. Nunc egestas varius turpis. Proin sollicitudin ipsum. Maecenas hendrerit vehicula mi. Morbi sed magna eu libero egestas imperdiet. Fusce ullamcorper ultricies quam. Morbi quis ligula. Aliquam erat volutpat. Sed luctus. Duis eu risus. Mauris et turpis quis nisl sagittis lacinia. Aenean faucibus venenatis risus. Morbi tempor condimentum dolor. Integer sapien sem, scelerisque quis, tincidunt ut, fringilla sed, eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec eu lectus. Suspendisse malesuada leo eu ipsum. Aliquam condimentum nisi eget turpis. Ut nulla turpis, scelerisque in, rutrum in, sodales eget, turpis. Nullam pharetra euismod odio. Proin elit risus, pharetra vitae, ullamcorper in, posuere nec, magna. Donec semper lectus at sem. Morbi vitae libero. Quisque erat lectus, tempor vel, venenatis sed, dictum placerat, mauris. Integer malesuada. Quisque eget lacus. Aenean vitae enim in odio congue scelerisque. Fusce pellentesque accumsan erat. Praesent ante velit, sodales eget, tincidunt in, ullamcorper et, nisi. Sed vulputate. Sed fringilla, libero at aliquam tincidunt, odio lacus sagittis lectus, in volutpat est dui ornare nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Etiam id ligula sed ante congue pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur ornare adipiscing tellus. Suspendisse mattis. In vel elit laoreet dolor placerat elementum. Integer auctor nunc non tortor. Fusce accumsan metus vel tortor. Suspendisse vehicula mi vitae magna. Donec in purus vel libero hendrerit rutrum. Nunc rhoncus sapien ac sem. Nullam convallis malesuada arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum sapien. Cras sem. Sed enim metus, porttitor in, imperdiet eget, placerat ac, sem. Mauris ipsum. Maecenas vitae lacus. Sed semper facilisis velit. Nam dignissim, felis sit amet tempus lobortis, libero metus dictum nisi, sit amet suscipit lorem odio non justo. Curabitur euismod, purus ac ornare egestas, orci massa tincidunt metus, et porta nulla nulla fringilla nibh. Aliquam id ipsum. Maecenas ac lorem. Nullam diam tellus, ornare ornare, convallis id, iaculis vitae, mi. Phasellus hendrerit. Cras malesuada pulvinar felis. Nunc id turpis vitae nisl vestibulum sollicitudin. Fusce elit risus, posuere vitae, mollis ac, commodo placerat, libero. Integer libero ipsum, congue ac, placerat non, sagittis nec, nibh. Vivamus sagittis, quam nec ullamcorper malesuada, libero magna dapibus dolor, in ornare enim leo non est. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec elit. Curabitur tempor sem vel lorem. In ullamcorper. Curabitur eu odio id mi commodo pulvinar. Nam ut nisi. Nulla consequat lorem ac lectus feugiat elementum. Integer tincidunt, leo et eleifend tempor, augue ipsum ullamcorper sem, pulvinar faucibus velit lectus a dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec mi sit amet lacus facilisis porttitor. Nam orci ante, dapibus eget, interdum in, hendrerit eu, augue. Aenean vehicula, ligula in porttitor volutpat, dui lectus mollis metus, sit amet tincidunt orci enim at nulla. Proin vestibulum vehicula orci. Aliquam erat volutpat. Fusce sit amet erat. Vivamus vestibulum pellentesque lectus. Fusce magna ante, pharetra quis, molestie sed, molestie vel, massa. Donec in erat at nunc sollicitudin euismod. Nunc et massa ut quam posuere vehicula. Cras fringilla ante vitae orci. Vestibulum mattis congue ligula. Duis eu pede eu odio tristique sodales. Curabitur sagittis venenatis ipsum. Etiam vitae lacus a mauris feugiat ultricies. Nulla convallis tortor et erat. Nunc nunc. Phasellus porta eros at dolor. Morbi placerat. Aenean non ipsum in libero euismod euismod. Maecenas vel justo. Proin sit amet orci adipiscing tellus tincidunt interdum. Pellentesque euismod nulla vitae est placerat lacinia. Donec malesuada, elit laoreet tincidunt sodales, lorem ligula consectetuer purus, ut rutrum mi neque eu sem. Phasellus ac odio. Vivamus lobortis. Aliquam erat volutpat. Nullam rutrum ipsum in dolor. Nullam vel libero. Duis lacinia lectus vel lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed sodales dolor. Proin rhoncus, lectus pharetra faucibus facilisis, diam ligula hendrerit leo, ac aliquet sem ipsum id arcu. Ut non erat eu risus ornare rhoncus. Mauris non lorem ut magna convallis rutrum. Integer est purus, venenatis in, euismod quis, feugiat vitae, leo. Suspendisse laoreet tellus eleifend neque. Sed vitae arcu nec pede tempus hendrerit. Mauris commodo, leo ultricies venenatis consectetuer, turpis tellus hendrerit diam, eget lacinia diam tortor in leo. Etiam luctus orci ut sem. Donec sed mi sit amet erat pharetra ullamcorper. Phasellus dolor diam, euismod et, pharetra ut, convallis sed, orci. Nam vitae lorem. Vivamus et nulla. Suspendisse vel tellus sed quam blandit rhoncus. Proin convallis erat vel dolor. Proin ut leo. Quisque ut pede non augue vestibulum egestas. Donec interdum justo eget dui. Nunc malesuada neque et felis. Donec eu dolor. Aenean in dolor vehicula diam bibendum auctor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed molestie laoreet nisi. Mauris condimentum magna quis massa. Nulla faucibus. In leo. Morbi vitae dolor. Aliquam erat volutpat. Sed euismod. Fusce pede. Nullam ipsum mauris, ultricies tempor, laoreet eu, pretium ac, sem. Praesent accumsan risus quis mi. Curabitur id nisi. Fusce imperdiet. Proin vitae velit. Vivamus eget urna vitae metus ultrices sodales. Mauris vel mi. Phasellus nisi metus, auctor sed, facilisis id, volutpat a, nisi. Nulla sagittis. Duis vitae nisl. Phasellus felis tortor, cursus vitae, convallis et, fringilla egestas, eros. Pellentesque nunc lectus, mattis laoreet, sollicitudin eu, imperdiet auctor, quam. In hac habitasse platea dictumst. Integer lectus nibh, tincidunt accumsan, sagittis nec, viverra vel, pede. Integer porttitor varius nulla. Aenean consectetuer leo a nunc. Suspendisse vel risus. Pellentesque sed eros. Aenean consectetuer diam ac diam. Sed varius semper tellus. Mauris condimentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam eget enim. Vivamus felis ante, porttitor a, cursus eget, cursus eu, quam. Aliquam consequat consectetuer lectus. Cras non tellus. Aliquam bibendum hendrerit ipsum. Phasellus auctor ullamcorper nunc. Suspendisse tempor neque at sapien. Quisque malesuada libero quis ipsum. Sed pellentesque pellentesque est. Aenean rhoncus magna eget arcu. Praesent dignissim. Duis magna. Praesent nunc nibh, sagittis vitae, iaculis sed, facilisis a, orci. Nunc eu lectus id velit porta commodo. Aliquam a tortor. Nullam hendrerit lacinia velit. Curabitur et velit ac libero tempus sollicitudin. Praesent aliquam dui eu enim. Aliquam erat volutpat. Duis quis risus. Sed sit amet metus eget odio porta iaculis. Duis lacinia, nibh vel hendrerit malesuada, odio quam eleifend sem, non aliquam nisi lectus ut nisl. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus sodales. Cras euismod ligula quis velit egestas commodo. Vestibulum vulputate ornare quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus convallis ligula id nunc. Nam consequat felis condimentum pede. Etiam nec risus. Mauris vehicula laoreet enim. Quisque nisl urna, tincidunt eget, congue non, rhoncus eu, odio. Ut quis velit. Aenean semper purus in tellus. Duis sagittis auctor sapien. Ut dapibus mi in lorem. Ut nunc. Phasellus id purus. Etiam ultrices. Sed nec nisi. Praesent ac augue nec turpis sodales cursus. Praesent et quam et turpis tempor mattis. Ut a velit eget enim feugiat pharetra. Cras blandit enim non ante. Aliquam erat volutpat. Quisque nulla arcu, eleifend ac, mollis a, congue at, leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin malesuada imperdiet sem. Cras a justo. Suspendisse volutpat mi in nunc. Vestibulum placerat sagittis arcu. Vivamus pede. Vivamus ultrices risus at leo. Nulla egestas adipiscing mi. Quisque cursus mi non arcu. Nulla congue. Donec dictum imperdiet diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin quis mi. Duis odio. Morbi tincidunt enim in mauris. Duis mi enim, dapibus a, suscipit ac, porttitor eu, leo. In aliquam, dolor vitae congue hendrerit, lacus risus consequat risus, ut molestie mauris purus a ligula. Nullam sit amet diam. Etiam congue malesuada dolor. Integer dictum. Fusce facilisis. Quisque neque velit, feugiat a, egestas quis, tempor a, magna. Fusce ligula. Praesent tincidunt mollis diam. Aenean libero neque, suscipit nec, volutpat in, ultrices sed, turpis. Etiam consequat bibendum arcu. In turpis. Pellentesque et odio. Proin ac lectus vitae elit malesuada sodales. Aenean bibendum enim ut nulla. Suspendisse turpis est, tempus non, cursus eget, pulvinar eget, nibh. Aliquam erat volutpat. Etiam risus urna, accumsan vel, pellentesque in, commodo sit amet, nisl. Nulla eget sem sed nulla porta egestas. In tempus est nec justo. Aenean placerat. Aenean commodo nulla nec magna commodo luctus. Nunc mollis sem sed metus. Sed vitae libero et felis varius dapibus. Maecenas at orci. Etiam quam turpis, interdum vel, interdum vitae, dapibus sit amet, pede. Suspendisse consectetuer velit dictum arcu. Vestibulum dui dolor, vehicula et, ultricies ut, facilisis et, enim. Duis eu neque id diam tempus ornare. Phasellus luctus faucibus ante. Morbi id enim ut dolor interdum volutpat. Nam non nunc. Nulla sagittis enim vitae mi. Fusce sit amet odio. Nulla elementum, massa ac tempus suscipit, leo magna tristique urna, ac gravida eros nisl sit amet est. Curabitur posuere mattis mauris. Integer pellentesque sodales velit. In scelerisque metus. Suspendisse potenti. Duis felis. Nunc vitae enim eget metus tempus egestas. Suspendisse potenti. Integer viverra sollicitudin nunc. Curabitur lectus. Sed faucibus. Fusce justo. Nulla facilisi. Donec viverra lorem sit amet ipsum aliquet imperdiet. Maecenas quis est. Cras nibh nisi, pellentesque sit amet, porttitor vitae, adipiscing vitae, massa. In hac habitasse platea dictumst. Etiam dignissim. Integer neque libero, consectetuer quis, egestas sit amet, feugiat sed, tellus. Nullam sagittis erat id purus. In erat pede, cursus ut, posuere eu, laoreet non, urna. Sed elit enim, placerat eu, rutrum non, consectetuer vel, purus. Curabitur eget magna. Phasellus ultrices velit at ipsum. Praesent posuere consectetuer lorem. Donec dapibus libero a eros. Phasellus convallis luctus quam. Vestibulum est dui, viverra id, feugiat eu, malesuada eget, mi. Fusce bibendum arcu vitae justo suscipit ullamcorper. Sed a augue rutrum nisi gravida volutpat. Maecenas consequat rutrum felis. Aliquam neque libero, dignissim ut, ullamcorper vel, luctus eu, enim. Donec mollis consectetuer ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur sed nulla ac libero dapibus pretium. Proin auctor imperdiet justo. Curabitur est mauris, tristique a, rutrum vel, vulputate vitae, augue. Proin purus nulla, pharetra id, faucibus quis, venenatis a, nunc. Sed tincidunt elementum turpis. Mauris nibh tellus, accumsan et, mattis eu, pulvinar eget, sem. Nulla facilisi. Mauris pulvinar dignissim eros. Fusce nec orci vitae lectus feugiat lobortis. Etiam velit turpis, aliquam sit amet, lacinia eu, mattis ut, ipsum. Praesent ut massa a quam scelerisque gravida. Suspendisse ullamcorper faucibus pede. Vivamus turpis. Mauris suscipit. Integer vel dui. Curabitur a enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut dapibus molestie dolor. Curabitur at mauris. Nullam luctus risus ut lectus. Phasellus imperdiet tellus et massa. Cras vulputate, arcu sit amet tempor suscipit, libero orci pharetra nibh, in pharetra massa lorem nec mi. Aenean sodales auctor orci. Aliquam euismod tincidunt velit. Maecenas urna nulla, congue dapibus, semper at, faucibus ultricies, dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis tincidunt aliquam nisl. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce commodo, eros ut adipiscing luctus, libero risus mollis ipsum, et vulputate lorem purus vel lacus. Nullam lectus neque, vehicula eget, eleifend ac, aliquet eu, enim. Praesent orci tellus, convallis vitae, aliquet eget, suscipit vel, ligula. Curabitur eleifend elit non sem. Fusce ut quam. Mauris at ipsum eget justo mattis pretium. Phasellus eu enim. Vestibulum suscipit purus at libero. Fusce vitae leo. Aenean cursus. Nunc ullamcorper augue nec enim. Fusce et est sit amet nisl sodales volutpat. In malesuada enim sed mauris. Aliquam et felis. Pellentesque euismod consequat erat. Aliquam pharetra diam sed erat. Nullam placerat, neque quis condimentum semper, lectus purus auctor metus, nec luctus nibh lectus in elit. Nullam faucibus pellentesque nunc. Suspendisse potenti. Curabitur commodo metus eu odio. Nulla porttitor consequat diam. Nam pretium ornare ante. Integer congue, elit ut commodo pellentesque, lectus urna luctus felis, et rhoncus magna libero pretium est. Mauris diam. Curabitur fringilla justo vel tortor. Mauris justo eros, adipiscing non, laoreet et, mattis in, tortor. Vestibulum vel justo non augue lacinia sollicitudin. Duis et libero eu nibh adipiscing sollicitudin. In sem. Quisque dictum ultrices lacus. Mauris quis orci. Ut aliquet eros ut mauris. Pellentesque ultrices. Aliquam erat volutpat. Nullam feugiat blandit lacus. Fusce vulputate, ante sit amet eleifend viverra, arcu augue feugiat urna, porttitor interdum sem ligula cursus sapien. In vitae augue nec sapien tincidunt dignissim. Morbi tincidunt aliquet mauris. Donec pellentesque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras ligula sem, eleifend sit amet, iaculis quis, varius ut, ante. Morbi dapibus eleifend magna. Nullam dapibus rhoncus tellus. Nam quis tortor. Cras arcu nunc, sagittis eu, malesuada varius, tempus et, lorem. Etiam sit amet metus. Praesent arcu. Aenean et metus. Quisque sem enim, posuere id, feugiat nec, gravida ut, neque. Maecenas semper, justo sit amet dapibus dapibus, purus justo facilisis purus, non fringilla eros ligula a neque. Donec nisi. Integer mattis, lacus in ullamcorper lobortis, risus massa aliquet ligula, eget auctor leo orci sit amet nisi. Aenean diam. Ut tristique quam eu velit. Curabitur sed mi eget arcu sodales aliquet. In sed risus. Sed et mi. Etiam sagittis enim tincidunt est. Cras vel est vel eros tincidunt consectetuer. Etiam eu sapien ac orci vestibulum dapibus. Sed ut est eu est euismod hendrerit. Pellentesque vitae orci non libero varius dignissim. Praesent iaculis, ligula id euismod interdum, lacus risus porttitor quam, a adipiscing mi augue at diam. Nulla iaculis iaculis turpis. Vivamus nec nunc quis libero ornare ullamcorper. Praesent imperdiet posuere dui. Etiam vulputate vestibulum urna. Cras cursus hendrerit ipsum. Praesent felis ante, posuere sed, mattis quis, sollicitudin ut, lorem. Donec nec odio. Sed luctus odio eu risus. Sed sem nisl, tincidunt quis, hendrerit et, facilisis non, mauris. Aliquam non felis. Integer sed lacus vitae dolor pulvinar condimentum. Etiam lobortis, libero quis tincidunt lacinia, nibh nisi iaculis quam, eu condimentum massa purus a turpis. Suspendisse potenti. Morbi vitae lacus ac tellus pulvinar mollis. Nam auctor fringilla sem. Morbi lacus elit, pellentesque at, mattis nec, volutpat feugiat, lectus. Phasellus eros ligula, molestie at, pulvinar id, eleifend vel, ante. Fusce facilisis, diam luctus interdum condimentum, libero justo venenatis tellus, molestie ullamcorper ante diam ac sem. Pellentesque tempus, ligula ac pellentesque vulputate, eros velit aliquet lacus, eu dignissim urna leo a diam. Suspendisse quam ipsum, ullamcorper sed, dignissim vehicula, facilisis ut, tellus. Fusce convallis, odio a malesuada pharetra, orci risus sagittis urna, sit amet tincidunt ligula pede vitae leo. Quisque augue. Phasellus scelerisque nisl sed purus malesuada pretium. Pellentesque condimentum tempus ipsum. Vivamus auctor metus sed sapien. Nulla tristique congue magna. Vestibulum iaculis urna ac risus. Nullam fringilla suscipit ipsum. Quisque euismod. Quisque ullamcorper pede tincidunt risus. Sed tortor pede, rutrum ac, varius sed, sagittis nec, orci. Phasellus arcu orci, bibendum quis, tempus id, consequat eu, velit. Phasellus commodo congue purus. Sed malesuada, pede eu volutpat tristique, tellus mauris vulputate nibh, a faucibus lorem enim nec nulla. Nunc semper, nisl iaculis rutrum consectetuer, leo eros egestas lacus, sit amet venenatis dolor ligula non lorem. Morbi feugiat. Donec vulputate. Vivamus at sapien sit amet est feugiat elementum. Donec nisl erat, tincidunt ornare, pellentesque vel, aliquet sit amet, eros. Duis sagittis porta sapien. Etiam a dui. Praesent lobortis nisl at lorem. Sed malesuada. Morbi viverra dui eu neque. Nullam sed ante sed diam malesuada vehicula. Morbi ut metus et dolor hendrerit vehicula. Integer in lacus nec dui aliquet dictum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse et mauris vitae dui lacinia ultrices. Mauris neque sem, sagittis sed, lobortis viverra, pharetra vitae, mi. Nam dui nunc, iaculis id, dictum at, porttitor vitae, diam. Donec tincidunt leo quis augue varius rhoncus. Nam risus. Vivamus dignissim. Praesent viverra, neque vitae vulputate blandit, dui massa rhoncus lectus, quis accumsan neque quam sit amet augue. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut congue pellentesque velit. Vivamus at elit. Cras risus metus, elementum ut, tristique nec, commodo in, sapien. Etiam metus. Maecenas congue, justo vitae egestas volutpat, orci quam aliquam mi, vitae pulvinar tortor pede vel nunc. Integer mollis, massa sit amet vestibulum fringilla, nulla tortor pretium nibh, eget porttitor nisi elit sit amet magna. Proin dignissim, nisl eget posuere posuere, velit diam ultrices turpis, a lacinia nunc dolor quis odio. Nulla egestas. Nam consectetuer. Pellentesque enim libero, viverra eget, dapibus ut, iaculis ac, neque. Donec vel tortor. Sed eu urna ut libero pharetra viverra. In hac habitasse platea dictumst. In dictum. Morbi non magna sit amet elit dictum facilisis. Sed ultrices porta urna. Vivamus tincidunt. Ut ante orci, pellentesque a, aliquet ut, dignissim eu, velit. Integer ultrices congue felis. Sed faucibus vestibulum augue. In lectus urna, vulputate non, dignissim id, placerat in, ante. Aenean mi erat, eleifend at, faucibus in, gravida eget, massa. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse potenti. Donec dignissim elit vel felis. Vestibulum gravida tortor ut massa. Nulla facilisi. Nulla imperdiet urna sed nibh. Suspendisse volutpat, nulla eget dignissim elementum, leo velit bibendum leo, ac viverra mi nisl nec mi. Vivamus et libero vel erat mattis semper. Cras hendrerit porttitor sapien. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc elementum condimentum orci. In hac habitasse platea dictumst. Donec massa quam, laoreet in, sagittis nec, porta eu, tortor. Integer eget dui. Nulla quis purus in justo tristique adipiscing. Ut eleifend placerat orci. Sed neque. Sed ultrices eros vitae eros. Praesent venenatis laoreet orci. Vivamus non elit. Aliquam varius tellus non erat. Vivamus ullamcorper magna sit amet lectus. Mauris venenatis, elit vel lobortis dapibus, eros lacus feugiat erat, in tincidunt dui libero a orci. Duis non nisi. Nulla aliquet, nunc vel vestibulum lobortis, est lorem luctus mi, ut sodales felis dolor vitae dolor. Fusce eget felis. Pellentesque tempus eros ut justo. Curabitur aliquet. Duis rutrum sapien sit amet lectus. Curabitur tellus. Nulla laoreet sapien at ante. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce lacinia venenatis sem. Mauris sagittis. Proin posuere nibh id pede. Maecenas hendrerit placerat nisi. Sed vitae justo quis ante pellentesque sollicitudin. Morbi in est. Nulla velit nibh, tempus non, tincidunt eget, ornare at, dui. Praesent fringilla magna id magna tincidunt mattis. Morbi vestibulum. Donec ut nisl. Duis turpis nulla, feugiat vel, commodo at, hendrerit eu, purus. Cras nec libero. Nullam vestibulum dolor et metus scelerisque vestibulum. Aliquam sed felis. Nulla dolor diam, placerat vitae, gravida eget, tincidunt consectetuer, pede. Maecenas auctor, felis vulputate placerat sollicitudin, sapien purus dapibus purus, condimentum sollicitudin sapien purus eget magna. In at est a mi placerat congue. Maecenas et leo. Praesent ac nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vel mi quis lacus congue consequat. Duis laoreet ipsum et odio. Duis pede orci, aliquam eget, rutrum et, faucibus tincidunt, dui. Donec aliquet enim vitae diam. In hac habitasse platea dictumst. Integer pede. Phasellus feugiat ullamcorper sem. Maecenas eu turpis. Maecenas dapibus leo varius neque. Mauris convallis, velit ut interdum pulvinar, est dolor elementum lacus, ut placerat neque est at dolor. Donec aliquet purus. Etiam quam urna, pharetra ut, consequat at, lacinia at, velit. Curabitur metus lacus, tincidunt sit amet, pharetra non, suscipit vel, quam. Ut lacus ante, ullamcorper porta, malesuada venenatis, vulputate et, dui. Nam posuere lacus eu urna. Sed ac erat vel nisl venenatis pharetra. Nullam egestas lectus non lorem. Maecenas mi neque, sodales a, ullamcorper aliquam, semper in, elit. Donec nec risus ultricies libero tincidunt accumsan. Sed rutrum neque tristique lacus. Fusce nulla ligula, vulputate et, pellentesque eget, varius ut, odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In quis risus non pede egestas imperdiet. Maecenas faucibus, purus id pulvinar sagittis, libero arcu pharetra lacus, sit amet auctor lorem tortor non urna. Suspendisse semper, sem vitae consectetuer molestie, nunc erat feugiat quam, non placerat augue mauris eu metus. Aliquam eleifend, justo sed ullamcorper auctor, elit sem rhoncus turpis, quis pellentesque nibh risus at enim. Cras dui. Vestibulum eget dolor. Sed faucibus. Praesent a odio feugiat quam scelerisque egestas. Fusce a ante non ante blandit congue. Aenean vestibulum. In hac habitasse platea dictumst. Ut consequat. Nam tincidunt est nec libero. Maecenas quis odio eu nisl vulputate pretium. Phasellus fermentum feugiat metus. Curabitur convallis fermentum erat. Donec ac lorem sit amet augue fringilla fringilla. Vestibulum neque ligula, consequat vitae, gravida posuere, vulputate ut, metus. Suspendisse potenti. Phasellus blandit. Quisque commodo odio at mi ultricies aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec condimentum, leo ac aliquam vehicula, metus augue lacinia tellus, ut dictum nisl orci ac neque. Nam a tellus. Praesent vitae nisl non augue laoreet adipiscing. Nullam at justo sed dolor placerat mattis. Nam varius nisl et urna. Sed bibendum, augue lobortis vestibulum ornare, nibh odio pharetra purus, quis eleifend est sapien sit amet lorem. Aenean viverra ante non libero. Ut posuere. Mauris arcu lacus, sodales in, condimentum ac, accumsan vitae, mi. Aliquam sodales dignissim purus. Donec at arcu. Vestibulum eleifend. Pellentesque dui. Phasellus sem. Sed ornare nisi lobortis ligula. Etiam est. Etiam leo lorem, auctor ut, molestie facilisis, tristique eu, sem. Morbi lorem. Mauris pede dolor, aliquam bibendum, facilisis sed, vehicula eu, nibh. Integer aliquet. Aliquam posuere, odio in sollicitudin luctus, nibh arcu vulputate mauris, sit amet eleifend risus magna ut leo. Nullam consectetuer semper dui. Donec dignissim justo interdum nisl vestibulum egestas. Donec sit amet arcu nec tellus sollicitudin eleifend. Ut auctor leo eget turpis. Integer commodo mattis neque. Vivamus vitae orci. Morbi quam quam, convallis vel, dignissim pretium, ultricies eu, dolor. Cras non est quis nisl faucibus sodales. Mauris euismod vulputate mauris. Duis vehicula feugiat orci. Nulla facilisi cras amet. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFI1aQDwJfZ7JTAY2MRApDhAKDTaHE5Juz9UvbNvag2eqXhB3+ahgCgulAq CQKic84xan7nfdky+QCSPYA= =jwif -----END PGP SIGNATURE----- Crypt_GPG-1.4.0/tests/data-files/testVerifyFileDualClearsignedData.asc0000664000175000017500000014074112610161626024266 0ustar alecalec-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus luctus placerat erat. Curabitur euismod arcu id eros. Maecenas accumsan pede in orci consectetuer tristique. Ut nec felis non nunc euismod ornare. Ut dui eros, euismod sit amet, condimentum nec, varius sit amet, leo. Cras ipsum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis porta. Donec neque magna, interdum eu, dictum non, viverra a, est. Praesent vel neque. Mauris vitae nunc. Praesent commodo eros eget eros. Nunc congue. Maecenas quis massa sed ante dapibus vestibulum. Sed at dui. Duis mauris nulla, sodales vel, tincidunt ut, sodales ac, tellus. Donec ullamcorper. Maecenas sollicitudin sagittis leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Phasellus leo. Maecenas posuere. Morbi massa. Maecenas dolor felis, dignissim nec, vulputate quis, auctor vel, lectus. Sed libero. Cras mi. Proin placerat libero vitae dolor. Donec non nunc vel nisi sodales facilisis. Ut a tortor vitae neque eleifend rhoncus. Suspendisse vehicula, lectus vitae elementum porta, diam eros scelerisque sem, et accumsan massa orci a urna. Vivamus posuere, massa sit amet sagittis pulvinar, leo erat congue metus, eu congue lacus tortor in mauris. Vestibulum dapibus lorem in turpis. Curabitur aliquet gravida purus. Integer quis felis at velit varius laoreet. Pellentesque aliquam consectetuer lectus. Nunc at sapien. Cras faucibus dignissim dolor. Sed id diam ac augue aliquet convallis. Proin feugiat, lectus elementum venenatis aliquet, nibh lectus porttitor tortor, sit amet aliquet erat sapien eu nulla. Morbi sagittis libero sed tellus. Sed purus turpis, sollicitudin vel, dapibus eu, vehicula vel, dui. Nullam fringilla tellus in lorem. Integer dolor. Mauris interdum tristique neque. Nullam ac magna. Nam vel eros id enim dignissim sagittis. Suspendisse pede. Aenean et lacus at sapien molestie consequat. Vestibulum sapien. Aliquam erat volutpat. Duis vel felis ac risus consequat tristique. Curabitur porta enim. Phasellus auctor consectetuer justo. Sed rhoncus congue turpis. Nam consequat massa ac elit. Nam aliquam. Nam velit. Aliquam condimentum vestibulum risus. Vivamus id nunc ut ante consequat hendrerit. Donec sit amet ante ut nisi vulputate malesuada. Aliquam id nisi at justo ornare imperdiet. Curabitur ac felis eu pede posuere pretium. Cras sed justo et enim pretium mattis. Maecenas nec metus. Fusce sed odio. Vivamus aliquam dictum nunc. Nullam aliquam magna eu massa. Etiam sit amet lacus. Duis velit mauris, ullamcorper sit amet, facilisis sit amet, ultricies id, neque. Aenean ut arcu in magna suscipit ultricies. Nulla mauris. Morbi sed purus. Maecenas vel augue id lorem tempor volutpat. Sed congue porttitor mi. Mauris fringilla magna quis enim. Sed eleifend, nibh ut ornare lobortis, augue mauris egestas sapien, sit amet rutrum risus sem non felis. Pellentesque ipsum augue, ornare et, lobortis sit amet, aliquet ac, nulla. Aliquam sit amet massa. Morbi nec odio ut diam ornare pellentesque. Etiam iaculis purus quis neque. Cras gravida velit at ante. Curabitur a justo vitae nulla molestie molestie. Pellentesque sed urna vel enim rutrum tempor. Sed lectus tortor, consectetuer ac, aliquet ac, commodo id, elit. Sed eleifend turpis. Maecenas turpis dui, vulputate in, euismod id, dignissim eget, massa. Integer id mauris. Mauris a diam. Curabitur scelerisque, arcu ac aliquet eleifend, nunc elit egestas libero, ut luctus ipsum enim in risus. Quisque a pede. Sed euismod ligula vel lectus. Aliquam erat volutpat. Curabitur quis ligula. Vivamus justo odio, scelerisque ut, feugiat id, dapibus quis, nibh. Aliquam et ante vitae risus mattis iaculis. Aenean pretium ligula et magna viverra vehicula. Proin felis. Proin malesuada fermentum sem. Vivamus suscipit. Aenean et risus. Quisque vel urna. In hac habitasse platea dictumst. Ut vel quam eu odio semper congue. Aenean pulvinar, quam eget faucibus consequat, purus est tristique tellus, quis iaculis lectus nibh a neque. Cras diam. Vestibulum est enim, pellentesque vitae, sagittis id, semper non, sem. Maecenas iaculis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam quam massa, ultricies a, tristique quis, luctus ut, enim. Ut hendrerit tellus sit amet diam. Mauris eget tellus sit amet tortor lacinia mattis. Praesent eros enim, iaculis id, ultricies sed, ultrices id, eros. Donec libero nibh, accumsan id, vehicula vel, bibendum vitae, est. Morbi ac velit vitae nibh pharetra semper. Aliquam eros turpis, porta sit amet, bibendum quis, porta vitae, ante. Fusce ac turpis nec nulla euismod fermentum. Integer imperdiet lorem consectetuer libero. Quisque luctus. Nam erat augue, ornare vitae, accumsan vitae, molestie id, massa. Integer cursus. Suspendisse libero. Nulla sed magna. Nulla suscipit, urna a varius aliquam, mi nulla posuere eros, fermentum consectetuer dui orci vel ipsum. Fusce varius erat in libero. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi lacinia. Etiam accumsan ultrices erat. Integer eu mi. In vel purus. Integer porttitor. Fusce pede enim, venenatis sit amet, varius rutrum, convallis eu, orci. Phasellus dictum lacinia ante. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut non tellus eget metus rhoncus condimentum. Praesent consequat augue eu erat. Donec accumsan, turpis a ultricies venenatis, neque tortor porta velit, sed sagittis velit sapien a tellus. Pellentesque eget diam. Phasellus luctus sagittis sem. Pellentesque ac risus. Sed ac velit. Maecenas sed justo. Sed ut sem. Morbi elit massa, pretium eget, aliquet sed, ornare ut, ligula. Etiam vitae mi eget nisi facilisis molestie. Phasellus varius mattis mauris. Suspendisse ut nunc. Praesent nec arcu. Nullam in lacus. In vitae est. In hac habitasse platea dictumst. Mauris ultrices. Nunc vulputate, augue quis imperdiet vehicula, libero orci cursus lectus, et mollis velit lorem eget lorem. Ut id dui a purus porttitor varius. Nulla neque nisl, vehicula et, venenatis at, pretium in, lectus. Pellentesque at lacus et sem dictum laoreet. Vestibulum quis mauris. Morbi fringilla cursus diam. Phasellus id neque. Aenean magna sem, facilisis non, luctus vitae, egestas a, sem. Ut lobortis urna pulvinar diam. Fusce in velit eget nibh mollis vulputate. In lorem ligula, commodo ut, tempor non, egestas quis, leo. Nullam sit amet purus. Integer pellentesque sagittis orci. Quisque neque lectus, porta euismod, tristique et, dictum ac, arcu. Mauris congue consequat dui. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nunc ut nibh nec nibh facilisis elementum. Maecenas vel metus. Etiam id orci at nulla consequat volutpat. Vestibulum vel nulla et leo sodales fringilla. Phasellus eu nisl et quam fringilla molestie. Aenean eget metus. Donec diam arcu, dignissim vitae, fermentum dictum, accumsan ac, purus. Proin tempor aliquam lorem. Nullam facilisis odio a ante. Aliquam dui. Nam id leo et massa fermentum tempus. In pellentesque elit ut metus. Fusce mollis est in libero. Donec orci nulla, scelerisque non, elementum id, semper accumsan, ante. Phasellus nec risus porta nunc molestie vulputate. Etiam justo sem, sagittis lobortis, laoreet scelerisque, ornare nec, arcu. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nunc laoreet sem mattis massa. Cras porttitor lectus vel metus. Integer tellus felis, sodales sed, pharetra vitae, sodales sit amet, nulla. Maecenas vulputate vestibulum nisl. Donec sollicitudin sollicitudin ante. Curabitur sed ipsum. Nunc odio eros, consequat vitae, condimentum luctus, auctor at, tortor. Morbi nisl. Vivamus gravida metus vel justo. Aliquam eget quam sed nunc faucibus vestibulum. Nullam in erat. Etiam volutpat nunc quis turpis. Pellentesque blandit. Praesent sagittis urna in orci facilisis varius. Donec ultricies. Fusce lobortis placerat urna. Quisque mattis, enim id venenatis mollis, elit metus ultrices quam, id commodo libero nisi sit amet sapien. Quisque sagittis porta odio. Maecenas ac tellus. Etiam ornare nibh eu arcu. Quisque euismod facilisis lorem. In mauris. Vivamus urna. Sed nisi. Curabitur convallis ultrices arcu. Nullam sit amet mi. Donec at arcu. Etiam hendrerit. Phasellus ullamcorper, orci nec fringilla convallis, felis purus tempor eros, tempor venenatis massa velit sit amet velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec libero. Fusce aliquet. Suspendisse at purus in augue lacinia tincidunt. Vivamus tempor pellentesque mi. Aenean consectetuer ultrices ligula. Nam turpis nisl, congue at, semper vel, dictum nec, elit. Sed lorem odio, bibendum eget, dignissim sit amet, cursus vel, erat. Donec cursus nisi ut lorem. Morbi quam mauris, hendrerit nec, egestas congue, placerat ac, nisi. Morbi auctor, risus in pharetra ullamcorper, enim tortor vulputate massa, ac interdum est libero ac purus. Mauris faucibus turpis a lacus. Proin pharetra magna vitae est. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Proin iaculis, tortor sed pharetra sodales, turpis nunc mattis neque, ac porttitor ipsum lacus et tortor. Nulla eleifend luctus nisl. Nulla fermentum elementum dui. Cras dictum sem vel lorem. Nam pulvinar, elit in hendrerit hendrerit, turpis arcu accumsan sem, id elementum lorem ante ut augue. In pulvinar lacus sit amet nisl. Aenean venenatis, tortor at hendrerit venenatis, dui erat posuere urna, eget pharetra diam dolor pulvinar tortor. Pellentesque consectetuer. Sed orci. Morbi lacus ante, mattis et, ultrices sed, scelerisque sed, pede. Nulla eu nisl dapibus purus fermentum varius. Etiam rutrum vestibulum sem. Fusce libero. Duis laoreet. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum arcu nisi, mattis vitae, blandit non, venenatis eu, purus. Fusce fringilla, dui id iaculis luctus, mauris ipsum vulputate libero, quis posuere lectus ante a arcu. Mauris imperdiet libero venenatis odio. Integer varius laoreet turpis. Vivamus fermentum. Vivamus dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur at diam. Nulla suscipit gravida erat. Nulla enim massa, bibendum ut, pellentesque id, sollicitudin sollicitudin, massa. Integer varius, arcu ut condimentum commodo, neque neque blandit pede, vitae adipiscing tortor nibh eget sapien. Proin volutpat urna eu diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed quam pede, gravida sed, semper eu, fringilla quis, sapien. Fusce tincidunt nisi. In eros odio, vestibulum et, dapibus quis, tincidunt ac, est. Fusce eget purus id leo adipiscing varius. Fusce euismod lorem id turpis. Phasellus tincidunt blandit sapien. Integer sagittis orci at pede. Aliquam accumsan. Morbi ac orci sit amet magna scelerisque dignissim. Quisque vitae lacus quis neque convallis ultrices. Vestibulum ac arcu at mauris ultricies mollis. Nam id nulla. Nunc sed ligula. Sed nulla lectus, hendrerit ut, convallis ac, dapibus nec, odio. Ut blandit sapien nec libero. Duis tempor fermentum pede. Suspendisse imperdiet tincidunt risus. Integer lacus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque id odio eu nibh placerat adipiscing. Suspendisse quis leo eu velit laoreet hendrerit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec euismod nibh nec leo. Nullam sagittis fermentum ligula. Sed feugiat cursus elit. Pellentesque id tortor. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec vulputate leo ut neque rhoncus tristique. Aenean molestie, nisi a venenatis accumsan, mauris risus interdum tortor, et laoreet velit metus quis dui. Ut sed nunc. Quisque tempor. Suspendisse metus lectus, congue id, blandit quis, cursus eget, urna. Sed ac purus. Suspendisse sed eros sit amet risus eleifend pellentesque. Donec diam. Vestibulum vel mi. Aenean sagittis magna quis libero. Nunc scelerisque gravida metus. Aliquam nulla ante, rutrum vitae, vehicula et, pharetra sed, nunc. Nulla nulla enim, commodo vel, euismod id, convallis at, purus. Nulla pulvinar. Praesent et elit eget justo varius laoreet. Nunc ornare feugiat nisi. Aliquam vel felis eget erat semper sagittis. Aenean vel nisi. Aenean vehicula adipiscing enim. Nulla at sem. Sed commodo pretium erat. In turpis. Cras ullamcorper, magna non placerat vehicula, lacus justo condimentum leo, a tempus lorem leo vel nisl. Aliquam ut magna. Donec eu neque. Nunc semper quam vel est. Quisque eros tellus, vehicula sit amet, ultricies ac, facilisis vitae, dui. Morbi gravida, ligula vitae vestibulum facilisis, metus ipsum fermentum nunc, sit amet vehicula nisi urna non nunc. Ut non est vitae urna bibendum faucibus. Praesent at risus. Morbi nisi ante, ultrices tincidunt, accumsan et, lobortis quis, ligula. Proin nec est. Ut varius mollis dui. Etiam tortor purus, facilisis quis, viverra id, tincidunt vitae, dolor. Sed ullamcorper. Ut nec lacus. Phasellus ut metus a felis vulputate sagittis. Praesent magna. Morbi pretium placerat pede. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam at tortor sit amet sapien adipiscing lacinia. Aenean vitae enim. Vivamus adipiscing, mauris vel venenatis scelerisque, leo ligula lacinia orci, sed commodo dui nisi sit amet leo. Integer a est sed lacus pretium accumsan. Mauris scelerisque pulvinar leo. Vivamus tristique dui ut est convallis consequat. Phasellus turpis pede, fringilla non, sodales vitae, eleifend ac, lectus. Vestibulum eget nisi sed eros dapibus pretium. Fusce tincidunt pretium neque. Aenean elementum pulvinar lorem. Vivamus sit amet velit. Mauris quis arcu. Curabitur pede purus, suscipit sed, elementum in, dignissim at, dolor. Morbi eu odio. Ut ipsum nibh, egestas eu, tincidunt quis, lacinia quis, lorem. Vestibulum sollicitudin sapien a dolor. Mauris sit amet augue in diam condimentum semper. Etiam est. Fusce sit amet leo eget elit fermentum faucibus. Praesent ipsum quam, tristique ut, tempor eu, facilisis sed, sem. In vitae nisl. Nunc et pede vel augue malesuada tincidunt. Nulla felis. Etiam vel dui et nibh fringilla rutrum. Duis aliquet dui. Proin sed turpis ac tortor aliquet porttitor. Pellentesque congue venenatis est. Vestibulum in libero ut nulla condimentum porta. Aliquam erat volutpat. Vestibulum tincidunt. Donec at augue eu risus cursus venenatis. Suspendisse potenti. Ut consequat sem. Aliquam gravida est ac eros. Vestibulum sit amet mauris non diam tincidunt condimentum. Pellentesque commodo egestas diam. Phasellus semper risus at tellus. Duis eu enim. In ac augue sit amet sapien commodo tincidunt. Morbi convallis enim non tortor. Aliquam turpis. Quisque tellus nisi, porttitor in, consequat in, elementum quis, ipsum. Nulla id turpis ac nisi sagittis luctus. Praesent ipsum magna, vehicula at, luctus nec, accumsan convallis, odio. Curabitur non augue et risus commodo laoreet. Suspendisse commodo lacus sit amet orci. Pellentesque molestie tristique arcu. Aliquam erat volutpat. Praesent sit amet lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas ornare risus in tellus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Morbi luctus, nisl id laoreet aliquam, eros leo sagittis pede, vel venenatis dui odio venenatis quam. Quisque justo justo, lacinia sed, facilisis vel, dictum eu, erat. Proin ligula dolor, dapibus id, pellentesque id, consequat et, erat. In posuere. In sed est. Nam volutpat orci id nibh. Morbi convallis magna vitae mauris. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas felis. Donec condimentum. Sed pretium eros et est. Curabitur vel mauris. Sed tellus. Aliquam tristique facilisis metus. Nulla elit justo, sollicitudin eget, pulvinar eget, hendrerit vitae, est. Nulla semper dolor sed lorem. Morbi nisl. Proin pretium, ligula vitae pretium congue, turpis lacus bibendum magna, suscipit aliquet odio ligula nec risus. Mauris vestibulum. Pellentesque vehicula dolor sed nibh. Pellentesque id massa. Mauris sit amet justo quis turpis mollis tempor. Nullam vulputate velit at pede. Aenean fringilla ultrices magna. Proin urna tellus, faucibus in, blandit in, iaculis blandit, quam. Vestibulum turpis. Donec ornare aliquet justo. Integer velit. Sed at felis a arcu viverra congue. Suspendisse laoreet tortor at diam. Suspendisse quis arcu eget sapien condimentum molestie. Proin iaculis aliquet ipsum. Curabitur lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque in tortor. Curabitur imperdiet. Maecenas bibendum vestibulum nibh. Nullam vehicula lectus ac lectus. Morbi et lorem. Aenean sed metus. Cras commodo. Vestibulum a tortor. Duis pede nulla, posuere nec, hendrerit quis, faucibus id, nisl. Integer id purus nec quam aliquet ornare. Fusce euismod nibh ultricies pede. Quisque eget est hendrerit arcu mattis sollicitudin. Vestibulum viverra, lectus porta scelerisque venenatis, elit diam tempor ipsum, eu euismod nulla tortor eu orci. Praesent vulputate arcu vel magna. Maecenas blandit lectus. Aenean nunc orci, ornare vel, aliquam molestie, mattis non, sem. Fusce ac turpis et felis suscipit sodales. Nunc sollicitudin feugiat mi. Sed mattis fringilla magna. Quisque ut purus. Nunc tempus velit sed quam. Quisque mollis laoreet lorem. Integer eu augue. Morbi lobortis urna aliquam est. Maecenas eu tortor. Etiam commodo porta lectus. Ut vehicula, lorem id congue ultricies, augue ante pellentesque mauris, quis bibendum ante dui a dui. Aliquam varius mauris et neque. Vivamus consectetuer mauris eu elit. Cras vel nisi. Cras mollis sapien vitae tortor. In quis sem. Sed malesuada, eros non bibendum viverra, leo turpis iaculis ligula, nec auctor enim sapien nec magna. Vestibulum cursus, risus quis tempus aliquet, pede magna volutpat diam, tempor rutrum dolor dui a lacus. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum euismod varius elit. Fusce et erat a leo ultrices semper. Vestibulum a ante quis neque lacinia laoreet. Nullam nisi ipsum, vulputate a, molestie quis, ornare sed, felis. In posuere ligula non odio. Nulla eleifend viverra arcu. Sed mollis metus ac massa. Quisque vitae tortor sed est laoreet sagittis. Donec et justo. Pellentesque porta mauris ut turpis. Ut diam. Nulla neque lacus, commodo egestas, iaculis quis, porta a, nibh. Integer ultricies, libero quis hendrerit imperdiet, quam purus consequat ligula, vitae dignissim elit nisl non turpis. Morbi ut orci in diam luctus convallis. Vivamus ligula. Sed magna leo, aliquam at, hendrerit ac, feugiat non, justo. Sed lectus. Suspendisse elementum pretium tellus. Aenean egestas. Aenean faucibus porta purus. Nullam lorem dolor, iaculis vel, lobortis et, euismod a, eros. Donec eget mi. Sed vitae ligula eu massa cursus luctus. Nunc ullamcorper. Nunc purus nulla, feugiat et, vestibulum quis, hendrerit at, tellus. Sed risus massa, porttitor elementum, rutrum a, posuere sed, nulla. Etiam blandit egestas ligula. Proin rutrum dolor at odio. Quisque et nunc. Maecenas sed dolor. Donec suscipit mattis magna. Donec sit amet leo. Aenean lobortis dolor non elit. Cras vulputate consequat tortor. Etiam sodales porttitor ante. Morbi ut leo quis lacus lobortis eleifend. Nunc fermentum, nisl sit amet pretium egestas, velit eros tincidunt lectus, non vulputate ipsum urna vitae erat. Integer sit amet sem quis turpis varius posuere. Proin in metus vitae neque commodo tincidunt. Praesent iaculis fringilla justo. Vestibulum nec sapien. Curabitur eros. Duis commodo, diam non congue imperdiet, risus nisl auctor nunc, eget sodales magna sapien egestas sem. Vivamus id mauris. Phasellus dapibus, lectus at ornare lacinia, mauris sem imperdiet ligula, bibendum imperdiet lorem dolor at purus. Quisque ultrices nisi at augue viverra scelerisque. In vel risus. Fusce quam diam, luctus a, pharetra ac, tempor ac, lectus. Fusce neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nullam eget augue. Quisque in tellus vel lorem vulputate iaculis. Integer a pede. Integer vulputate molestie lorem. Donec velit magna, iaculis id, pretium in, aliquam nec, felis. Fusce nec libero sed velit egestas molestie. Maecenas turpis tortor, molestie in, hendrerit eu, tempor sed, enim. Fusce non orci. Suspendisse eleifend neque vitae odio. Quisque bibendum, justo a tristique gravida, sapien ante adipiscing nisl, non vehicula purus mi sit amet metus. Donec pharetra, felis nec interdum imperdiet, dui ipsum tempus diam, ac aliquam lorem libero vel nunc. Integer tincidunt adipiscing risus. Maecenas ante. Nunc vestibulum, nibh nec laoreet commodo, nibh erat tempor erat, ultricies mattis pede turpis luctus leo. Phasellus egestas ligula ac massa. Quisque tincidunt, erat ut volutpat ornare, neque eros tristique ante, sit amet bibendum turpis enim eget lectus. Pellentesque hendrerit lorem sed sem. Pellentesque semper elit non velit. Mauris nisl. Proin sed pede ac est mollis vestibulum. Nullam faucibus, lectus vel mollis accumsan, ipsum massa porta quam, id egestas turpis ante quis sapien. In aliquam ipsum in neque. Quisque id sapien. Morbi vitae elit. Nam leo eros, ullamcorper at, molestie a, mattis sit amet, augue. Pellentesque convallis suscipit elit. Nulla viverra. Nam ut erat. Duis metus. Mauris neque. Nulla eu odio elementum dolor adipiscing tincidunt. Aenean convallis, eros quis hendrerit luctus, dui tortor hendrerit ipsum, nec egestas nisl leo id tellus. Praesent eu turpis non tellus sodales semper. Duis quis enim sed nunc vulputate posuere. Proin leo. Proin mi risus, dapibus id, pretium sed, pharetra eget, diam. Aenean risus lacus, placerat quis, dictum dapibus, ullamcorper at, ipsum. Ut egestas sem sed quam. Nullam gravida lectus sed mauris condimentum accumsan. Nam ac pede. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Mauris varius bibendum ligula. Aenean neque. Nulla facilisi. Sed ultricies, lorem laoreet tempor ultricies, erat pede volutpat nibh, eget blandit quam massa hendrerit dolor. Fusce consectetuer, mauris id cursus eleifend, justo libero ultricies sapien, sed consectetuer odio mi eget elit. Vestibulum id arcu. Etiam tortor erat, accumsan vitae, pulvinar a, fringilla non, ligula. Maecenas venenatis semper urna. Quisque ac dolor. Nulla tellus. Quisque varius. Vestibulum non lacus. Phasellus iaculis. Duis pede. Praesent viverra lacus quis massa. Mauris eget dui. Proin aliquam, mauris eu dapibus viverra, pede nibh accumsan enim, sit amet aliquet nibh diam bibendum est. Nam dui. Morbi porta. Fusce scelerisque turpis ac arcu. Quisque quis erat. Nam sodales tellus et velit. Morbi vel arcu. Vivamus at nibh at odio congue scelerisque. In hac habitasse platea dictumst. Maecenas sed dui. Nulla turpis. Nulla rhoncus, quam lobortis tempor convallis, justo diam tristique erat, ut lobortis massa pede id magna. Donec purus. Cras tempus ligula eget nisi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse adipiscing sapien vitae enim. Donec egestas metus at sem. Sed in massa. Proin vulputate risus et nunc. Cras ut purus. Ut posuere semper eros. Praesent diam. Donec at lectus ac odio fringilla mollis. Mauris pede eros, faucibus in, cursus sit amet, adipiscing eget, ipsum. Donec malesuada laoreet purus. Sed mauris tellus, scelerisque eget, semper quis, vulputate non, leo. Sed quis dui sit amet enim facilisis faucibus. Sed sem. Quisque sit amet odio. In pellentesque scelerisque elit. In hac habitasse platea dictumst. Maecenas mattis massa quis lectus. Nam arcu. Nulla accumsan magna et ipsum. Donec felis erat, tristique ut, tincidunt a, elementum quis, metus. Aliquam erat volutpat. Vivamus ut orci pulvinar nisl condimentum varius. Etiam condimentum dui quis lectus. Donec ut sem sed nisl dictum pulvinar. Maecenas arcu enim, pretium vel, tincidunt quis, tristique pharetra, risus. Suspendisse pede lorem, luctus et, eleifend vitae, eleifend et, purus. Cras pretium est at tortor. Aenean ac ipsum et dolor dictum suscipit. Donec et magna vitae lectus malesuada facilisis. Cras dignissim. Morbi eget purus. Nulla in tellus. Ut turpis. Nunc imperdiet. Donec pretium pellentesque diam. Aliquam dapibus. Cras eu tellus ut erat tristique pretium. In hac habitasse platea dictumst. Phasellus lobortis. Proin a enim malesuada nunc luctus suscipit. Maecenas eu risus imperdiet ligula hendrerit tincidunt. Nunc egestas varius turpis. Proin sollicitudin ipsum. Maecenas hendrerit vehicula mi. Morbi sed magna eu libero egestas imperdiet. Fusce ullamcorper ultricies quam. Morbi quis ligula. Aliquam erat volutpat. Sed luctus. Duis eu risus. Mauris et turpis quis nisl sagittis lacinia. Aenean faucibus venenatis risus. Morbi tempor condimentum dolor. Integer sapien sem, scelerisque quis, tincidunt ut, fringilla sed, eros. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec eu lectus. Suspendisse malesuada leo eu ipsum. Aliquam condimentum nisi eget turpis. Ut nulla turpis, scelerisque in, rutrum in, sodales eget, turpis. Nullam pharetra euismod odio. Proin elit risus, pharetra vitae, ullamcorper in, posuere nec, magna. Donec semper lectus at sem. Morbi vitae libero. Quisque erat lectus, tempor vel, venenatis sed, dictum placerat, mauris. Integer malesuada. Quisque eget lacus. Aenean vitae enim in odio congue scelerisque. Fusce pellentesque accumsan erat. Praesent ante velit, sodales eget, tincidunt in, ullamcorper et, nisi. Sed vulputate. Sed fringilla, libero at aliquam tincidunt, odio lacus sagittis lectus, in volutpat est dui ornare nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Etiam id ligula sed ante congue pharetra. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur ornare adipiscing tellus. Suspendisse mattis. In vel elit laoreet dolor placerat elementum. Integer auctor nunc non tortor. Fusce accumsan metus vel tortor. Suspendisse vehicula mi vitae magna. Donec in purus vel libero hendrerit rutrum. Nunc rhoncus sapien ac sem. Nullam convallis malesuada arcu. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum sapien. Cras sem. Sed enim metus, porttitor in, imperdiet eget, placerat ac, sem. Mauris ipsum. Maecenas vitae lacus. Sed semper facilisis velit. Nam dignissim, felis sit amet tempus lobortis, libero metus dictum nisi, sit amet suscipit lorem odio non justo. Curabitur euismod, purus ac ornare egestas, orci massa tincidunt metus, et porta nulla nulla fringilla nibh. Aliquam id ipsum. Maecenas ac lorem. Nullam diam tellus, ornare ornare, convallis id, iaculis vitae, mi. Phasellus hendrerit. Cras malesuada pulvinar felis. Nunc id turpis vitae nisl vestibulum sollicitudin. Fusce elit risus, posuere vitae, mollis ac, commodo placerat, libero. Integer libero ipsum, congue ac, placerat non, sagittis nec, nibh. Vivamus sagittis, quam nec ullamcorper malesuada, libero magna dapibus dolor, in ornare enim leo non est. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec elit. Curabitur tempor sem vel lorem. In ullamcorper. Curabitur eu odio id mi commodo pulvinar. Nam ut nisi. Nulla consequat lorem ac lectus feugiat elementum. Integer tincidunt, leo et eleifend tempor, augue ipsum ullamcorper sem, pulvinar faucibus velit lectus a dolor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas nec mi sit amet lacus facilisis porttitor. Nam orci ante, dapibus eget, interdum in, hendrerit eu, augue. Aenean vehicula, ligula in porttitor volutpat, dui lectus mollis metus, sit amet tincidunt orci enim at nulla. Proin vestibulum vehicula orci. Aliquam erat volutpat. Fusce sit amet erat. Vivamus vestibulum pellentesque lectus. Fusce magna ante, pharetra quis, molestie sed, molestie vel, massa. Donec in erat at nunc sollicitudin euismod. Nunc et massa ut quam posuere vehicula. Cras fringilla ante vitae orci. Vestibulum mattis congue ligula. Duis eu pede eu odio tristique sodales. Curabitur sagittis venenatis ipsum. Etiam vitae lacus a mauris feugiat ultricies. Nulla convallis tortor et erat. Nunc nunc. Phasellus porta eros at dolor. Morbi placerat. Aenean non ipsum in libero euismod euismod. Maecenas vel justo. Proin sit amet orci adipiscing tellus tincidunt interdum. Pellentesque euismod nulla vitae est placerat lacinia. Donec malesuada, elit laoreet tincidunt sodales, lorem ligula consectetuer purus, ut rutrum mi neque eu sem. Phasellus ac odio. Vivamus lobortis. Aliquam erat volutpat. Nullam rutrum ipsum in dolor. Nullam vel libero. Duis lacinia lectus vel lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed sodales dolor. Proin rhoncus, lectus pharetra faucibus facilisis, diam ligula hendrerit leo, ac aliquet sem ipsum id arcu. Ut non erat eu risus ornare rhoncus. Mauris non lorem ut magna convallis rutrum. Integer est purus, venenatis in, euismod quis, feugiat vitae, leo. Suspendisse laoreet tellus eleifend neque. Sed vitae arcu nec pede tempus hendrerit. Mauris commodo, leo ultricies venenatis consectetuer, turpis tellus hendrerit diam, eget lacinia diam tortor in leo. Etiam luctus orci ut sem. Donec sed mi sit amet erat pharetra ullamcorper. Phasellus dolor diam, euismod et, pharetra ut, convallis sed, orci. Nam vitae lorem. Vivamus et nulla. Suspendisse vel tellus sed quam blandit rhoncus. Proin convallis erat vel dolor. Proin ut leo. Quisque ut pede non augue vestibulum egestas. Donec interdum justo eget dui. Nunc malesuada neque et felis. Donec eu dolor. Aenean in dolor vehicula diam bibendum auctor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed molestie laoreet nisi. Mauris condimentum magna quis massa. Nulla faucibus. In leo. Morbi vitae dolor. Aliquam erat volutpat. Sed euismod. Fusce pede. Nullam ipsum mauris, ultricies tempor, laoreet eu, pretium ac, sem. Praesent accumsan risus quis mi. Curabitur id nisi. Fusce imperdiet. Proin vitae velit. Vivamus eget urna vitae metus ultrices sodales. Mauris vel mi. Phasellus nisi metus, auctor sed, facilisis id, volutpat a, nisi. Nulla sagittis. Duis vitae nisl. Phasellus felis tortor, cursus vitae, convallis et, fringilla egestas, eros. Pellentesque nunc lectus, mattis laoreet, sollicitudin eu, imperdiet auctor, quam. In hac habitasse platea dictumst. Integer lectus nibh, tincidunt accumsan, sagittis nec, viverra vel, pede. Integer porttitor varius nulla. Aenean consectetuer leo a nunc. Suspendisse vel risus. Pellentesque sed eros. Aenean consectetuer diam ac diam. Sed varius semper tellus. Mauris condimentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam eget enim. Vivamus felis ante, porttitor a, cursus eget, cursus eu, quam. Aliquam consequat consectetuer lectus. Cras non tellus. Aliquam bibendum hendrerit ipsum. Phasellus auctor ullamcorper nunc. Suspendisse tempor neque at sapien. Quisque malesuada libero quis ipsum. Sed pellentesque pellentesque est. Aenean rhoncus magna eget arcu. Praesent dignissim. Duis magna. Praesent nunc nibh, sagittis vitae, iaculis sed, facilisis a, orci. Nunc eu lectus id velit porta commodo. Aliquam a tortor. Nullam hendrerit lacinia velit. Curabitur et velit ac libero tempus sollicitudin. Praesent aliquam dui eu enim. Aliquam erat volutpat. Duis quis risus. Sed sit amet metus eget odio porta iaculis. Duis lacinia, nibh vel hendrerit malesuada, odio quam eleifend sem, non aliquam nisi lectus ut nisl. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus sodales. Cras euismod ligula quis velit egestas commodo. Vestibulum vulputate ornare quam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus convallis ligula id nunc. Nam consequat felis condimentum pede. Etiam nec risus. Mauris vehicula laoreet enim. Quisque nisl urna, tincidunt eget, congue non, rhoncus eu, odio. Ut quis velit. Aenean semper purus in tellus. Duis sagittis auctor sapien. Ut dapibus mi in lorem. Ut nunc. Phasellus id purus. Etiam ultrices. Sed nec nisi. Praesent ac augue nec turpis sodales cursus. Praesent et quam et turpis tempor mattis. Ut a velit eget enim feugiat pharetra. Cras blandit enim non ante. Aliquam erat volutpat. Quisque nulla arcu, eleifend ac, mollis a, congue at, leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin malesuada imperdiet sem. Cras a justo. Suspendisse volutpat mi in nunc. Vestibulum placerat sagittis arcu. Vivamus pede. Vivamus ultrices risus at leo. Nulla egestas adipiscing mi. Quisque cursus mi non arcu. Nulla congue. Donec dictum imperdiet diam. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin quis mi. Duis odio. Morbi tincidunt enim in mauris. Duis mi enim, dapibus a, suscipit ac, porttitor eu, leo. In aliquam, dolor vitae congue hendrerit, lacus risus consequat risus, ut molestie mauris purus a ligula. Nullam sit amet diam. Etiam congue malesuada dolor. Integer dictum. Fusce facilisis. Quisque neque velit, feugiat a, egestas quis, tempor a, magna. Fusce ligula. Praesent tincidunt mollis diam. Aenean libero neque, suscipit nec, volutpat in, ultrices sed, turpis. Etiam consequat bibendum arcu. In turpis. Pellentesque et odio. Proin ac lectus vitae elit malesuada sodales. Aenean bibendum enim ut nulla. Suspendisse turpis est, tempus non, cursus eget, pulvinar eget, nibh. Aliquam erat volutpat. Etiam risus urna, accumsan vel, pellentesque in, commodo sit amet, nisl. Nulla eget sem sed nulla porta egestas. In tempus est nec justo. Aenean placerat. Aenean commodo nulla nec magna commodo luctus. Nunc mollis sem sed metus. Sed vitae libero et felis varius dapibus. Maecenas at orci. Etiam quam turpis, interdum vel, interdum vitae, dapibus sit amet, pede. Suspendisse consectetuer velit dictum arcu. Vestibulum dui dolor, vehicula et, ultricies ut, facilisis et, enim. Duis eu neque id diam tempus ornare. Phasellus luctus faucibus ante. Morbi id enim ut dolor interdum volutpat. Nam non nunc. Nulla sagittis enim vitae mi. Fusce sit amet odio. Nulla elementum, massa ac tempus suscipit, leo magna tristique urna, ac gravida eros nisl sit amet est. Curabitur posuere mattis mauris. Integer pellentesque sodales velit. In scelerisque metus. Suspendisse potenti. Duis felis. Nunc vitae enim eget metus tempus egestas. Suspendisse potenti. Integer viverra sollicitudin nunc. Curabitur lectus. Sed faucibus. Fusce justo. Nulla facilisi. Donec viverra lorem sit amet ipsum aliquet imperdiet. Maecenas quis est. Cras nibh nisi, pellentesque sit amet, porttitor vitae, adipiscing vitae, massa. In hac habitasse platea dictumst. Etiam dignissim. Integer neque libero, consectetuer quis, egestas sit amet, feugiat sed, tellus. Nullam sagittis erat id purus. In erat pede, cursus ut, posuere eu, laoreet non, urna. Sed elit enim, placerat eu, rutrum non, consectetuer vel, purus. Curabitur eget magna. Phasellus ultrices velit at ipsum. Praesent posuere consectetuer lorem. Donec dapibus libero a eros. Phasellus convallis luctus quam. Vestibulum est dui, viverra id, feugiat eu, malesuada eget, mi. Fusce bibendum arcu vitae justo suscipit ullamcorper. Sed a augue rutrum nisi gravida volutpat. Maecenas consequat rutrum felis. Aliquam neque libero, dignissim ut, ullamcorper vel, luctus eu, enim. Donec mollis consectetuer ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Curabitur sed nulla ac libero dapibus pretium. Proin auctor imperdiet justo. Curabitur est mauris, tristique a, rutrum vel, vulputate vitae, augue. Proin purus nulla, pharetra id, faucibus quis, venenatis a, nunc. Sed tincidunt elementum turpis. Mauris nibh tellus, accumsan et, mattis eu, pulvinar eget, sem. Nulla facilisi. Mauris pulvinar dignissim eros. Fusce nec orci vitae lectus feugiat lobortis. Etiam velit turpis, aliquam sit amet, lacinia eu, mattis ut, ipsum. Praesent ut massa a quam scelerisque gravida. Suspendisse ullamcorper faucibus pede. Vivamus turpis. Mauris suscipit. Integer vel dui. Curabitur a enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut dapibus molestie dolor. Curabitur at mauris. Nullam luctus risus ut lectus. Phasellus imperdiet tellus et massa. Cras vulputate, arcu sit amet tempor suscipit, libero orci pharetra nibh, in pharetra massa lorem nec mi. Aenean sodales auctor orci. Aliquam euismod tincidunt velit. Maecenas urna nulla, congue dapibus, semper at, faucibus ultricies, dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis tincidunt aliquam nisl. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce commodo, eros ut adipiscing luctus, libero risus mollis ipsum, et vulputate lorem purus vel lacus. Nullam lectus neque, vehicula eget, eleifend ac, aliquet eu, enim. Praesent orci tellus, convallis vitae, aliquet eget, suscipit vel, ligula. Curabitur eleifend elit non sem. Fusce ut quam. Mauris at ipsum eget justo mattis pretium. Phasellus eu enim. Vestibulum suscipit purus at libero. Fusce vitae leo. Aenean cursus. Nunc ullamcorper augue nec enim. Fusce et est sit amet nisl sodales volutpat. In malesuada enim sed mauris. Aliquam et felis. Pellentesque euismod consequat erat. Aliquam pharetra diam sed erat. Nullam placerat, neque quis condimentum semper, lectus purus auctor metus, nec luctus nibh lectus in elit. Nullam faucibus pellentesque nunc. Suspendisse potenti. Curabitur commodo metus eu odio. Nulla porttitor consequat diam. Nam pretium ornare ante. Integer congue, elit ut commodo pellentesque, lectus urna luctus felis, et rhoncus magna libero pretium est. Mauris diam. Curabitur fringilla justo vel tortor. Mauris justo eros, adipiscing non, laoreet et, mattis in, tortor. Vestibulum vel justo non augue lacinia sollicitudin. Duis et libero eu nibh adipiscing sollicitudin. In sem. Quisque dictum ultrices lacus. Mauris quis orci. Ut aliquet eros ut mauris. Pellentesque ultrices. Aliquam erat volutpat. Nullam feugiat blandit lacus. Fusce vulputate, ante sit amet eleifend viverra, arcu augue feugiat urna, porttitor interdum sem ligula cursus sapien. In vitae augue nec sapien tincidunt dignissim. Morbi tincidunt aliquet mauris. Donec pellentesque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Cras ligula sem, eleifend sit amet, iaculis quis, varius ut, ante. Morbi dapibus eleifend magna. Nullam dapibus rhoncus tellus. Nam quis tortor. Cras arcu nunc, sagittis eu, malesuada varius, tempus et, lorem. Etiam sit amet metus. Praesent arcu. Aenean et metus. Quisque sem enim, posuere id, feugiat nec, gravida ut, neque. Maecenas semper, justo sit amet dapibus dapibus, purus justo facilisis purus, non fringilla eros ligula a neque. Donec nisi. Integer mattis, lacus in ullamcorper lobortis, risus massa aliquet ligula, eget auctor leo orci sit amet nisi. Aenean diam. Ut tristique quam eu velit. Curabitur sed mi eget arcu sodales aliquet. In sed risus. Sed et mi. Etiam sagittis enim tincidunt est. Cras vel est vel eros tincidunt consectetuer. Etiam eu sapien ac orci vestibulum dapibus. Sed ut est eu est euismod hendrerit. Pellentesque vitae orci non libero varius dignissim. Praesent iaculis, ligula id euismod interdum, lacus risus porttitor quam, a adipiscing mi augue at diam. Nulla iaculis iaculis turpis. Vivamus nec nunc quis libero ornare ullamcorper. Praesent imperdiet posuere dui. Etiam vulputate vestibulum urna. Cras cursus hendrerit ipsum. Praesent felis ante, posuere sed, mattis quis, sollicitudin ut, lorem. Donec nec odio. Sed luctus odio eu risus. Sed sem nisl, tincidunt quis, hendrerit et, facilisis non, mauris. Aliquam non felis. Integer sed lacus vitae dolor pulvinar condimentum. Etiam lobortis, libero quis tincidunt lacinia, nibh nisi iaculis quam, eu condimentum massa purus a turpis. Suspendisse potenti. Morbi vitae lacus ac tellus pulvinar mollis. Nam auctor fringilla sem. Morbi lacus elit, pellentesque at, mattis nec, volutpat feugiat, lectus. Phasellus eros ligula, molestie at, pulvinar id, eleifend vel, ante. Fusce facilisis, diam luctus interdum condimentum, libero justo venenatis tellus, molestie ullamcorper ante diam ac sem. Pellentesque tempus, ligula ac pellentesque vulputate, eros velit aliquet lacus, eu dignissim urna leo a diam. Suspendisse quam ipsum, ullamcorper sed, dignissim vehicula, facilisis ut, tellus. Fusce convallis, odio a malesuada pharetra, orci risus sagittis urna, sit amet tincidunt ligula pede vitae leo. Quisque augue. Phasellus scelerisque nisl sed purus malesuada pretium. Pellentesque condimentum tempus ipsum. Vivamus auctor metus sed sapien. Nulla tristique congue magna. Vestibulum iaculis urna ac risus. Nullam fringilla suscipit ipsum. Quisque euismod. Quisque ullamcorper pede tincidunt risus. Sed tortor pede, rutrum ac, varius sed, sagittis nec, orci. Phasellus arcu orci, bibendum quis, tempus id, consequat eu, velit. Phasellus commodo congue purus. Sed malesuada, pede eu volutpat tristique, tellus mauris vulputate nibh, a faucibus lorem enim nec nulla. Nunc semper, nisl iaculis rutrum consectetuer, leo eros egestas lacus, sit amet venenatis dolor ligula non lorem. Morbi feugiat. Donec vulputate. Vivamus at sapien sit amet est feugiat elementum. Donec nisl erat, tincidunt ornare, pellentesque vel, aliquet sit amet, eros. Duis sagittis porta sapien. Etiam a dui. Praesent lobortis nisl at lorem. Sed malesuada. Morbi viverra dui eu neque. Nullam sed ante sed diam malesuada vehicula. Morbi ut metus et dolor hendrerit vehicula. Integer in lacus nec dui aliquet dictum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse et mauris vitae dui lacinia ultrices. Mauris neque sem, sagittis sed, lobortis viverra, pharetra vitae, mi. Nam dui nunc, iaculis id, dictum at, porttitor vitae, diam. Donec tincidunt leo quis augue varius rhoncus. Nam risus. Vivamus dignissim. Praesent viverra, neque vitae vulputate blandit, dui massa rhoncus lectus, quis accumsan neque quam sit amet augue. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut congue pellentesque velit. Vivamus at elit. Cras risus metus, elementum ut, tristique nec, commodo in, sapien. Etiam metus. Maecenas congue, justo vitae egestas volutpat, orci quam aliquam mi, vitae pulvinar tortor pede vel nunc. Integer mollis, massa sit amet vestibulum fringilla, nulla tortor pretium nibh, eget porttitor nisi elit sit amet magna. Proin dignissim, nisl eget posuere posuere, velit diam ultrices turpis, a lacinia nunc dolor quis odio. Nulla egestas. Nam consectetuer. Pellentesque enim libero, viverra eget, dapibus ut, iaculis ac, neque. Donec vel tortor. Sed eu urna ut libero pharetra viverra. In hac habitasse platea dictumst. In dictum. Morbi non magna sit amet elit dictum facilisis. Sed ultrices porta urna. Vivamus tincidunt. Ut ante orci, pellentesque a, aliquet ut, dignissim eu, velit. Integer ultrices congue felis. Sed faucibus vestibulum augue. In lectus urna, vulputate non, dignissim id, placerat in, ante. Aenean mi erat, eleifend at, faucibus in, gravida eget, massa. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse potenti. Donec dignissim elit vel felis. Vestibulum gravida tortor ut massa. Nulla facilisi. Nulla imperdiet urna sed nibh. Suspendisse volutpat, nulla eget dignissim elementum, leo velit bibendum leo, ac viverra mi nisl nec mi. Vivamus et libero vel erat mattis semper. Cras hendrerit porttitor sapien. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc elementum condimentum orci. In hac habitasse platea dictumst. Donec massa quam, laoreet in, sagittis nec, porta eu, tortor. Integer eget dui. Nulla quis purus in justo tristique adipiscing. Ut eleifend placerat orci. Sed neque. Sed ultrices eros vitae eros. Praesent venenatis laoreet orci. Vivamus non elit. Aliquam varius tellus non erat. Vivamus ullamcorper magna sit amet lectus. Mauris venenatis, elit vel lobortis dapibus, eros lacus feugiat erat, in tincidunt dui libero a orci. Duis non nisi. Nulla aliquet, nunc vel vestibulum lobortis, est lorem luctus mi, ut sodales felis dolor vitae dolor. Fusce eget felis. Pellentesque tempus eros ut justo. Curabitur aliquet. Duis rutrum sapien sit amet lectus. Curabitur tellus. Nulla laoreet sapien at ante. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce lacinia venenatis sem. Mauris sagittis. Proin posuere nibh id pede. Maecenas hendrerit placerat nisi. Sed vitae justo quis ante pellentesque sollicitudin. Morbi in est. Nulla velit nibh, tempus non, tincidunt eget, ornare at, dui. Praesent fringilla magna id magna tincidunt mattis. Morbi vestibulum. Donec ut nisl. Duis turpis nulla, feugiat vel, commodo at, hendrerit eu, purus. Cras nec libero. Nullam vestibulum dolor et metus scelerisque vestibulum. Aliquam sed felis. Nulla dolor diam, placerat vitae, gravida eget, tincidunt consectetuer, pede. Maecenas auctor, felis vulputate placerat sollicitudin, sapien purus dapibus purus, condimentum sollicitudin sapien purus eget magna. In at est a mi placerat congue. Maecenas et leo. Praesent ac nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vel mi quis lacus congue consequat. Duis laoreet ipsum et odio. Duis pede orci, aliquam eget, rutrum et, faucibus tincidunt, dui. Donec aliquet enim vitae diam. In hac habitasse platea dictumst. Integer pede. Phasellus feugiat ullamcorper sem. Maecenas eu turpis. Maecenas dapibus leo varius neque. Mauris convallis, velit ut interdum pulvinar, est dolor elementum lacus, ut placerat neque est at dolor. Donec aliquet purus. Etiam quam urna, pharetra ut, consequat at, lacinia at, velit. Curabitur metus lacus, tincidunt sit amet, pharetra non, suscipit vel, quam. Ut lacus ante, ullamcorper porta, malesuada venenatis, vulputate et, dui. Nam posuere lacus eu urna. Sed ac erat vel nisl venenatis pharetra. Nullam egestas lectus non lorem. Maecenas mi neque, sodales a, ullamcorper aliquam, semper in, elit. Donec nec risus ultricies libero tincidunt accumsan. Sed rutrum neque tristique lacus. Fusce nulla ligula, vulputate et, pellentesque eget, varius ut, odio. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In quis risus non pede egestas imperdiet. Maecenas faucibus, purus id pulvinar sagittis, libero arcu pharetra lacus, sit amet auctor lorem tortor non urna. Suspendisse semper, sem vitae consectetuer molestie, nunc erat feugiat quam, non placerat augue mauris eu metus. Aliquam eleifend, justo sed ullamcorper auctor, elit sem rhoncus turpis, quis pellentesque nibh risus at enim. Cras dui. Vestibulum eget dolor. Sed faucibus. Praesent a odio feugiat quam scelerisque egestas. Fusce a ante non ante blandit congue. Aenean vestibulum. In hac habitasse platea dictumst. Ut consequat. Nam tincidunt est nec libero. Maecenas quis odio eu nisl vulputate pretium. Phasellus fermentum feugiat metus. Curabitur convallis fermentum erat. Donec ac lorem sit amet augue fringilla fringilla. Vestibulum neque ligula, consequat vitae, gravida posuere, vulputate ut, metus. Suspendisse potenti. Phasellus blandit. Quisque commodo odio at mi ultricies aliquet. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec condimentum, leo ac aliquam vehicula, metus augue lacinia tellus, ut dictum nisl orci ac neque. Nam a tellus. Praesent vitae nisl non augue laoreet adipiscing. Nullam at justo sed dolor placerat mattis. Nam varius nisl et urna. Sed bibendum, augue lobortis vestibulum ornare, nibh odio pharetra purus, quis eleifend est sapien sit amet lorem. Aenean viverra ante non libero. Ut posuere. Mauris arcu lacus, sodales in, condimentum ac, accumsan vitae, mi. Aliquam sodales dignissim purus. Donec at arcu. Vestibulum eleifend. Pellentesque dui. Phasellus sem. Sed ornare nisi lobortis ligula. Etiam est. Etiam leo lorem, auctor ut, molestie facilisis, tristique eu, sem. Morbi lorem. Mauris pede dolor, aliquam bibendum, facilisis sed, vehicula eu, nibh. Integer aliquet. Aliquam posuere, odio in sollicitudin luctus, nibh arcu vulputate mauris, sit amet eleifend risus magna ut leo. Nullam consectetuer semper dui. Donec dignissim justo interdum nisl vestibulum egestas. Donec sit amet arcu nec tellus sollicitudin eleifend. Ut auctor leo eget turpis. Integer commodo mattis neque. Vivamus vitae orci. Morbi quam quam, convallis vel, dignissim pretium, ultricies eu, dolor. Cras non est quis nisl faucibus sodales. Mauris euismod vulputate mauris. Duis vehicula feugiat orci. Nulla facilisi cras amet. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFI1aQDwJfZ7JTAY2MRApDhAKD0iljS+FCCf/9K0Bw6KyGhNZ23oACghI1J H/Ba8Y+h0pW1XUVSaTgDkd6IPwMFAUjVpAMDzIkK+h2tSxECkOEAn1iVmj+tIpeX MXRjHGvufGX+Vp3NAJ975VhAY0/9zeDHeFeJhXSAxx4gbA== =REia -----END PGP SIGNATURE----- Crypt_GPG-1.4.0/tests/data-files/testVerifyFileDualNormalSignedData.asc0000664000175000017500000004464412610161626024435 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) owG9ec+rbWt21TPP6mwIpFraCWzSSGtxFdR0SpDivYTcVN6lQnHSiajr7r3uuUv2 j/P2XuuAVBDtmYZJBQMBpTCNsiFYYEN7Nl7DZoGKpJFO/gAp0NgR0/Kbc4wx5/z2 OZcXX+WkUfXuOWfvtb5v/hhjzDG/99Mff/RTX//4R7+1+dOf/eG3Pvqe//jF7//R j3/vi93uL/3wi//89ueW6br8+nSZ3/2jX5oP06freHhzvhzHw3fm+9O0/3Rcxl/+ wx98/Kvny3Tczg/X9bjdnw/ny/Y6L9vxOC3Ddnc+XafdMi3rdNmO+/lhvu7m0/12 OszLq+2vz4/jcb1uD+tuaf95OIy76TIuW/u/V9tP1sv4dl7Wy3Za5+vxvN+Ol926 nfft7+frq+1n47SbTuN1O+526/E6nrYP037azqft+bKb+1cvl/m6zJ+v06vt3bI9 Tbvtu3aE6/Z0Pm1P62kXrzhfTuMFn9qvs79piD9299rPx+m0tDu3pw3bx/Eytyvk Jw7TuV3h0o7nkbHrHLfX8262t47LuZ2lnbf9a37bvjct2+N4f2p/27f/PYyXdu25 PX57PJ9aFob2letuslhc5v28Ww/tOy1yr7afrvb582UZ27/PdrHTZI+2p41DC8Yy XfbtzdM6tEfv/LznUzvv/DhdLuO2faYl+dX225dxutoLH6cDHmEBboe4to8u4+RR Kh/bnY8tImcP0Ha6nxYm5Y0Fs0XnHg9ghj63Ux7H63XcXqeWx3aq7X588Ks/tve3 fxwsRt+xP3rkebMjjnBaD4d20ut5Px4m+8ph2C7zaTfv13aWdck/jS0Xy3Q4eGw8 HvbV4+58eZgu5UTX8+Ew71p17Vu9XMf7eVnae5C0F0nUt9+PVz+Xv2SziZM8nK+t Qi1a58vbGVEqB0VHebVaBu3V11lFtx4e1mVswbQAD9ux9VH7sIfnMFlPIaSH+W3L DsvxOFsaz+3a0W/4OxPtL4xiUn94WczXOQL9btzN7Uzz1Xtl3LYX+7tRLF6D02Ga 302n/fby/nza+WHWawtli9x1ak98b/EZdVR+tX2JfeVVbXcejyizFthDQ6OrPfs6 HQdLRvQ+qss7f9yurYsTXhjhQRXIHs20P6yHx7n1vXetow9LeNs+tjoA6BctZO2J vOx8YoG2d0UVR2EfgIunbauGB/tMAtp4MCxatveX8XHej+0AFwvP61ZC9w2tvF0A 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 3/nrf+9PPvnd+d/+u9/4xo//1j/5y9/6b/8P =8gcy -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/data-files/testVerifyFileNormalSignedData.asc0000664000175000017500000004440212610161626023617 0ustar alecalec-----BEGIN PGP MESSAGE----- Version: GnuPG v1.4.6 (GNU/Linux) owG9eT2rbFt2XVuNHRxwoMCpKYMzb15iMAZhjJAs9ED9kGmuHDja75x6925Rp+p0 1a6LHShwZowDBwIlxh+g1IFTg3EHzpxKgWJHAv0BZV5zfMw5V937aPlJV0H3u+ec qr3Xmh9jjDnmf/jbP/7RL/3yz//gT/7s93/+/Pw3/tvPf/7t392Pt/13jtftu3/9 G9vp+M3l+rqefrq9Px9ffn3d19/84z/88W9drsfXw/Z2u78eXi6ny/Vw2/bD+nrc l8Pz5Xw7Pu/H/X68HtaX7W27PW/n94fjadu/OvzO9nF9vd8Op/vzPv7zdlqfj9d1 P8T/fXX4tft1/Xbb79fD8b7dXi8vh/X6fD9sL+Pvl9tXh5+sx+fjeb0d1ufn++tt PR/eji/Hw3Y+XK7P2/zq/brd9u1n9+NXh3f74Xx8Pnw3jnA7nC/nw/l+fs5XXK7n 9cpPvdw3vGnJP073etlej+d93Hk8bTl8XK/buEJ94nS8jCtcx/EQmbjO6+F2ed7i ret+GWcZ5x3/2r4d3zvuh9f1/Xn87WX87229jmtv4/GH18t5ZGAZX7k9HyMW1+1l e76fxndG5L46/Po9Pn+57uv49yUudj7Go+Np6zKCsR+vL+PNx/syHv2M817O47zb x+P1uh7GZ0aCvzr89nU93uKFH48nPiICPA5xGx/d1yOi1D72fHkdEbkgQIfj++Ou pHwTwRzRec8HKEM/i1O+rrfbergdRx7HqQ4v6xuu/nG8f/zjFDH6afwRkdfNXnmE 8/10Gie9XV7W0zG+cloO+3Z+3l7u4yz3vf60jlzsx9MJsUE84quvz5fr2/HaTnS7 nE7b86iul1Evt/X9tu/jPUzaF0nUb39YbzgXXvL0lCd5u9xGhUa0LtdvN0apHZQd hWqNDMarb5uL7n56u+/rCGYEeDmso4/GhxGe0zF6iiE9bd+O7KgcX7dI42VcO/uN f1ei8cIsJvcHymK7bRno79bnbZxpu6FX1sN4Md7NYkENHk/H7bvj+eVw/XA5P+Mw 99sI5Yjc7Tie+CHis/qo+ur4kvoKVR13Xl9ZZiOwp4FEt3j27fi6RDKy91ld6Pz1 cB9dXPCiCC+uQPVopf3tfvq4jb5H1wJ9VMKH8bE7AMC/GCEbT9Rlt7MKdLwrqzgL +0RcPB9GNbzFZwrQ1lNg0X54f10/bi/rOMA1wvP1KKH3A63QLgSoFR05TiyAOa3j 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 +n8= =u8ey -----END PGP MESSAGE----- Crypt_GPG-1.4.0/tests/config.php.dist0000664000175000017500000000120512610161626015767 0ustar alecalec * @copyright 2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id:$ * @link http://pear.php.net/package/Crypt_GPG */ $GLOBALS['Crypt_GPG_Unittest_Config'] = array( 'enable-key-generation' => false, ); ?> Crypt_GPG-1.4.0/tests/DecryptAndVerifyTest.php0000664000175000017500000013505412610161626017654 0ustar alecalec * $ phpunit DecryptAndVefifyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests decrypt verify abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class DecryptAndVerifyTestCase extends Crypt_GPG_TestCase { // string // {{{ testDecryptVerify() /** * @group string */ public function testDecryptVerify() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('5dGf4//0CqBmlexYjyS7agt4Zn4'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258956392); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with first-keypair@example.com, signed with // first-keypair@example.com // {{{ encrypted data no passphrase $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyNoPassphrase() /** * @group string */ public function testDecryptVerifyNoPassphrase() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('0YWPoUQhN5G4uTi45QLy3GG3RWg'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258956262); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with no-passphrase@example.com, signed with // first-keypair@example.com // {{{ encrypted data no passphrase $encryptedData = <<gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyKeyNotFoundException_decrypt() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testDecryptVerifyKeyNotFoundException_decrypt() { // was encrypted with missing-key@example.com, signed with // first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyKeyNotFoundException_verify() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testDecryptVerifyKeyNotFoundException_verify() { // was encrypted with first-keypair@example.com, signed with // missing-key@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyKeyNotFoundException_both() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testDecryptVerifyKeyNotFoundException_both() { // was encrypted and signed with missing-key@example.com // {{{ encrypted data $encryptedData = <<gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyNoDataException_invalid() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testDecryptVerifyNoDataException_invalid() { $encryptedData = 'Invalid OpenPGP data.'; $this->gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyNoDataException_empty() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testDecryptVerifyNoDataException_empty() { $encryptedData = ''; $this->gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyBadPassphraseException_missing() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testDecryptVerifyBadPassphraseException_missing() { // encrypted with first-keypair@example.com, signed with // first-keypair@example.com // {{{ encrypted data no passphrase $encryptedData = <<gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyBadPassphraseException_bad() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testDecryptVerifyBadPassphraseException_bad() { // encrypted with first-keypair@example.com, signed with // first-keypair@example.com // {{{ encrypted data no passphrase $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'incorrect'); $this->gpg->decryptAndVerify($encryptedData); } // }}} // {{{ testDecryptVerifyDual() /** * @group string */ public function testDecryptVerifyDual() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('TAsI7RYUgZAud0wMZu3Iab3bZXo'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258955651); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with both first-keypair@example.com and // second-keypair@example.com, signed with first-keypair@example.com // {{{ dual encrypted, signed data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyDualOnePassphrase() /** * @group string */ public function testDecryptVerifyDualOnePassphrase() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('3OJnX+PqHI0YUCeFxICCxhPHY1Q'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258955916); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with both first-keypair@example.com and // no-passhprase@example.com, signed with first-keypair@example.com // {{{ dual encrypted, signed data $encryptedData = <<gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyDualSignatories() /** * @group string */ public function testDecryptVerifyDualSignatories() { // {{{ signature1 $signature1 = new Crypt_GPG_Signature(); $signature1->setId('7PujVkx4qk28IejcD6BirrwBmRE'); $signature1->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature1->setKeyId('C097D9EC94C06363'); $signature1->setCreationDate(1258956025); $signature1->setExpirationDate(0); $signature1->setValid(true); $userId1 = new Crypt_GPG_UserId(); $userId1->setName('First Keypair Test Key'); $userId1->setComment('do not encrypt important data with this key'); $userId1->setEmail('first-keypair@example.com'); $signature1->setUserId($userId1); // }}} // {{{ signature2 $signature2 = new Crypt_GPG_Signature(); $signature2->setId('AhrDdkdcBsEsOSQOYENhl5C7auc'); $signature2->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $signature2->setKeyId('03CC890AFA1DAD4B'); $signature2->setCreationDate(1258956025); $signature2->setExpirationDate(0); $signature2->setValid(true); $userId2 = new Crypt_GPG_UserId(); $userId2->setName('Second Keypair Test Key'); $userId2->setComment('do not encrypt important data with this key'); $userId2->setEmail('second-keypair@example.com'); $signature2->setUserId($userId2); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature1, $signature2) ); // encrypted with first-keypair@example.com and signed with // first-keypair@example.com and second-keypair@example.com // {{{ encrypted, dual signed data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifySignedOnly() /** * @group string */ public function testDecryptVerifySignedOnly() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('LS9EdhGLaEUllGk3Snc0Bk+Cn3E'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258956761); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // signed with first-keypair@example.com // {{{ signed data $signedData = <<gpg->decryptAndVerify($signedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyFirstSubKey() /** * @group string */ public function testDecryptVerifyFirstSubKey() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('YUeHL9fEAK4hMokvXsNgUP5vaJ8'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1267228319); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with first subkey (ELG-E) of multiple-subkeys@example.com, // signed with first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('multiple-subkeys@example.com', 'test'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifySecondSubKey() /** * @group string */ public function testDecryptVerifySecondSubKey() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('ZLZFDxxO+zdCEklUu6eppBCPCsA'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1267229043); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => array($signature) ); // encrypted with second subkey (RSA) of multiple-subkeys@example.com, // signed with first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('multiple-subkeys@example.com', 'test'); $results = $this->gpg->decryptAndVerify($encryptedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifySignedOnlyBadSignature() /** * @group string */ public function testDecryptVerifySignedOnlyBadSignature() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setValid(false); $signature->setKeyId('C097D9EC94C06363'); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedResults = array( 'data' => "Hello, Bob! Goodbye, Alice!\n", 'signatures' => array($signature) ); // {{{ clearsigned data $clearsignedData = <<gpg->decryptAndVerify($clearsignedData); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // file // {{{ testDecryptVerifyFile() /** * @group file */ public function testDecryptVerifyFile() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('kVwy2yYB0TlXyGd9FUvVYp5jCoI'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258220197); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature) ); $inputFilename = $this->getDataFilename('testDecryptVerifyFile.asc'); $outputFilename = $this->getTempFilename('testDecryptVerifyFile.plain'); // file is encrypted with first-keypair@example.com $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptVerifyFileToString() /** * @group file */ public function testDecryptVerifyFileToString() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('GTvYFmQ5yfMM/UOffkYCx21Se2M'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258221035); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedSignatures = array($signature); $expectedResults = array( 'data' => 'Hello, Alice! Goodbye, Bob!', 'signatures' => $expectedSignatures ); $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileToString.asc' ); // file is encrypted with first-keypair@example.com $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($inputFilename); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); } // }}} // {{{ testDecryptVerifyFileNoPassphrase() /** * @group file */ public function testDecryptVerifyFileNoPassphrase() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('unMY9l/f9sFaMvMV0H1ZuNJRY6Q'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258220226); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature) ); $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileNoPassphrase.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileNoPassphrase.plain' ); // file is encrypted with no-passphrase@example.com $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptVerifyFileFileException_input() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testDecryptVerifyFileFileException_input() { // input file does not exist $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileFileException_input.asc' ); $this->gpg->decryptAndVerifyFile($inputFilename); } // }}} // {{{ testDecryptVerifyFileFileException_output() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testDecryptVerifyFileFileException_output() { // input file is encrypted with first-keypair@example.com // output file does not exist $inputFilename = $this->getDataFilename('testDecryptVerifyFile.asc'); $outputFilename = './non-existent' . '/testDecryptVerifyFileFileException_output.plain'; $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptAndVerifyFile($inputFilename, $outputFilename); } // }}} // {{{ testDecryptVerifyFileKeyNotFoundException_decrypt() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group file */ public function testDecryptVerifyFileKeyNotFoundException_decrypt() { // file is encrypted with missing-key@example.com, not signed $inputFilename = $this->getDataFilename( 'testDecryptFileKeyNotFoundException.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileKeyNotFoundException.plain' ); $this->gpg->decryptAndVerifyFile($inputFilename, $outputFilename); } // }}} // {{{ testDecryptVerifyFileDual() /** * @group file */ public function testDecryptVerifyFileDual() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('7TYk0hpio90QZHHHb4UtgCWAEq4'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258220362); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature) ); $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileDual.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileDual.plain' ); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptVerifyFileDualSignatories() /** * @group file */ public function testDecryptVerifyFileDualSignatories() { // {{{ signature1 $signature1 = new Crypt_GPG_Signature(); $signature1->setId('MF8xqL325bs7KiokMHTnHirF4go'); $signature1->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $signature1->setKeyId('03CC890AFA1DAD4B'); $signature1->setCreationDate(1258220269); $signature1->setExpirationDate(0); $signature1->setValid(true); $userId1 = new Crypt_GPG_UserId(); $userId1->setName('Second Keypair Test Key'); $userId1->setComment('do not encrypt important data with this key'); $userId1->setEmail('second-keypair@example.com'); $signature1->setUserId($userId1); // }}} // {{{ signature2 $signature2 = new Crypt_GPG_Signature(); $signature2->setId('d0q7jibZpJSLpGAhNWhpSkZZeUg'); $signature2->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature2->setKeyId('C097D9EC94C06363'); $signature2->setCreationDate(1258220269); $signature2->setExpirationDate(0); $signature2->setValid(true); $userId2 = new Crypt_GPG_UserId(); $userId2->setName('First Keypair Test Key'); $userId2->setComment('do not encrypt important data with this key'); $userId2->setEmail('first-keypair@example.com'); $signature2->setUserId($userId2); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature1, $signature2) ); $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileDualSignatories.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileDualSignatories.plain' ); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptVerifyFileDualOnePassphrase() /** * @group file */ public function testDecryptVerifyFileDualOnePassphrase() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('kgyLjfFigxOrliyc8XlS6NaLJuw'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1258220334); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature) ); $inputFilename = $this->getDataFilename( 'testDecryptVerifyFileDualOnePassphrase.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileDualOnePassphrase.plain' ); // decrypt with no-passphrase $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); // decrypt with second key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->gpg->clearDecryptKeys(); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptVerifyFileNoDataException() /** * @expectedException Crypt_GPG_NoDataException * * @group file */ public function testDecryptVerifyFileNoDataException() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->decryptAndVerifyFile($filename); } // }}} // {{{ testDecryptVerifyFileSignedOnly() /** * @group file */ public function testDecryptVerifyFileSignedOnly() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('vctnI/HnsRYmqcVwCJcJhS60lKU'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221960707); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $expectedResults = array( 'data' => null, 'signatures' => array($signature) ); $inputFilename = $this->getDataFilename( 'testVerifyFileNormalSignedData.asc' ); $outputFilename = $this->getTempFilename( 'testDecryptVerifyFileSignedData.plain' ); $results = $this->gpg->decryptAndVerifyFile( $inputFilename, $outputFilename ); $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} } ?> Crypt_GPG-1.4.0/tests/DecryptTest.php0000664000175000017500000005757512610161626016057 0ustar alecalec * $ phpunit DecryptTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2009 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests decryption abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class DecryptTestCase extends Crypt_GPG_TestCase { // string // {{{ testDecrypt() /** * @group string */ public function testDecrypt() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptNoPassphrase() /** * @group string */ public function testDecryptNoPassphrase() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with no-passphrase@example.com // {{{ encrypted data no passphrase $encryptedData = <<gpg->decrypt($encryptedData); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testDecryptKeyNotFoundException() { // was encrypted with missing-key@example.com // {{{ encrypted data $encryptedData = <<gpg->decrypt($encryptedData); } // }}} // {{{ testDecryptNoDataException_invalid() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testDecryptNoDataException_invalid() { $encryptedData = 'Invalid OpenPGP data.'; $this->gpg->decrypt($encryptedData); } // }}} // {{{ testDecryptNoDataException_empty() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testDecryptNoDataException_empty() { $encryptedData = ''; $this->gpg->decrypt($encryptedData); } // }}} // {{{ testDecryptBadPassphraseException_missing() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testDecryptBadPassphraseException_missing() { // encrypted with first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->decrypt($encryptedData); } // }}} // {{{ testDecryptBadPassphraseException_bad() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testDecryptBadPassphraseException_bad() { // encrypted with first-keypair@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'incorrect'); $this->gpg->decrypt($encryptedData); } // }}} // {{{ testDecryptDual() /** * @group string */ public function testDecryptDual() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with both first-keypair@example.com and // second-keypair@example.com // {{{ dual encrypted data $encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertEquals($expectedDecryptedData, $decryptedData); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptDualOnePassphrase() /** * @group string */ public function testDecryptDualOnePassphrase() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with both first-keypair@example.com and // no-passphrase@example.com // {{{ dual encrypted data one passphrase $encryptedData = <<gpg->decrypt($encryptedData); $this->assertEquals($expectedDecryptedData, $decryptedData); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptSignedData() /** * @group string */ public function testDecryptSignedData() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // signed with first-keypair@example.com // {{{ signed data $signedData = <<gpg->decrypt($signedData); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptFirstSubKey() /** * @group string */ public function testDecryptFirstSubKey() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with first subkey (ELG-E) of multiple-subkeys@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('multiple-subkeys@example.com', 'test'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // {{{ testDecryptSecondSubKey() /** * @group string */ public function testDecryptSecondSubKey() { $expectedDecryptedData = 'Hello, Alice! Goodbye, Bob!'; // encrypted with second subkey (RSA) of multiple-subkeys@example.com // {{{ encrypted data $encryptedData = <<gpg->addDecryptKey('multiple-subkeys@example.com', 'test'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($expectedDecryptedData, $decryptedData); } // }}} // file // {{{ testDecryptFile() /** * @group file */ public function testDecryptFile() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $inputFilename = $this->getDataFilename('testDecryptFile.asc'); $outputFilename = $this->getTempFilename('testDecryptFile.plain'); // file is encrypted with first-keypair@example.com $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($inputFilename, $outputFilename); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptFileToString() /** * @group file */ public function testDecryptFileToString() { $expectedData = 'Hello, Alice! Goodbye, Bob!'; $inputFilename = $this->getDataFilename('testDecryptFileToString.asc'); // file is encrypted with first-keypair@example.com $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decryptFile($inputFilename); $this->assertEquals($expectedData, $decryptedData); } // }}} // {{{ testDecryptFileNoPassphrase() /** * @group file */ public function testDecryptFileNoPassphrase() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $inputFilename = $this->getDataFilename('testDecryptFileNoPassphrase.asc'); $outputFilename = $this->getTempFilename('testDecryptFileNoPassphrase.plain'); // file is encrypted with no-passphrase@example.com $this->gpg->decryptFile($inputFilename, $outputFilename); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptFileFileException_input() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testDecryptFileFileException_input() { // input file does not exist $inputFilename = $this->getDataFilename('testDecryptFileFileException_input.asc'); $this->gpg->decryptFile($inputFilename); } // }}} // {{{ testDecryptFileFileException_output() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testDecryptFileFileException_output() { // input file is encrypted with first-keypair@example.com // output file does not exist $inputFilename = $this->getDataFilename('testDecryptFile.asc'); $outputFilename = './non-existent' . '/testDecryptFileFileException_output.plain'; $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($inputFilename, $outputFilename); } // }}} // {{{ testDecryptFileKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group file */ public function testDecryptFileKeyNotFoundException() { // file is encrypted with missing-key@example.com $inputFilename = $this->getDataFilename('testDecryptFileKeyNotFoundException.asc'); $outputFilename = $this->getTempFilename('testDecryptFileKeyNotFoundException.plain'); $this->gpg->decryptFile($inputFilename, $outputFilename); } // }}} // {{{ testDecryptFileDual() /** * @group file */ public function testDecryptFileDual() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $inputFilename = $this->getDataFilename('testDecryptFileDual.asc'); $outputFilename = $this->getTempFilename('testDecryptFileDual.plain'); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($inputFilename, $outputFilename); $this->gpg->clearDecryptKeys(); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $this->gpg->decryptFile($inputFilename, $outputFilename); $this->gpg->clearDecryptKeys(); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptFileDualOnePassphrase() /** * @group file */ public function testDecryptFileDualOnePassphrase() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $inputFilename = $this->getDataFilename('testDecryptFileDualOnePassphrase.asc'); $outputFilename = $this->getTempFilename('testDecryptFileDualOnePassphrase.plain'); // decrypt with no-passphrase $this->gpg->decryptFile($inputFilename, $outputFilename); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($inputFilename, $outputFilename); $this->gpg->clearDecryptKeys(); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testDecryptFileNoDataException() /** * @expectedException Crypt_GPG_NoDataException * * @group file */ public function testDecryptFileNoDataException() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->decryptFile($filename); } // }}} // {{{ testDecryptFileSignedData() /** * @group string */ public function testDecryptFileSignedData() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $inputFilename = $this->getDataFilename('testVerifyFileNormalSignedData.asc'); $outputFilename = $this->getTempFilename('testDecryptFileSignedData.plain'); $this->gpg->decryptFile($inputFilename, $outputFilename); $md5Sum = $this->getMd5Sum($outputFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} } ?> Crypt_GPG-1.4.0/tests/DeletePrivateKeyTest.php0000664000175000017500000001051412610161626017631 0ustar alecalec * $ phpunit DeletePrivateKeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests private key deletion abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class DeletePrivateKeyTestCase extends Crypt_GPG_TestCase { // {{{ testDeletePrivateKey() /** * @group delete-private */ public function testDeletePrivateKey() { $keyId = 'first-keypair@example.com'; $this->gpg->deletePrivateKey($keyId); $expectedKeys = array(); // {{{ first-keypair@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('C097D9EC94C06363'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $subKey->setLength(1024); $subKey->setCreationDate(1221785805); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setHasPrivate(false); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('9F93F9116728EF12'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('C9C65B3BBF040E40D0EA27B79F93F9116728EF12'); $subKey->setLength(2048); $subKey->setCreationDate(1221785821); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(false); $key->addSubKey($subKey); // }}} $keys = $this->gpg->getKeys($keyId); $this->assertEquals($expectedKeys, $keys); } // }}} // {{{ testDeletePrivateKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group delete-private */ public function testDeletePrivateKeyNotFoundException() { $keyId = 'non-existent-key@example.com'; $this->gpg->deletePrivateKey($keyId); } // }}} // {{{ testDeletePrivateKeyNotFoundException_public_only() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group delete-private */ public function testDeletePrivateKeyNotFoundException_public_only() { $keyId = 'public-only@example.com'; $this->gpg->deletePrivateKey($keyId); } // }}} } ?> Crypt_GPG-1.4.0/tests/DeletePublicKeyTest.php0000664000175000017500000000570112610161626017437 0ustar alecalec * $ phpunit DeletePublicKeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests public key deletion abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class DeletePublicKeyTestCase extends Crypt_GPG_TestCase { // {{{ testDeletePublicKey() /** * @group delete-public */ public function testDeletePublicKey() { $keyId = 'public-only@example.com'; $this->gpg->deletePublicKey($keyId); $expectedKeys = array(); $keys = $this->gpg->getKeys($keyId); $this->assertEquals($expectedKeys, $keys); } // }}} // {{{ testDeletePublicKeyDeletePrivateKeyException() /** * @expectedException Crypt_GPG_DeletePrivateKeyException * * @group delete-public */ public function testDeletePublicKeyDeletePrivateKeyException() { $keyId = 'first-keypair@example.com'; $this->gpg->deletePublicKey($keyId); } // }}} // {{{ testDeletePublicKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group delete-public */ public function testDeletePublicKeyNotFoundException() { $keyId = 'non-existent-key@example.com'; $this->gpg->deletePublicKey($keyId); } // }}} } ?> Crypt_GPG-1.4.0/tests/EncryptAndSignTest.php0000664000175000017500000004046612610161626017324 0ustar alecalec * $ phpunit EncryptSignTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2009 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests encrypt and sign abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2009 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class EncryptAndSignTestCase extends Crypt_GPG_TestCase { // string // {{{ testEncryptAndSignKeyNotFoundException_invalid_sign_key() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptAndSignKeyNotFoundException_invalid_sign_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('non-existent-key@example.com'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignKeyNotFoundException_no_sign_key() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptAndSignKeyNotFoundException_no_sign_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignKeyNotFoundException_invalid_encrypt_key() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptAndSignKeyNotFoundException_invalid_encrypt_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('non-existent-key@example.com'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignKeyNotFoundException_no_encrypt_key() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptAndSignKeyNotFoundException_no_encrypt_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignBadPassphraseException_missing_sign_key() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testEncryptAndSignBadPassphraseException_missing_sign_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignBadPassphraseException_bad_sign_key() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testEncryptAndSignBadPassphraseException_bad_sign_key() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'incorrect'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSign($data); } // }}} // {{{ testEncryptAndSignNoPassphrase() /** * @group string */ public function testEncryptAndSignNoPassphrase() { $data = 'Hello, Alice! Goodbye, Bob!'; $signKey = 'no-passphrase@example.com'; $encryptKey = 'first-keypair@example.com'; $decryptPassphrase = 'test1'; $this->gpg->addSignKey($signKey); $this->gpg->addEncryptKey($encryptKey); $encryptedSignedData = $this->gpg->encryptAndSign($data); $this->gpg->addDecryptKey($encryptKey, $decryptPassphrase); $results = $this->gpg->decryptAndVerify($encryptedSignedData); $this->assertEquals($data, $results['data']); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSign() /** * @group string */ public function testEncryptAndSign() { $data = 'Hello, Alice! Goodbye, Bob!'; $signKey = 'first-keypair@example.com'; $signPassphrase = 'test1'; $encryptKey = 'first-keypair@example.com'; $decryptPassphrase = 'test1'; $this->gpg->addSignKey($signKey, $signPassphrase); $this->gpg->addEncryptKey($encryptKey); $encryptedSignedData = $this->gpg->encryptAndSign($data); $this->gpg->addDecryptKey($encryptKey, $decryptPassphrase); $results = $this->gpg->decryptAndVerify($encryptedSignedData); $this->assertEquals($data, $results['data']); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignDualOnePassphrase() /** * @group string */ public function testEncryptAndSignDualOnePassphrase() { $data = 'Hello, Alice! Goodbye, Bob!'; $signKey1 = 'first-keypair@example.com'; $signPassphrase1 = 'test1'; $signKey2 = 'no-passphrase@example.com'; $encryptKey = 'first-keypair@example.com'; $decryptPassphrase = 'test1'; $this->gpg->addSignKey($signKey1, $signPassphrase1); $this->gpg->addSignKey($signKey2); $this->gpg->addEncryptKey($encryptKey); $encryptedSignedData = $this->gpg->encryptAndSign($data); $this->gpg->addDecryptKey($encryptKey, $decryptPassphrase); $results = $this->gpg->decryptAndVerify($encryptedSignedData); $this->assertEquals($data, $results['data']); $this->assertEquals(2, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignDual() /** * @group string */ public function testEncryptAndSignDual() { $data = 'Hello, Alice! Goodbye, Bob!'; $signKey1 = 'first-keypair@example.com'; $signPassphrase1 = 'test1'; $signKey2 = 'second-keypair@example.com'; $signPassphrase2 = 'test2'; $encryptKey = 'first-keypair@example.com'; $decryptPassphrase = 'test1'; $this->gpg->addSignKey($signKey1, $signPassphrase1); $this->gpg->addSignKey($signKey2, $signPassphrase2); $this->gpg->addEncryptKey($encryptKey); $encryptedSignedData = $this->gpg->encryptAndSign($data); $this->gpg->addDecryptKey($encryptKey, $decryptPassphrase); $results = $this->gpg->decryptAndVerify($encryptedSignedData); $this->assertEquals($data, $results['data']); $this->assertEquals(2, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignEmpty() /** * @group string */ public function testEncryptAndSignEmpty() { $data = ''; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('first-keypair@example.com'); $encryptedSignedData = $this->gpg->encryptAndSign($data); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerify($encryptedSignedData); $this->assertEquals('', $results['data']); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // file // {{{ testEncryptAndSignFileNoPassphrase() /** * @group file */ public function testEncryptAndSignFileNoPassphrase() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.asc'); $decryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.plain'); $this->gpg->addSignKey('no-passphrase@example.com'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($encryptedFilename, $decryptedFilename); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignFile() /** * @group file */ public function testEncryptAndSignFile() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.asc'); $decryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($encryptedFilename, $decryptedFilename); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignFileDualOnePassphrase() /** * @group file */ public function testEncryptAndSignFileDualOnePassphrase() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.asc'); $decryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('no-passphrase@example.com'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($encryptedFilename, $decryptedFilename); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); $this->assertEquals(2, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignFileDual() /** * @group file */ public function testEncryptAndSignFileDual() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.asc'); $decryptedFilename = $this->getTempFilename('testEncryptAndSignFileNoPassphrase.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($encryptedFilename, $decryptedFilename); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); $this->assertEquals(2, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testEncryptAndSignFileFileException_input() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testEncryptAndSignFileFileException_input() { // input file does not exist $inputFilename = $this->getDataFilename( 'testEncryptAndSignFileFileFileException_input.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($inputFilename); } // }}} // {{{ testEncryptAndSignFileFileException_output() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testEncryptAndSignFileFileException_output() { // input file is plaintext // output file does not exist $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = './non-existent' . '/testEncryptAndSignFileFileException_output.plain'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($inputFilename, $outputFilename); } // }}} // {{{ testEncryptAndSignFileEmpty() /** * @group file */ public function testEncryptAndSignFileEmpty() { $originalFilename = $this->getDataFilename('testFileEmpty.plain'); $encryptedFilename = $this->getTempFilename('testEncryptAndSignFileEmpty.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptAndSignFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $results = $this->gpg->decryptAndVerifyFile($encryptedFilename); $this->assertEquals('', $results['data']); $this->assertEquals(1, count($results['signatures'])); foreach ($results['signatures'] as $signature) { $this->assertTrue($signature->isValid()); } } // }}} } ?> Crypt_GPG-1.4.0/tests/EncryptTest.php0000664000175000017500000002145612610161626016056 0ustar alecalec * $ phpunit EncryptTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests encryption abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class EncryptTestCase extends Crypt_GPG_TestCase { public function testHasEncryptKeys() { $this->assertFalse($this->gpg->hasEncryptKeys()); $this->gpg->addEncryptKey('no-passphrase@example.com'); $this->assertTrue($this->gpg->hasEncryptKeys()); } // {{{ testEncrypt() /** * @group string */ public function testEncrypt() { $data = 'Hello, Alice! Goodbye, Bob!'; $keyId = 'first-keypair@example.com'; $passphrase = 'test1'; $this->gpg->addEncryptKey($keyId); $encryptedData = $this->gpg->encrypt($data); $this->gpg->addDecryptKey($keyId, $passphrase); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($data, $decryptedData); } // }}} // {{{ testEncryptDual() /** * @group string */ public function testEncryptDual() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->addEncryptKey('second-keypair@example.com'); $encryptedData = $this->gpg->encrypt($data); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($data, $decryptedData); $this->gpg->clearDecryptKeys(); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->gpg->clearDecryptKeys(); $this->assertEquals($data, $decryptedData); } // }}} // {{{ testEncryptKeyNotFoundException_invalid() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptNotFoundException_invalid() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addEncryptKey('non-existent-key@example.com'); $this->gpg->encrypt($data); } // }}} // {{{ testEncryptKeyNotFoundException_none() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testEncryptNotFoundException_none() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->encrypt($data); } // }}} // {{{ testEncryptEmpty() /** * @group string */ public function testEncryptEmpty() { $data = ''; $this->gpg->addEncryptKey('first-keypair@example.com'); $encryptedData = $this->gpg->encrypt($data); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($data, $decryptedData); } // }}} // file // {{{ testEncryptFile() /** * @group file */ public function testEncryptFile() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptFile.asc'); $decryptedFilename = $this->getTempFilename('testEncryptFile.plain'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptFile($originalFilename, $encryptedFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($encryptedFilename, $decryptedFilename); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testEncryptFileDual() /** * @group file */ public function testEncryptFileDual() { $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1'; $originalFilename = $this->getDataFilename('testFileMedium.plain'); $encryptedFilename = $this->getTempFilename('testEncryptFile.asc'); $decryptedFilename = $this->getTempFilename('testEncryptFile.plain'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->addEncryptKey('second-keypair@example.com'); $this->gpg->encryptFile($originalFilename, $encryptedFilename); // decrypt with first key $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $this->gpg->decryptFile($encryptedFilename, $decryptedFilename); $this->gpg->clearDecryptKeys(); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); // decrypt with second key $this->gpg->addDecryptKey('second-keypair@example.com', 'test2'); $this->gpg->decryptFile($encryptedFilename, $decryptedFilename); $this->gpg->clearDecryptKeys(); $md5Sum = $this->getMd5Sum($decryptedFilename); $this->assertEquals($expectedMd5Sum, $md5Sum); } // }}} // {{{ testEncryptFileToString() /** * @group file */ public function testEncryptFileToString() { $expectedData = 'Hello, Alice! Goodbye, Bob!'; $originalFilename = $this->getDataFilename('testFileSmall.plain'); $this->gpg->addEncryptKey('first-keypair@example.com'); $encryptedData = $this->gpg->encryptFile($originalFilename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals($expectedData, $decryptedData); } // }}} // {{{ testEncryptFileFileException_input() /** * @group file * * @expectedException Crypt_GPG_FileException */ public function testEncryptFileFileException_input() { // input file does not exist $filename = $this->getDataFilename('testEncryptFileFileException_input.plain'); $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptFile($filename); } // }}} // {{{ testEncryptFileFileException_output() /** * @group file * * @expectedException Crypt_GPG_FileException */ public function testEncryptFileFileException_output() { // output file does not exist $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = './non-existent' . '/testEncryptFileFileException_output.asc'; $this->gpg->addEncryptKey('first-keypair@example.com'); $this->gpg->encryptFile($inputFilename, $outputFilename); } // }}} // {{{ testEncryptFileEmpty() /** * @group file */ public function testEncryptFileEmpty() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->addEncryptKey('first-keypair@example.com'); $encryptedData = $this->gpg->encryptFile($filename); $this->gpg->addDecryptKey('first-keypair@example.com', 'test1'); $decryptedData = $this->gpg->decrypt($encryptedData); $this->assertEquals('', $decryptedData); } // }}} } ?> Crypt_GPG-1.4.0/tests/ExceptionsTest.php0000664000175000017500000001740712610161626016554 0ustar alecalec * $ phpunit ExceptionsTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Exception classes. */ require_once 'Crypt/GPG/Exceptions.php'; /** * Exception classes tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class ExceptionsTestCase extends Crypt_GPG_TestCase { // exception // {{{ testException /** * @group exception * @expectedException Crypt_GPG_Exception * @expectedExceptionMessage test exception */ public function testException() { throw new Crypt_GPG_Exception('test exception'); } // }}} // file exception // {{{ testFileException /** * @group file-exception * @expectedException Crypt_GPG_FileException * @expectedExceptionMessage test exception */ public function testFileException() { throw new Crypt_GPG_FileException('test exception'); } // }}} // {{{ testFileException_getFilename() /** * @group file-exception */ public function testFileException_getFilename() { $e = new Crypt_GPG_FileException('test exception', 0, 'test-filename.php'); $this->assertEquals('test-filename.php', $e->getFilename()); } // }}} // open subprocess exception // {{{ testOpenSubprocessException /** * @group open-subprocess-exception * @expectedException Crypt_GPG_OpenSubprocessException * @expectedExceptionMessage test exception */ public function testOpenSubprocessException() { throw new Crypt_GPG_OpenSubprocessException('test exception'); } // }}} // {{{ testOpenSubprocessException_getCommand() /** * @group open-subprocess-exception */ public function testOpenSubprocessException_getCommand() { $e = new Crypt_GPG_OpenSubprocessException('test exception', 0, 'gpg --verify'); $this->assertEquals('gpg --verify', $e->getCommand()); } // }}} // invalid operation exception // {{{ testInvalidOperationException /** * @group invalid-operation-exception * @expectedException Crypt_GPG_InvalidOperationException * @expectedExceptionMessage test exception */ public function testInvalidOperationException() { throw new Crypt_GPG_InvalidOperationException('test exception'); } // }}} // {{{ testInvalidOperationException_getOperation() /** * @group invalid-operation-exception */ public function testInvalidOperationException_getOperation() { $e = new Crypt_GPG_InvalidOperationException('test exception', 0, '--verify'); $this->assertEquals('--verify', $e->getOperation()); } // }}} // key not found exception // {{{ testKeyNotFoundException /** * @group key-not-found-exception * @expectedException Crypt_GPG_KeyNotFoundException * @expectedExceptionMessage test exception */ public function testKeyNotFoundException() { throw new Crypt_GPG_KeyNotFoundException('test exception'); } // }}} // {{{ testKeyNotFoundException_getKeyId() /** * @group key-not-found-exception */ public function testKeyNotFoundException_getKeyId() { $e = new Crypt_GPG_KeyNotFoundException('test exception', 0, '9F93F9116728EF12'); $this->assertEquals('9F93F9116728EF12', $e->getKeyId()); } // }}} // no data exception // {{{ testNoDataException /** * @group no-data-exception * @expectedException Crypt_GPG_NoDataException * @expectedExceptionMessage test exception */ public function testNoDataException() { throw new Crypt_GPG_NoDataException('test exception'); } // }}} // bad passphrase exception // {{{ testBadPassphraseException /** * @group bad-passphrase-exception * @expectedException Crypt_GPG_BadPassphraseException * @expectedExceptionMessage test exception */ public function testBadPassphraseException() { throw new Crypt_GPG_BadPassphraseException('test exception'); } // }}} // {{{ testBadPassphraseException_getBadPassphrases() /** * @group bad-passphrase-exception */ public function testBadPassphraseException_getBadPassphrases() { $e = new Crypt_GPG_BadPassphraseException('test exception', 0, array('C097D9EC94C06363', '9F93F9116728EF12')); $keyIds = $e->getBadPassphrases(); $this->assertTrue(is_array($keyIds), 'Failed to assert returned ' . 'key ids for bad passphrases is an array.'); $this->assertContains('C097D9EC94C06363', $keyIds); $this->assertContains('9F93F9116728EF12', $keyIds); } // }}} // {{{ testBadPassphraseException_getMissingPassphrase() /** * @group bad-passphrase-exception */ public function testBadPassphraseException_getMissingPassphrase() { $e = new Crypt_GPG_BadPassphraseException('test exception', 0, array(), array('C097D9EC94C06363', '9F93F9116728EF12')); $keyIds = $e->getMissingPassphrases(); $this->assertTrue(is_array($keyIds), 'Failed to assert returned ' . 'key ids for missing passphrases is an array.'); $this->assertContains('C097D9EC94C06363', $keyIds); $this->assertContains('9F93F9116728EF12', $keyIds); } // }}} // delete private key exception // {{{ testDeletePrivateKeyException /** * @group delete-private-key-exception * @expectedException Crypt_GPG_DeletePrivateKeyException * @expectedExceptionMessage test exception */ public function testDeletePrivateKeyException() { throw new Crypt_GPG_DeletePrivateKeyException('test exception'); } // }}} // {{{ testDeletePrivateKeyException_getKeyId() /** * @group delete-private-key-exception */ public function testDeletePrivateKeyException_getKeyId() { $e = new Crypt_GPG_DeletePrivateKeyException('test exception', 0, '9F93F9116728EF12'); $this->assertEquals('9F93F9116728EF12', $e->getKeyId()); } // }}} } ?> Crypt_GPG-1.4.0/tests/ExportPublicKeyTest.php0000664000175000017500000001106312610161626017514 0ustar alecalec * $ phpunit ExportPublicKeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests key export abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class ExportPublicKeyTestCase extends Crypt_GPG_TestCase { // {{{ testExportPublicKey() /** * @group export */ public function testExportPublicKey() { $keyId = 'public-only@example.com'; // {{{ expected key data // Key block identifier and version identifier intentionally omitted // because they contain system-specific information, and causes tests // to fail on other systems. $expectedKeyData = <<gpg->exportPublicKey($keyId); // Check for containment rather than equality since the OpenPGP header // varies from system to system. $this->assertContains($expectedKeyData, $keyData); } // }}} // {{{ testExportPublicKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group export */ public function testExportPublicKeyNotFoundException() { $keyId = 'non-existent-key@example.com'; $this->gpg->exportPublicKey($keyId); } // }}} } ?> Crypt_GPG-1.4.0/tests/GeneralTest.php0000664000175000017500000001732612610161626016010 0ustar alecalec * $ phpunit GeneralTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * General tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class GeneralTestCase extends Crypt_GPG_TestCase { // {{{ testPublicKeyringFileException() /** * @expectedException Crypt_GPG_FileException */ public function testPublicKeyringFileException() { $publicKeyringFile = $this->getTempFilename('pubring.gpg'); new Crypt_GPG( array( 'publicKeyring' => $publicKeyringFile ) ); } // }}} // {{{ testPrivateKeyringFileException() /** * @expectedException Crypt_GPG_FileException */ public function testPrivateKeyringFileException() { $privateKeyringFile = $this->getTempFilename('secring.gpg'); new Crypt_GPG( array( 'privateKeyring' => $privateKeyringFile ) ); } // }}} // {{{ testTrustDatabaseFileException() /** * @expectedException Crypt_GPG_FileException */ public function testTrustDatabaseFileException() { $trustDbFile = $this->getTempFilename('secring.gpg'); new Crypt_GPG( array( 'trustDb' => $trustDbFile ) ); } // }}} // {{{ testHomedirFileException_NoCreate() /** * @expectedException Crypt_GPG_FileException * @expectedExceptionMessage cannot be created */ public function testHomedirFileException_NoCreate() { if (posix_getuid() === 0) { $this->markTestSkipped('Root can write to any homedir.'); } $nonCreatableDirectory = '//.gnupg'; new Crypt_GPG(array('homedir' => $nonCreatableDirectory)); } // }}} // {{{ testHomedirFileException_NoExecute() /** * @expectedException Crypt_GPG_FileException * @expectedExceptionMessage is not enterable */ public function testHomedirFileException_NoExecute() { if (posix_getuid() === 0) { $this->markTestSkipped('Root can do what it wants to any homedir.'); } $nonExecutableDirectory = $this->getTempFilename('home-no-execute'); mkdir($nonExecutableDirectory); chmod($nonExecutableDirectory, 0600); // rw- --- --- new Crypt_GPG(array('homedir' => $nonExecutableDirectory)); } // }}} // {{{ testHomedirFileException_NoWrite() /** * @expectedException Crypt_GPG_FileException() * @expectedExceptionMessage is not writeable */ public function testHomedirFileException_NoWrite() { if (posix_getuid() === 0) { $this->markTestSkipped('Root can write to any homedir.'); } $nonWriteableDirectory = $this->getTempFilename('home-no-write'); mkdir($nonWriteableDirectory); chmod($nonWriteableDirectory, 0300); // r-x --- --- new Crypt_GPG(array('homedir' => $nonWriteableDirectory)); } // }}} // {{{ testBinaryPEARException() /** * @expectedException PEAR_Exception */ public function testBinaryPEARException() { new Crypt_GPG(array('binary' => './non-existent-binary')); } // }}} // {{{ testGPGBinaryPEARException() /** * @expectedException PEAR_Exception */ public function testGPGBinaryPEARException() { new Crypt_GPG(array('gpgBinary' => './non-existent-binary')); } // }}} // {{{ testSetEngine() public function testSetEngine() { $engine = new Crypt_GPG_Engine($this->getOptions()); $gpg = new Crypt_GPG(); $gpg->setEngine($engine); $homedirConstraint = $this->attribute( $this->attributeEqualTo( '_homedir', dirname(__FILE__) . '/' . self::HOMEDIR ), 'engine' ); $this->assertThat( $gpg, $homedirConstraint, 'Engine was not set properly.' ); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $returnedGpg = $this->gpg->setEngine( new Crypt_GPG_Engine($this->getOptions()) ); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for setEngine() method.' ); $returnedGpg = $this->gpg->addDecryptKey( '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'test1' ); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for addDecryptKey() ' . 'method.' ); $returnedGpg = $this->gpg->addEncryptKey( '8D2299D9C5C211128B32BBB0C097D9EC94C06363' ); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for addEncryptKey() ' . 'method.' ); $returnedGpg = $this->gpg->addSignKey( '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'test1' ); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for addSignKey() ' . 'method.' ); $returnedGpg = $this->gpg->clearDecryptKeys(); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for clearDecryptKeys() ' . 'method.' ); $returnedGpg = $this->gpg->clearEncryptKeys(); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for clearEncryptKeys() ' . 'method.' ); $returnedGpg = $this->gpg->clearSignKeys(); $this->assertEquals( $this->gpg, $returnedGpg, 'Failed asserting fluent interface works for clearSignKeys() ' . 'method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/GetFingerprintTest.php0000664000175000017500000000676212610161626017364 0ustar alecalec * $ phpunit GetFingerprintTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests fingerprint retrieval of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class GetFingerprintTestCase extends Crypt_GPG_TestCase { // {{{ testGetFingerprint() /** * @group get-fingerprint */ public function testGetFingerprint() { $keyId = 'public-only@example.com'; $expectedFingerprint = 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'; $fingerprint = $this->gpg->getFingerprint($keyId); $this->assertEquals($expectedFingerprint, $fingerprint); } // }}} // {{{ testGetFingerprintNull() /** * @group get-fingerprint */ public function testGetFingerprintNull() { $keyId = 'non-existent-key@example.com'; $fingerprint = $this->gpg->getFingerprint($keyId); $this->assertNull($fingerprint); } // }}} // {{{ testGetFingerprintX509() /** * @group get-fingerprint */ public function testGetFingerprintX509() { $keyId = 'public-only@example.com'; $expectedFingerprint = 'F8:31:18:CB:6F:58:92:DC:1C:3E:93:6D:AB:A8:1E:F5:4E:8C:0D:EB'; $fingerprint = $this->gpg->getFingerprint($keyId, Crypt_GPG::FORMAT_X509); $this->assertEquals($expectedFingerprint, $fingerprint); } // }}} // {{{ testGetFingerprintCanonical() /** * @group get-fingerprint */ public function testGetFingerprintCanonical() { $keyId = 'public-only@example.com'; $expectedFingerprint = 'F831 18CB 6F58 92DC 1C3E 936D ABA8 1EF5 4E8C 0DEB'; $fingerprint = $this->gpg->getFingerprint($keyId, Crypt_GPG::FORMAT_CANONICAL); $this->assertEquals($expectedFingerprint, $fingerprint); } // }}} } ?> Crypt_GPG-1.4.0/tests/GetKeysTest.php0000664000175000017500000002664412610161626016011 0ustar alecalec * $ phpunit GetKeysTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests key retrieval of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class GetKeysTestCase extends Crypt_GPG_TestCase { // {{{ testGetKeys() /** * @group get-keys */ public function testGetKeys() { $expectedKeys = array(); // {{{ first-keypair@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('C097D9EC94C06363'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $subKey->setLength(1024); $subKey->setCreationDate(1221785805); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('9F93F9116728EF12'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('C9C65B3BBF040E40D0EA27B79F93F9116728EF12'); $subKey->setLength(2048); $subKey->setCreationDate(1221785821); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); // }}} // {{{ second-keypair@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('03CC890AFA1DAD4B'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('880922DBEA733E906693E4A903CC890AFA1DAD4B'); $subKey->setLength(1024); $subKey->setCreationDate(1221785821); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('B2F54E4757E22450'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('C641EE162B46B810E8089153B2F54E4757E22450'); $subKey->setLength(2048); $subKey->setCreationDate(1221785825); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); // }}} // {{{ public-only@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('Public Only Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('public-only@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('ABA81EF54E8C0DEB'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'); $subKey->setLength(1024); $subKey->setCreationDate(1221785826); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setHasPrivate(false); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('BA4984433CDF4169'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('B68C9DB020181C798047A6E7BA4984433CDF4169'); $subKey->setLength(2048); $subKey->setCreationDate(1221785832); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(false); $key->addSubKey($subKey); // }}} // {{{ no-passphrase@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('No Passphrase Public and Private Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('no-passphrase@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('94563FB398ADA6B2'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('1EC9C5DBF239DD0A3A4FCD0D94563FB398ADA6B2'); $subKey->setLength(1024); $subKey->setCreationDate(1221785833); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('24BF380700C14B4F'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('86DD46AC210531EE5A37567824BF380700C14B4F'); $subKey->setLength(2048); $subKey->setCreationDate(1221785845); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); // }}} // {{{ multiple-subkeys@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('Multiple Subkeys'); $userId->setEmail('multiple-subkeys@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('B07A621DC9295765'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('F9DF21B5D2DD02D3DF760270B07A621DC9295765'); $subKey->setLength(1024); $subKey->setCreationDate(1232605399); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY | Crypt_GPG_SubKey::USAGE_AUTHENTICATION); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('6F941ACC362453DA'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('A728EE198BA2FB5C7B1C8B896F941ACC362453DA'); $subKey->setLength(2048); $subKey->setCreationDate(1232605407); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('2921E0D3FF5B0F4A'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_RSA); $subKey->setFingerprint('E1363DCE4863B824813AB2702921E0D3FF5B0F4A'); $subKey->setLength(2048); $subKey->setCreationDate(1232605437); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); // }}} $keys = $this->gpg->getKeys(); $this->assertEquals($expectedKeys, $keys); } // }}} // {{{ testGetKeysWithKeyId() /** * @group get-keys */ public function testGetKeysWithKeyId() { $keyId = 'first-keypair@example.com'; $expectedKeys = array(); // {{{ first-keypair@example.com $key = new Crypt_GPG_Key(); $expectedKeys[] = $key; $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $key->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('C097D9EC94C06363'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $subKey->setLength(1024); $subKey->setCreationDate(1221785805); $subKey->setExpirationDate(0); $subKey->setUsage(Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY); $subKey->setHasPrivate(true); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setId('9F93F9116728EF12'); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setFingerprint('C9C65B3BBF040E40D0EA27B79F93F9116728EF12'); $subKey->setLength(2048); $subKey->setCreationDate(1221785821); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $key->addSubKey($subKey); // }}} $keys = $this->gpg->getKeys($keyId); $this->assertEquals($expectedKeys, $keys); } // }}} // {{{ testGetKeysNone() /** * @group get-keys */ public function testGetKeysNone() { $keyId = 'non-existent-key@example.com'; $expectedKeys = array(); $keys = $this->gpg->getKeys($keyId); $this->assertEquals($expectedKeys, $keys); } // }}} } ?> Crypt_GPG-1.4.0/tests/ImportKeyTest.php0000664000175000017500000004367012610161626016357 0ustar alecalec * $ phpunit ImportKeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests key import abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class ImportKeyTestCase extends Crypt_GPG_TestCase { // string // {{{ testImportKey_private() /** * @group string */ public function testImportKey_private() { $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 1, 'private_unchanged' => 0 ); // {{{ private key data $privateKeyData = <<gpg->importKey($privateKeyData); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKey_public() /** * @group string */ public function testImportKey_public() { $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 1, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 0 ); // {{{ public key data $publicKeyData = <<gpg->importKey($publicKeyData); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyAlreadyImported_private() /** * @group string */ public function testImportKeyAlreadyImported_private() { // {{{ private key data $privateKeyData = <<gpg->importKey($privateKeyData); $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 1, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); $result = $this->gpg->importKey($privateKeyData); $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 1 ); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyAlreadyImported_public() /** * @group string */ public function testImportKeyAlreadyImported_public() { // {{{ public key data $publicKeyData = <<gpg->importKey($publicKeyData); $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 1, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); $result = $this->gpg->importKey($publicKeyData); $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 0, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyNoDataException_invalid() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testImportKeyNoDataException_invalid() { $keyData = 'Invalid OpenPGP data.'; $this->gpg->importKey($keyData); } // }}} // {{{ testImportKeyNoDataException_empty() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testImportKeyNoDataException_empty() { $keyData = ''; $this->gpg->importKey($keyData); } // }}} // file // {{{ testImportKeyFile_private() /** * @group file */ public function testImportKeyFile_private() { $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 1, 'private_unchanged' => 0 ); $filename = $this->getDataFilename('testImportKeyFile_private.asc'); $result = $this->gpg->importKeyFile($filename); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyFile_public() /** * @group file */ public function testImportKeyFile_public() { $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 1, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 0 ); $filename = $this->getDataFilename('testImportKeyFile_public.asc'); $result = $this->gpg->importKeyFile($filename); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyFileAlreadyImported_private() /** * @group file */ public function testImportKeyFileAlreadyImported_private() { $filename = $this->getDataFilename('testImportKeyFile_private.asc'); $result = $this->gpg->importKeyFile($filename); $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 1, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); $result = $this->gpg->importKeyFile($filename); $expectedResult = array( 'fingerprint' => 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB', 'fingerprints' => array('F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB'), 'public_imported' => 0, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 1 ); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyFileAlreadyImported_public() /** * @group file */ public function testImportKeyFileAlreadyImported_public() { $filename = $this->getDataFilename('testImportKeyFile_public.asc'); $result = $this->gpg->importKeyFile($filename); $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 1, 'public_unchanged' => 0, 'private_imported' => 0, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); $result = $this->gpg->importKeyFile($filename); $expectedResult = array( 'fingerprint' => '948F9835FF09F5F91CFF2AC1268AB7103435E65D', 'fingerprints' => array('948F9835FF09F5F91CFF2AC1268AB7103435E65D'), 'public_imported' => 0, 'public_unchanged' => 1, 'private_imported' => 0, 'private_unchanged' => 0 ); $this->assertEquals($expectedResult, $result); } // }}} // {{{ testImportKeyFileFileException() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testImportKeyFileFileException() { // input file does not exist $filename = $this->getDataFilename('testImportKeyFileFileException.asc'); $this->gpg->importKeyFile($filename); } // }}} // {{{ testImportKeyFileNoDataException() /** * @expectedException Crypt_GPG_NoDataException * * @group file */ public function testImportKeyFileNoDataException() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->importKeyFile($filename); } // }}} } ?> Crypt_GPG-1.4.0/tests/KeyGeneratorTest.php0000664000175000017500000007164712610161626017040 0ustar alecalec * $ phpunit KeyGeneratorTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id: GetKeysTestCase.php 274158 2009-01-22 06:33:54Z gauthierm $ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * The Crypt_GPG class to test */ require_once 'Crypt/GPG/KeyGenerator.php'; /** * Tests key generation of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class KeyGeneratorTestCase extends Crypt_GPG_TestCase { // helper methods // {{{ assertKeyEquals() protected function assertKeyEquals( Crypt_GPG_Key $key1, Crypt_GPG_Key $key2 ) { $userIds1 = $key1->getUserIds(); $userIds2 = $key2->getUserIds(); $userId1 = $userIds1[0]; $userId2 = $userIds2[0]; $subKeys1 = $key1->getSubKeys(); $subKeys2 = $key2->getSubKeys(); $subKeyA1 = $subKeys1[0]; $subKeyB1 = $subKeys1[1]; $subKeyA2 = $subKeys2[0]; $subKeyB2 = $subKeys2[1]; $this->assertEquals( $userId1->getName(), $userId2->getName(), 'User id names do not match.' ); $this->assertEquals( $userId1->getEmail(), $userId2->getEmail(), 'User id email addresses do not match.' ); $this->assertEquals( $userId1->getComment(), $userId2->getComment(), 'User id comments do not match.' ); $this->assertEquals( $subKeyA1->getAlgorithm(), $subKeyA2->getAlgorithm(), 'Primary key algorithms do not match.' ); $this->assertEquals( $subKeyA1->getLength(), $subKeyA2->getLength(), 'Primary key lengths do not match.' ); $this->assertEquals( $subKeyA1->getExpirationDate(), $subKeyA2->getExpirationDate(), 'Primary key expiration dates do not match.' ); $this->assertEquals( $subKeyA1->canSign(), $subKeyA2->canSign(), 'Primary key signing abilities do not match.' ); $this->assertEquals( $subKeyA1->canEncrypt(), $subKeyA2->canEncrypt(), 'Primary key encrypting abilities do not match.' ); $this->assertEquals( $subKeyA1->hasPrivate(), $subKeyA2->hasPrivate(), 'Primary key private keys do not match.' ); $this->assertEquals( $subKeyB1->getAlgorithm(), $subKeyB2->getAlgorithm(), 'Secondary key algorithms do not match.' ); $this->assertEquals( $subKeyB1->getLength(), $subKeyB2->getLength(), 'Secondary key lengths do not match.' ); $this->assertEquals( $subKeyB1->getExpirationDate(), $subKeyB2->getExpirationDate(), 'Secondary key expiration dates do not match.' ); $this->assertEquals( $subKeyB1->canSign(), $subKeyB2->canSign(), 'Secondary key signing abilities do not match.' ); $this->assertEquals( $subKeyB1->canEncrypt(), $subKeyB2->canEncrypt(), 'Secondary key encrypting abilities do not match.' ); $this->assertEquals( $subKeyB1->hasPrivate(), $subKeyB2->hasPrivate(), 'Secondary key private keys do not match.' ); } // }}} // {{{ setUp() public function setUp() { parent::setUp(); $this->generator = new Crypt_GPG_KeyGenerator($this->getOptions()); } // }}} // mutators // {{{ testSetExpirationDate_zero() /** * @group mutators */ public function testSetExpirationDate_zero() { $expectedDate = 0; $this->generator->setExpirationDate(0); $this->assertAttributeEquals( $expectedDate, 'expirationDate', $this->generator, 'Setting expiration date to zero failed.' ); } // }}} // {{{ testSetExpirationDate_integer() /** * @group mutators */ public function testSetExpirationDate_integer() { $expectedDate = 2000000000; $this->generator->setExpirationDate(2000000000); $this->assertAttributeEquals( $expectedDate, 'expirationDate', $this->generator, 'Setting expiration date by integer failed.' ); } // }}} // {{{ testSetExpirationDate_string() /** * @group mutators */ public function testSetExpirationDate_string() { date_default_timezone_set('UTC'); $expectedDate = 2000000000; $this->generator->setExpirationDate('2033-05-18T03:33:20'); $this->assertAttributeEquals( $expectedDate, 'expirationDate', $this->generator, 'Setting expiration date by string failed.' ); } // }}} // {{{ testSetExpirationDate_invalid_format() /** * @group mutators * @expectedException InvalidArgumentException */ public function testSetExpirationDate_invalid_format() { date_default_timezone_set('UTC'); $this->generator->setExpirationDate('this is not a date'); } // }}} // {{{ testSetExpirationDate_too_early_date() /** * @group mutators * @expectedException InvalidArgumentException */ public function testSetExpirationDate_too_early_date() { $this->generator->setExpirationDate(1301088055); } // }}} // {{{ testSetExpirationDate_today() /** * @group mutators * @expectedException InvalidArgumentException */ public function testSetExpirationDate_today() { $this->generator->setExpirationDate(time()); } // }}} // {{{ testSetExpirationDate_too_late_date() /** * @group mutators * @expectedException InvalidArgumentException */ public function testSetExpirationDate_too_late_date() { $this->generator->setExpirationDate(2147483648); } // }}} // {{{ testSetPassphrase() /** * @group mutators */ public function testSetPassphrase() { $expectedPassphrase = 'test1'; $this->generator->setPassphrase('test1'); $this->assertAttributeEquals( $expectedPassphrase, 'passphrase', $this->generator, 'Setting passphrase failed.' ); } // }}} // {{{ testSetKeyParams_algorithm() /** * @group mutators */ public function testSetKeyParams_algorithm() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 1024; $expectedUsage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY; $this->generator->setKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN ); $this->assertAttributeEquals( $expectedAlgorithm, 'keyAlgorithm', $this->generator, 'Setting key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'keySize', $this->generator, 'Setting key algorithm changed key size.' ); $this->assertAttributeEquals( $expectedUsage, 'keyUsage', $this->generator, 'Setting key algorithm changed key usage.' ); } // }}} // {{{ testSetKeyParams_algorithm_and_size() /** * @group mutators */ public function testSetKeyParams_algorithm_and_size() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 512; $expectedUsage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY; $this->generator->setKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN, 512 ); $this->assertAttributeEquals( $expectedAlgorithm, 'keyAlgorithm', $this->generator, 'Setting key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'keySize', $this->generator, 'Setting key size failed.' ); $this->assertAttributeEquals( $expectedUsage, 'keyUsage', $this->generator, 'Setting key algorithm and size changed key usage.' ); } // }}} // {{{ testSetKeyParams_algorithm_size_and_usage() /** * @group mutators */ public function testSetKeyParams_algorithm_size_and_usage() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 512; $expectedUsage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY | Crypt_GPG_SubKey::USAGE_ENCRYPT; $this->generator->setKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN, 512, Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_CERTIFY | Crypt_GPG_SubKey::USAGE_ENCRYPT ); $this->assertAttributeEquals( $expectedAlgorithm, 'keyAlgorithm', $this->generator, 'Setting key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'keySize', $this->generator, 'Setting key size failed.' ); $this->assertAttributeEquals( $expectedUsage, 'keyUsage', $this->generator, 'Setting key usage failed.' ); } // }}} // {{{ testSetKeyParams_invalid_algorithm() /** * @group mutators * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testSetKeyParams_invalid_algorithm() { $this->generator->setKeyParams(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); } // }}} // {{{ testSetKeyParams_invalid_dsa_usage() /** * @group mutators * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testSetKeyParams_invalid_dsa_usage() { $this->generator->setKeyParams( Crypt_GPG_SubKey::ALGORITHM_DSA, 2048, Crypt_GPG_SubKey::USAGE_ENCRYPT | Crypt_GPG_SubKey::USAGE_CERTIFY ); } // }}} // {{{ testSetSubKeyParams_algorithm() /** * @group mutators */ public function testSetSubKeyParams_algorithm() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 2048; $expectedUsage = Crypt_GPG_SubKey::USAGE_ENCRYPT; $this->generator->setSubKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN ); $this->assertAttributeEquals( $expectedAlgorithm, 'subKeyAlgorithm', $this->generator, 'Setting sub-key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'subKeySize', $this->generator, 'Setting sub-key algorithm changed key size.' ); $this->assertAttributeEquals( $expectedUsage, 'subKeyUsage', $this->generator, 'Setting sub-key algorithm changed key usage.' ); } // }}} // {{{ testSetSubKeyParams_algorithm_and_size() /** * @group mutators */ public function testSetSubKeyParams_algorithm_and_size() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 1024; $expectedUsage = Crypt_GPG_SubKey::USAGE_ENCRYPT; $this->generator->setSubKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN, 1024 ); $this->assertAttributeEquals( $expectedAlgorithm, 'subKeyAlgorithm', $this->generator, 'Setting sub-key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'subKeySize', $this->generator, 'Setting sub-key size failed.' ); $this->assertAttributeEquals( $expectedUsage, 'subKeyUsage', $this->generator, 'Setting sub-key algorithm and size changed key usage.' ); } // }}} // {{{ testSetSubKeyParams_algorithm_size_and_usage() /** * @group mutators */ public function testSetSubKeyParams_algorithm_size_and_usage() { $expectedAlgorithm = Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN; $expectedSize = 1024; $expectedUsage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT; $this->generator->setSubKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN, 1024, Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT ); $this->assertAttributeEquals( $expectedAlgorithm, 'subKeyAlgorithm', $this->generator, 'Setting sub-key algorithm failed.' ); $this->assertAttributeEquals( $expectedSize, 'subKeySize', $this->generator, 'Setting sub-key size failed.' ); $this->assertAttributeEquals( $expectedUsage, 'subKeyUsage', $this->generator, 'Setting sub-key usage failed.' ); } // }}} // {{{ testSetSubKeyParams_invalid_elgamal_usage() /** * @group mutators * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testSetSubKeyParams_invalid_elgamal_usage() { $this->generator->setSubKeyParams( Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 2048, Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT ); } // }}} // {{{ testSetSubKeyParams_invalid_dsa_usage() /** * @group mutators * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testSetSubKeyParams_invalid_dsa_usage() { $this->generator->setSubKeyParams( Crypt_GPG_SubKey::ALGORITHM_DSA, 2048, Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT ); } // }}} // {{{ testSetStatusHandler() /** * @group mutators */ public function testSetStatusHandler() { $statusHandler = new Crypt_GPG_KeyGeneratorStatusHandler(); $this->generator->setStatusHandler($statusHandler); $this->assertAttributeEquals( $statusHandler, 'statusHandler', $this->generator, 'Setting status handler failed.' ); } // }}} // {{{ testSetErrorHandler() /** * @group mutators */ public function testSetErrorHandler() { $errorHandler = new Crypt_GPG_KeyGeneratorErrorHandler(); $this->generator->setErrorHandler($errorHandler); $this->assertAttributeEquals( $errorHandler, 'errorHandler', $this->generator, 'Setting error handler failed.' ); } // }}} // generate key tests // {{{ testGenerateKeyWithName() /** * @group generate-key */ public function testGenerateKeyWithName() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(0); $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->generateKey('Test Keypair'); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithNameAndEmail() /** * @group generate-key */ public function testGenerateKeyWithNameAndEmail() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $userId->setEmail('generate-test@example.com'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(0); $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->generateKey( 'Test Keypair', 'generate-test@example.com' ); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithNameEmailAndComment() /** * @group generate-key */ public function testGenerateKeyWithNameEmailAndComment() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $userId->setComment('do not use this key'); $userId->setEmail('generate-test@example.com'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(0); $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->generateKey( 'Test Keypair', 'generate-test@example.com', 'do not use this key' ); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithUserId() /** * @group generate-key */ public function testGenerateKeyWithUserId() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $userId->setEmail('generate-test@example.com'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(0); $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->generateKey( new Crypt_GPG_UserId( 'Test Keypair ' ) ); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithPassphrase() /** * @group generate-key */ public function testGenerateKeyWithPassphrase() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $userId->setEmail('generate-test@example.com'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(0); $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(0); $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->setPassphrase('test1')->generateKey( new Crypt_GPG_UserId( 'Test Keypair ' ) ); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithExpirationDate() /** * @group generate-key */ public function testGenerateKeyWithExpirationDate() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } // {{{ generate-test@example.com $expectedKey = new Crypt_GPG_Key(); $userId = new Crypt_GPG_UserId(); $userId->setName('Test Keypair'); $userId->setEmail('generate-test@example.com'); $expectedKey->addUserId($userId); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA); $subKey->setLength(1024); $subKey->setExpirationDate(1999998000); // truncated to day $subKey->setCanSign(true); $subKey->setCanEncrypt(false); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $subKey->setLength(2048); $subKey->setExpirationDate(1999998000); // truncated to day $subKey->setCanSign(false); $subKey->setCanEncrypt(true); $subKey->setHasPrivate(true); $expectedKey->addSubKey($subKey); // }}} $key = $this->generator->setExpirationDate(2000000000)->generateKey( new Crypt_GPG_UserId( 'Test Keypair ' ) ); $this->assertKeyEquals($expectedKey, $key); } // }}} // {{{ testGenerateKeyWithInvalidPrimaryKeyAlgorithm() /** * @group generate-key * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testGenerateKeyWithInvalidPrimaryKeyAlgorithm() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } $key = $this->generator ->setKeyParams(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN) ->generateKey( new Crypt_GPG_UserId( 'Test Keypair ' ) ); } // }}} // {{{ testGenerateKeyWithInvalidSubKeyAlgorithm() /** * @group generate-key * @expectedException Crypt_GPG_InvalidKeyParamsException */ public function testGenerateKeyWithInvalidSubKeyAlgorithm() { if (!$this->config['enable-key-generation']) { $this->markTestSkipped( 'Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.' ); } $key = $this->generator ->setSubKeyParams(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC_SGN) ->generateKey( new Crypt_GPG_UserId( 'Test Keypair ' ) ); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $returnedGenerator = $this->generator->setStatusHandler( new Crypt_GPG_KeyGeneratorStatusHandler() ); $this->assertEquals( $this->generator, $returnedGenerator, 'Failed asserting fluent interface works for setStatusHandler() ' . 'method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/KeyTest.php0000664000175000017500000004157112610161626015162 0ustar alecalec * $ phpunit KeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Key class. */ require_once 'Crypt/GPG/Key.php'; /** * User id class. */ require_once 'Crypt/GPG/UserId.php'; /** * Sub-key class. */ require_once 'Crypt/GPG/SubKey.php'; /** * Key class tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class KeyTestCase extends Crypt_GPG_TestCase { // accessors // {{{ testGetSubKeys() /** * @group accessors */ public function testGetSubKeys() { $key = new Crypt_GPG_Key(); $firstSubKey = new Crypt_GPG_SubKey(array( 'id' => 'C097D9EC94C06363', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785805, 'expiration' => 0, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $key->addSubKey($firstSubKey); $secondSubKey = new Crypt_GPG_SubKey(array( 'id' => '9F93F9116728EF12', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => 'C9C65B3BBF040E40D0EA27B79F93F9116728EF12', 'length' => 2048, 'creation' => 1221785821, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $key->addSubKey($secondSubKey); $subKeys = $key->getSubKeys(); $this->assertTrue(is_array($subKeys), 'Failed to assert returned sub-keys is an array.'); $this->assertEquals(2, count($subKeys), 'Failed to assert number of returned sub-keys is the same as ' . 'the number of sub-keys added.'); $this->assertContainsOnly('Crypt_GPG_SubKey', $subKeys, false, 'Failed to assert all returned sub-keys are Crypt_GPG_SubKey ' . 'objects.'); $this->assertArrayHasKey(0, $subKeys); $this->assertEquals($subKeys[0], $firstSubKey, 'Failed to assert the first sub-key is the same as the first ' . 'added sub-key.'); $this->assertArrayHasKey(1, $subKeys); $this->assertEquals($subKeys[1], $secondSubKey, 'Failed to assert the second sub-key is the same as the second ' . 'added sub-key.'); } // }}} // {{{ testGetUserIds() /** * @group accessors */ public function testGetUserIds() { $key = new Crypt_GPG_Key(); $firstUserId = new Crypt_GPG_UserId(array( 'name' => 'Alice', 'comment' => 'shipping', 'email' => 'alice@example.com' )); $key->addUserId($firstUserId); $secondUserId = new Crypt_GPG_UserId(array( 'name' => 'Bob', 'comment' => 'receiving', 'email' => 'bob@example.com' )); $key->addUserId($secondUserId); $userIds = $key->getUserIds(); $this->assertTrue(is_array($userIds), 'Failed to assert returned user ids is an array.'); $this->assertEquals(2, count($userIds), 'Failed to assert number of returned user ids is the same as ' . 'the number of user ids added.'); $this->assertContainsOnly('Crypt_GPG_UserId', $userIds, false, 'Failed to assert all returned user ids are Crypt_GPG_UserId ' . 'objects.'); $this->assertArrayHasKey(0, $userIds); $this->assertEquals($userIds[0], $firstUserId, 'Failed to assert the first user id is the same as the first ' . 'added user id.'); $this->assertArrayHasKey(1, $userIds); $this->assertEquals($userIds[1], $secondUserId, 'Failed to assert the second user id is the same as the second ' . 'added user id.'); } // }}} // {{{ testGetPrimaryKey() /** * @group accessors */ public function testGetPrimaryKey() { $key = new Crypt_GPG_Key(); $firstSubKey = new Crypt_GPG_SubKey(array( 'id' => 'C097D9EC94C06363', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785805, 'expiration' => 0, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $key->addSubKey($firstSubKey); $secondSubKey = new Crypt_GPG_SubKey(array( 'id' => '9F93F9116728EF12', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => 'C9C65B3BBF040E40D0EA27B79F93F9116728EF12', 'length' => 2048, 'creation' => 1221785821, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $key->addSubKey($secondSubKey); $primaryKey = $key->getPrimaryKey(); $this->assertEquals($firstSubKey, $primaryKey, 'Failed to assert the primary key is the same as the first added ' . 'sub-key.'); } // }}} // {{{ testCanSign_none() /** * @group accessors */ public function testCanSign_none() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canSign' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => false)); $key->addSubKey($subKey); $this->assertFalse($key->canSign()); } // }}} // {{{ testCanSign_one() /** * @group accessors */ public function testCanSign_one() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canSign' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => true)); $key->addSubKey($subKey); $this->assertTrue($key->canSign()); } // }}} // {{{ testCanSign_all() /** * @group accessors */ public function testCanSign_all() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canSign' => true)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => true)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canSign' => true)); $key->addSubKey($subKey); $this->assertTrue($key->canSign()); } // }}} // {{{ testCanEncrypt_none() /** * @group accessors */ public function testCanEncrypt_none() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => false)); $key->addSubKey($subKey); $this->assertFalse($key->canEncrypt()); } // }}} // {{{ testCanEncrypt_one() /** * @group accessors */ public function testCanEncrypt_one() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => false)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => true)); $key->addSubKey($subKey); $this->assertTrue($key->canEncrypt()); } // }}} // {{{ testCanEncrypt_all() /** * @group accessors */ public function testCanEncrypt_all() { $key = new Crypt_GPG_Key(); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => true)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => true)); $key->addSubKey($subKey); $subKey = new Crypt_GPG_SubKey(array('canEncrypt' => true)); $key->addSubKey($subKey); $this->assertTrue($key->canEncrypt()); } // }}} // mutators // {{{ testAddSubKey() /** * @group mutators */ public function testAddSubKey() { $key = new Crypt_GPG_Key(); $subKeys = $key->getSubKeys(); $this->assertTrue(is_array($subKeys), 'Failed to assert returned sub-keys is an array.'); $this->assertEquals(0, count($subKeys), 'Failed to assert there are no sub-keys.'); // add first sub-key $firstSubKey = new Crypt_GPG_SubKey(array( 'id' => 'C097D9EC94C06363', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785805, 'expiration' => 0, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $key->addSubKey($firstSubKey); $subKeys = $key->getSubKeys(); $this->assertTrue(is_array($subKeys), 'Failed to assert returned sub-keys is an array.'); $this->assertEquals(1, count($subKeys), 'Failed to assert number of returned sub-keys is the same as ' . 'the number of sub-keys added.'); $this->assertContainsOnly('Crypt_GPG_SubKey', $subKeys, false, 'Failed to assert all returned sub-keys are Crypt_GPG_SubKey ' . 'objects.'); $this->assertArrayHasKey(0, $subKeys); $this->assertEquals($subKeys[0], $firstSubKey, 'Failed to assert the first sub-key is the same as the first ' . 'added sub-key.'); // add second sub-key $secondSubKey = new Crypt_GPG_SubKey(array( 'id' => '9F93F9116728EF12', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => 'C9C65B3BBF040E40D0EA27B79F93F9116728EF12', 'length' => 2048, 'creation' => 1221785821, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $key->addSubKey($secondSubKey); $subKeys = $key->getSubKeys(); $this->assertTrue(is_array($subKeys), 'Failed to assert returned sub-keys is an array.'); $this->assertEquals(2, count($subKeys), 'Failed to assert number of returned sub-keys is the same as ' . 'the number of sub-keys added.'); $this->assertContainsOnly('Crypt_GPG_SubKey', $subKeys, false, 'Failed to assert all returned sub-keys are Crypt_GPG_SubKey ' . 'objects.'); $this->assertArrayHasKey(0, $subKeys); $this->assertEquals($subKeys[0], $firstSubKey, 'Failed to assert the first sub-key is the same as the first ' . 'added sub-key.'); $this->assertArrayHasKey(1, $subKeys); $this->assertEquals($subKeys[1], $secondSubKey, 'Failed to assert the second sub-key is the same as the second ' . 'added sub-key.'); } // }}} // {{{ testAddUserId() /** * @group mutators */ public function testAddUserId() { $key = new Crypt_GPG_Key(); $userIds = $key->getUserIds(); $this->assertTrue(is_array($userIds), 'Failed to assert returned user ids is an array.'); $this->assertEquals(0, count($userIds), 'Failed to assert there are no user ids.'); // add first user id $firstUserId = new Crypt_GPG_UserId(array( 'name' => 'Alice', 'comment' => 'shipping', 'email' => 'alice@example.com' )); $key->addUserId($firstUserId); $userIds = $key->getUserIds(); $this->assertTrue(is_array($userIds), 'Failed to assert returned user ids is an array.'); $this->assertEquals(1, count($userIds), 'Failed to assert number of returned user ids is the same as ' . 'the number of user ids added.'); $this->assertContainsOnly('Crypt_GPG_UserId', $userIds, false, 'Failed to assert all returned user ids are Crypt_GPG_UserId ' . 'objects.'); $this->assertArrayHasKey(0, $userIds); $this->assertEquals($userIds[0], $firstUserId, 'Failed to assert the first user id is the same as the first ' . 'added user id.'); // add second user id $secondUserId = new Crypt_GPG_UserId(array( 'name' => 'Bob', 'comment' => 'receiving', 'email' => 'bob@example.com' )); $key->addUserId($secondUserId); $userIds = $key->getUserIds(); $this->assertTrue(is_array($userIds), 'Failed to assert returned user ids is an array.'); $this->assertEquals(2, count($userIds), 'Failed to assert number of returned user ids is the same as ' . 'the number of user ids added.'); $this->assertContainsOnly('Crypt_GPG_UserId', $userIds, false, 'Failed to assert all returned user ids are Crypt_GPG_UserId ' . 'objects.'); $this->assertArrayHasKey(0, $userIds); $this->assertEquals($userIds[0], $firstUserId, 'Failed to assert the first user id is the same as the first ' . 'added user id.'); $this->assertArrayHasKey(1, $userIds); $this->assertEquals($userIds[1], $secondUserId, 'Failed to assert the second user id is the same as the second ' . 'added user id.'); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $key = new Crypt_GPG_Key(); // add first sub-key $firstSubKey = new Crypt_GPG_SubKey(array( 'id' => 'C097D9EC94C06363', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785805, 'expiration' => 0, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $returnedKey = $key->addSubKey($firstSubKey); $this->assertEquals( $key, $returnedKey, 'Failed asserting fluent interface works for addSubKey() method.' ); $firstUserId = new Crypt_GPG_UserId(array( 'name' => 'Alice', 'comment' => 'shipping', 'email' => 'alice@example.com' )); $returnedKey = $key->addUserId($firstUserId); $this->assertEquals( $key, $returnedKey, 'Failed asserting fluent interface works for addUserId() method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/phpunit.xml0000664000175000017500000000033012610161626015256 0ustar alecalec .:.. Crypt_GPG-1.4.0/tests/SignatureCreationInfoTest.php0000664000175000017500000000501612610161626020666 0ustar alecalec * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; //require_once 'Crypt/GPG/SignatureCreationInfo.php'; /** * Test the signature creation information class * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class SignatureCreationInfoTest extends Crypt_GPG_TestCase { public function testValidSigCreatedLine() { $sci = new Crypt_GPG_SignatureCreationInfo( 'SIG_CREATED D 17 2 00 1440922957 8D2299D9C5C211128B32BBB0C097D9EC94C06363' ); $this->assertTrue($sci->isValid()); $this->assertEquals(Crypt_GPG::SIGN_MODE_DETACHED, $sci->getMode()); $this->assertEquals(1440922957, $sci->getTimestamp()); $this->assertEquals(17, $sci->getPkAlgorithm()); $this->assertEquals(2, $sci->getHashAlgorithm()); $this->assertEquals('sha1', $sci->getHashAlgorithmName()); $this->assertEquals( '8D2299D9C5C211128B32BBB0C097D9EC94C06363', $sci->getKeyFingerprint() ); } public function testInvalidSigCreatedLine() { $sci = new Crypt_GPG_SignatureCreationInfo('foo bar'); $this->assertNull($sci->getMode()); $this->assertFalse($sci->isValid()); } } ?> Crypt_GPG-1.4.0/tests/SignatureTest.php0000664000175000017500000004342312610161626016371 0ustar alecalec * $ phpunit SignatureTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2011 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Signature class. */ require_once 'Crypt/GPG/Signature.php'; /** * Signature class tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class SignatureTestCase extends Crypt_GPG_TestCase { // construct // {{{ testConstructFromSignature() /** * @group construct */ public function testConstructFromSignature() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'keyId' => '0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature($expectedSignature); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testConstructFromArray() /** * @group construct */ public function testConstructFromArray() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'keyId' => '0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals('KuhELanvhPRXozEjFWb2mam1q20', $signature->getId()); $this->assertEquals('8D2299D9C5C211128B32BBB0C097D9EC94C06363', $signature->getKeyFingerprint()); $this->assertEquals('0C097D9EC94C06363', $signature->getKeyId()); $this->assertEquals(1221785858, $signature->getCreationDate()); $this->assertEquals(1421785858, $signature->getExpirationDate()); $this->assertFalse($signature->isValid()); $this->assertEquals('Alice ', strval($signature->getUserId())); } // }}} // accessors // {{{ testGetId() /** * @group accessors */ public function testGetId() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals('KuhELanvhPRXozEjFWb2mam1q20', $signature->getId()); } // }}} // {{{ testGetKeyFingerprint() /** * @group accessors */ public function testGetKeyFingerprint() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals('8D2299D9C5C211128B32BBB0C097D9EC94C06363', $signature->getKeyFingerprint()); } // }}} // {{{ testGetKeyId() /** * @group accessors */ public function testGetKeyId() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'keyId' => '0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals('0C097D9EC94C06363', $signature->getKeyId()); } // }}} // {{{ testGetCreationDate() /** * @group accessors */ public function testGetCreationDate() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals(1221785858, $signature->getCreationDate()); } // }}} // {{{ testGetExpirationDate() /** * @group accessors */ public function testGetExpirationDate() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertEquals(1421785858, $signature->getExpirationDate()); } // }}} // {{{ testIsValid() /** * @group accessors */ public function testIsValid() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $this->assertTrue($signature->isValid()); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $this->assertFalse($signature->isValid()); } // }}} // {{{ testGetUserId() /** * @group accessors */ public function testGetUserId() { $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Alice', 'email' => 'alice@example.com' )); $this->assertEquals($expectedUserId, $signature->getUserId()); } // }}} // mutators // {{{ testSetId() /** * @group mutators */ public function testSetId() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'something different', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature->setId('KuhELanvhPRXozEjFWb2mam1q20'); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetKeyFingerprint() /** * @group mutators */ public function testSetKeyFingerprint() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => 'bad fingerprint', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetKeyId() /** * @group mutators */ public function testSetKeyId() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'keyId' => '0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'keyId' => 'bad key id', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature->setKeyId('0C097D9EC94C06363'); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetCreationDate() /** * @group mutators */ public function testSetCreationDate() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1111111111, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature->setCreationDate(1221785858); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetExpirationDate() /** * @group mutators */ public function testSetExpirationDate() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 0, 'valid' => true, 'userId' => 'Alice ' )); $signature->setExpirationDate(1421785858); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetValid() /** * @group mutators */ public function testSetValid() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => false, 'userId' => 'Alice ' )); $signature->setValid(true); $this->assertEquals($expectedSignature, $signature); } // }}} // {{{ testSetUserId() /** * @group accessors */ public function testSetUserId() { $expectedSignature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Alice ' )); $signature = new Crypt_GPG_Signature(array( 'id' => 'KuhELanvhPRXozEjFWb2mam1q20', 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'creation' => 1221785858, 'expiration' => 1421785858, 'valid' => true, 'userId' => 'Bob ' )); $userId = new Crypt_GPG_UserId(array( 'name' => 'Alice', 'email' => 'alice@example.com' )); $signature->setUserId($userId); $this->assertEquals($expectedSignature, $signature); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setId('KuhELanvhPRXozEjFWb2mam1q20'); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setId() method.' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363' ); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setKeyFingerprint() ' . 'method.' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setKeyId('0C097D9EC94C06363'); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setKeyId() method' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setCreationDate(1234567890); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setCreationDate() ' . 'method.' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setExpirationDate(1234567890); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setExpirationDate() ' . 'method.' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setValid(true); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setValid() method.' ); $signature = new Crypt_GPG_Signature(); $returnedSignature = $signature->setUserId(new Crypt_GPG_UserId()); $this->assertEquals( $signature, $returnedSignature, 'Failed asserting fluent interface works for setUserId() method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/SignTest.php0000664000175000017500000004475212610161626015336 0ustar alecalec * $ phpunit SignTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests signing abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class SignTestCase extends Crypt_GPG_TestCase { public function testHasSignKeys() { $this->assertFalse($this->gpg->hasSignKeys()); $this->gpg->addSignKey('no-passphrase@example.com'); $this->assertTrue($this->gpg->hasSignKeys()); } // {{{ testSignKeyNotFoundException_invalid() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testSignKeyNotFoundException_invalid() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('non-existent-key@example.com'); $this->gpg->sign($data); } // }}} // {{{ testSignKeyNotFoundException_none() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testSignKeyNotFoundException_none() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->sign($data); } // }}} // {{{ testSignBadPassphraseException_missing() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testSignBadPassphraseException_missing() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com'); $this->gpg->sign($data); } // }}} // {{{ testSignBadPassphraseException_bad() /** * @expectedException Crypt_GPG_BadPassphraseException * * @group string */ public function testSignBadPassphraseException_bad() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'incorrect'); $this->gpg->sign($data); } // }}} // {{{ testSignNoPassphrase() /** * @group string */ public function testSignNoPassphrase() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('no-passphrase@example.com'); $signedData = $this->gpg->sign($data); $signatures = $this->gpg->verify($signedData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignNormal() /** * @group string */ public function testSignNormal() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->sign($data); $signatures = $this->gpg->verify($signedData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignClear() /** * @group string */ public function testSignClear() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_CLEAR); $signatures = $this->gpg->verify($signedData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDetached() /** * @group string */ public function testSignDetached() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signatureData = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_DETACHED); $signatures = $this->gpg->verify($data, $signatureData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDualOnePassphrase() /** * @group string */ public function testSignDualOnePassphrase() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('no-passphrase@example.com'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->sign($data); $signatures = $this->gpg->verify($signedData); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDualNormal() /** * @group string */ public function testSignDualNormal() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $signedData = $this->gpg->sign($data); $signatures = $this->gpg->verify($signedData); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDualClear() /** * @group string */ public function testSignDualClear() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $signedData = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_CLEAR); $signatures = $this->gpg->verify($signedData); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDualDetached() /** * @group string */ public function testSignDualDetached() { $data = 'Hello, Alice! Goodbye, Bob!'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $signatureData = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_DETACHED); $signatures = $this->gpg->verify($data, $signatureData); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignEmpty() /** * @group string */ public function testSignEmpty() { $data = ''; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->sign($data); $signatures = $this->gpg->verify($signedData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignDetachedTextmode() /** * @group string */ public function testSignDetachedTextmode() { // data with Unix line endings $data = "It was the best of times,\n" . "it was the worst of times,\n" . "it was the age of wisdom,\n" . "it was the age of foolishness,\n" . "it was the epoch of belief,\n" . "it was the epoch of incredulity,\n" . "it was the season of Light,\n" . "it was the season of Darkness,\n" . "it was the spring of hope,\n" . "it was the winter of despair,"; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signatureData = $this->gpg->sign( $data, Crypt_GPG::SIGN_MODE_DETACHED, true, true ); // convert data to Windows line endings $data = str_replace("\n", "\r\n", $data); // verify data $signatures = $this->gpg->verify($data, $signatureData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue( $signature->isValid(), 'Failed asserting textmode signature is valid.' ); } } // }}} // file // {{{ testSignFileNoPassphrase() /** * @group file */ public function testSignFileNoPassphrase() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileNoPassphrase.asc'); $this->gpg->addSignKey('no-passphrase@example.com'); $this->gpg->signFile($inputFilename, $outputFilename); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileNormal() /** * @group file */ public function testSignFileNormal() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileNormal.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename, $outputFilename); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileClear() /** * @group file */ public function testSignFileClear() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileClear.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename, $outputFilename, Crypt_GPG::SIGN_MODE_CLEAR); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDetached() /** * @group file */ public function testSignFileDetached() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileDetached.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename, $outputFilename, Crypt_GPG::SIGN_MODE_DETACHED); $signatureData = file_get_contents($outputFilename); $signatures = $this->gpg->verifyFile($inputFilename, $signatureData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDetachedToString() /** * @group file */ public function testSignFileDetachedToString() { $filename = $this->getDataFilename('testFileMedium.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signatureData = $this->gpg->signFile($filename, null, Crypt_GPG::SIGN_MODE_DETACHED); $signatures = $this->gpg->verifyFile($filename, $signatureData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDualOnePassphrase() /** * @group file */ public function testSignFileDualOnePassphrase() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileDualOnePassphrase.asc'); $this->gpg->addSignKey('no-passphrase@example.com'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename, $outputFilename); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDualNormal() /** * @group file */ public function testSignFileDualNormal() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileDualNormal.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $this->gpg->signFile($inputFilename, $outputFilename); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDualClear() /** * @group file */ public function testSignFileDualClear() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileDualClear.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $this->gpg->signFile($inputFilename, $outputFilename, Crypt_GPG::SIGN_MODE_CLEAR); $signatures = $this->gpg->verifyFile($outputFilename); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileDualDetached() /** * @group file */ public function testSignFileDualDetached() { $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = $this->getTempFilename('testSignFileDualDetached.asc'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->addSignKey('second-keypair@example.com', 'test2'); $this->gpg->signFile($inputFilename, $outputFilename, Crypt_GPG::SIGN_MODE_DETACHED); $signatureData = file_get_contents($outputFilename); $signatures = $this->gpg->verifyFile($inputFilename, $signatureData); $this->assertEquals(2, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testSignFileFileException_input() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testSignFileFileException_input() { // input file does not exist $inputFilename = $this->getDataFilename('testSignFileFileFileException_input.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename); } // }}} // {{{ testSignFileFileException_output() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testSignFileFileException_output() { // input file is encrypted with first-keypair@example.com // output file does not exist $inputFilename = $this->getDataFilename('testFileMedium.plain'); $outputFilename = './non-existent' . '/testSignFileFileException_output.plain'; $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $this->gpg->signFile($inputFilename, $outputFilename); } // }}} // {{{ testSignFileEmpty() /** * @group file */ public function testSignFileEmpty() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->signFile($filename); $signatures = $this->gpg->verify($signedData); $this->assertEquals(1, count($signatures)); foreach ($signatures as $signature) { $this->assertTrue($signature->isValid()); } } // }}} // {{{ testGetLastSignatureInfo() public function testGetLastSignatureInfo() { $this->gpg->addSignKey('first-keypair@example.com', 'test1'); $signedData = $this->gpg->sign('test', Crypt_GPG::SIGN_MODE_DETACHED); $sigInfo = $this->gpg->getLastSignatureInfo(); $this->assertInstanceOf('Crypt_GPG_SignatureCreationInfo', $sigInfo); $this->assertTrue($sigInfo->isValid()); $this->assertEquals(date('Y-m-d'), date('Y-m-d', $sigInfo->getTimestamp())); $this->assertEquals(Crypt_GPG::SIGN_MODE_DETACHED, $sigInfo->getMode()); $this->assertEquals( '8D2299D9C5C211128B32BBB0C097D9EC94C06363', $sigInfo->getKeyFingerprint() ); $this->assertNotNull($sigInfo->getHashAlgorithmName()); } // }}} } ?> Crypt_GPG-1.4.0/tests/SubKeyTest.php0000664000175000017500000007624512610161626015642 0ustar alecalec * $ phpunit SubKeyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Sub-key class. */ require_once 'Crypt/GPG/SubKey.php'; /** * Sub-key class tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class SubKeyTestCase extends Crypt_GPG_TestCase { // construct // {{{ testConstructFromString() /** * @group construct */ public function testConstructFromString() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'length' => 2048, 'creation' => 1221528655, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true, 'isRevoked' => true )); $string = 'sub:r:2048:16:8C37DBD2A01B7976:1221528655::::::e:'; $subKey = new Crypt_GPG_SubKey($string); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testConstructFromSubKey() /** * @group construct */ public function testConstructFromSubKey() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true, 'isRevoked' => true )); $subKey = new Crypt_GPG_SubKey($expectedSubKey); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testConstructFromArray() /** * @group construct */ public function testConstructFromArray() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true, 'isRevoked' => true )); $this->assertEquals('8C37DBD2A01B7976', $subKey->getId()); $this->assertEquals(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, $subKey->getAlgorithm()); $this->assertEquals('8D2299D9C5C211128B32BBB0C097D9EC94C06363', $subKey->getFingerprint()); $this->assertEquals(2048, $subKey->getLength()); $this->assertEquals(1221785858, $subKey->getCreationDate()); $this->assertEquals(1421785858, $subKey->getExpirationDate()); $this->assertFalse($subKey->canSign()); $this->assertTrue($subKey->canEncrypt()); $this->assertTrue($subKey->hasPrivate()); $this->assertTrue($subKey->isRevoked()); } // }}} // parse // {{{ testParse() /** * @group parse */ public function testParse() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'length' => 2048, 'creation' => 1221528655, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true, 'isRevoked' => true )); $string = 'sub:r:2048:16:8C37DBD2A01B7976:1221528655::::::e:'; $subKey = Crypt_GPG_SubKey::parse($string); $this->assertEquals($expectedSubKey, $subKey); // test parsing 'usage' flags $string = 'sub:r:2048:16:8C37DBD2A01B7976:1221528655::::::esca:'; $subKey = Crypt_GPG_SubKey::parse($string); $usage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT | Crypt_GPG_SubKey::USAGE_CERTIFY | Crypt_GPG_SubKey::USAGE_AUTHENTICATION; $this->assertEquals($usage, $subKey->usage()); } // }}} // {{{ testParseCreationDateIso() /** * @group parse */ public function testParseCreationDateIso() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'length' => 2048, 'creation' => 1221442255, 'expiration' => 0, 'canSign' => false, 'canEncrypt' => true )); $string = 'sub:u:2048:16:8C37DBD2A01B7976:20080915T013055::::::e:'; $subKey = Crypt_GPG_SubKey::parse($string); $this->assertEquals($expectedSubKey, $subKey); } // }}} // accessors // {{{ testGetId() /** * @group accessors */ public function testGetId() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals('8C37DBD2A01B7976', $subKey->getId()); } // }}} // {{{ testGetAlgorithm() /** * @group accessors */ public function testGetAlgorithm() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, $subKey->getAlgorithm()); } // }}} // {{{ testGetFingerprint() /** * @group accessors */ public function testGetFingerprint() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals('8D2299D9C5C211128B32BBB0C097D9EC94C06363', $subKey->getFingerprint()); } // }}} // {{{ testGetLength() /** * @group accessors */ public function testGetLength() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals(2048, $subKey->getLength()); } // }}} // {{{ testGetCreationDate() /** * @group accessors */ public function testGetCreationDate() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals(1221785858, $subKey->getCreationDate()); } // }}} // {{{ testGetExpirationDate() /** * @group accessors */ public function testGetExpirationDate() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertEquals(1421785858, $subKey->getExpirationDate()); } // }}} // {{{ testCanSign() /** * @group accessors */ public function testCanSign() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $this->assertTrue($subKey->canSign()); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertFalse($subKey->canSign()); } // }}} // {{{ testCanEncrypt() /** * @group accessors */ public function testCanEncrypt() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $this->assertTrue($subKey->canEncrypt()); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $this->assertFalse($subKey->canEncrypt()); } // }}} // {{{ testUsage() /** * @group accessors */ public function testUsage() { $usage = Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT | Crypt_GPG_SubKey::USAGE_CERTIFY | Crypt_GPG_SubKey::USAGE_AUTHENTICATION; $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'usage' => $usage, 'hasPrivate' => true )); $this->assertSame($usage, $subKey->usage()); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $this->assertSame(Crypt_GPG_SubKey::USAGE_SIGN, $subKey->usage()); } // }}} // {{{ testHasPrivate() /** * @group accessors */ public function testHasPrivate() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $this->assertTrue($subKey->hasPrivate()); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => false )); $this->assertFalse($subKey->hasPrivate()); } // }}} // {{{ testIsRevoked() /** * @group accessors */ public function testIsRevoked() { $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true, 'isRevoked' => true )); $this->assertTrue($subKey->isRevoked()); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => false, 'isRevoked' => false )); $this->assertFalse($subKey->isRevoked()); } // }}} // mutators // {{{ testSetId() /** * @group mutators */ public function testSetId() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => 'something different', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setId('8C37DBD2A01B7976'); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetAlgorithm() /** * @group mutators */ public function testSetAlgorithm() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetFingerprint() /** * @group mutators */ public function testSetFingerprint() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => 'something different', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetLength() /** * @group mutators */ public function testSetLength() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setLength(2048); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetCreationDate() /** * @group mutators */ public function testSetCreationDate() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1111111111, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setCreationDate(1221785858); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetExpirationDate() /** * @group mutators */ public function testSetExpirationDate() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1111111111, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey->setExpirationDate(1421785858); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetCanSign() /** * @group mutators */ public function testSetCanSign() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => true, 'canEncrypt' => false, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_DSA, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 1024, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => true )); $subKey->setCanSign(true); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetCanEncrypt() /** * @group mutators */ public function testSetCanEncrypt() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => true, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => true )); $subKey->setCanEncrypt(true); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetHasPrivate() /** * @group mutators */ public function testSetHasPrivate() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => false )); $subKey->setHasPrivate(true); $this->assertEquals($expectedSubKey, $subKey); } // }}} // {{{ testSetRevoked() /** * @group mutators */ public function testSetRevoked() { $expectedSubKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => false, 'isRevoked' => true )); $subKey = new Crypt_GPG_SubKey(array( 'id' => '8C37DBD2A01B7976', 'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC, 'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363', 'length' => 2048, 'creation' => 1221785858, 'expiration' => 1421785858, 'canSign' => false, 'canEncrypt' => false, 'hasPrivate' => false, 'isRevoked' => false )); $subKey->setRevoked(true); $this->assertEquals($expectedSubKey, $subKey); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setId('8C37DBD2A01B7976'); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setId() method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setAlgorithm( Crypt_GPG_SubKey::ALGORITHM_DSA ); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setAlgorithm() method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363' ); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setFingerprint() ' . 'method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setLength(2048); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setLength() method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setCreationDate(1234567890); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setCreationDate() ' . 'method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setExpirationDate(1234567890); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setExpirationDate() ' . 'method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setCanSign(true); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setCanSign() method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setCanEncrypt(true); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setCanEncrypt() ' . 'method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setHasPrivate(true); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setHasPrivate() ' . 'method.' ); $subKey = new Crypt_GPG_SubKey(); $returnedSubKey = $subKey->setRevoked(true); $this->assertEquals( $subKey, $returnedSubKey, 'Failed asserting fluent interface works for setRevoked() method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/TestCase.php0000664000175000017500000010025012610161626015273 0ustar alecalec * @copyright 2005-2013 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * The Crypt_GPG class to test */ require_once 'Crypt/GPG.php'; /** * Key class definition */ require_once 'Crypt/GPG/Key.php'; /** * Signature class definition */ require_once 'Crypt/GPG/Signature.php'; /** * Abstract base class for testing Crypt_GPG. * * Test keyring contains: * * 1) first-keypair@example.com - passphrase 'test1' * A public-private key pair that can be used to both encrypt and decrypt. * * 2) second-keypair@example.com - passphrase 'test2' * A public-private key pair that can be used to both encrypt and decrypt. * * 3) public-only@example.com - passphrase 'test' * A public key with no private key. Used for testing private key import. * * 4) no-passphrase@example.com - no passphrase * A public-private key pair that can be used to both encrypt and decrypt * with no passphrase. * * 5) external-public@example.com - passphrase 'test' * A public key that does not initially exist in the keyring that can be * imported. * * 6) multiple-subkeys@example.com - passphrases 'test1' and 'test2' * A public-private key pair that has multiple encrypting subkeys. The * first subkey is an ELG-E key. The second is an RSA key. */ abstract class Crypt_GPG_TestCase extends PHPUnit_Framework_TestCase { // {{{ class constants const HOMEDIR = 'test-keychain'; const TEMPDIR = 'temp-files'; const DATADIR = 'data-files'; // }}} // {{{ protected properties protected $gpg; // }}} // {{{ getOptions() protected function getOptions() { return array( 'homedir' => dirname(__FILE__) . '/' . self::HOMEDIR, // 'debug' => true ); } // }}} // set up // {{{ setUp() public function setUp() { // load test configuration file if it exists $configFilename = dirname(__FILE__).'/config.php'; if (file_exists($configFilename)) { include $configFilename; if ( !isset($GLOBALS['Crypt_GPG_Unittest_Config']) || !is_array($GLOBALS['Crypt_GPG_Unittest_Config']) ) { $this->markTestSkipped( 'Unit test configuration is incorrect. Please read the ' . 'documentation in TestCase.php and fix the ' . 'configuration file. See the configuration in ' . '\'config.php.dist\' for an example.' ); } $this->config = $GLOBALS['Crypt_GPG_Unittest_Config']; } else { $this->config = array(); } // default test config values if (!isset($this->config['enable-key-generation'])) { $this->config['enable-key-generation'] = false; } $this->_setUpKeyring(); $this->_setUpTempdir(); $this->gpg = new Crypt_GPG($this->getOptions()); } // }}} // {{{ _setUpKeyring() private function _setUpKeyring() { // {{{ pubring data $pubringData = <<getKeyringFilename('pubring.gpg'), 'wb'); fwrite($pubring, base64_decode(str_replace("\n", '', $pubringData))); fclose($pubring); $secring = fopen($this->getKeyringFilename('secring.gpg'), 'wb'); fwrite($secring, base64_decode(str_replace("\n", '', $secringData))); fclose($secring); $trustdb = fopen($this->getKeyringFilename('trustdb.gpg'), 'wb'); fwrite($trustdb, base64_decode(str_replace("\n", '', $trustdbData))); fclose($trustdb); $randomSeed = fopen($this->getKeyringFilename('random_seed'), 'wb'); fwrite($randomSeed, base64_decode( str_replace("\n", '', $randomSeedData))); fclose($randomSeed); } // }}} // {{{ _setUpTempdir() private function _setUpTempdir() { $directoryName = dirname(__FILE__) . '/' . self::TEMPDIR; if (!file_exists($directoryName)) { mkdir($directoryName); } } // }}} // tear down // {{{ tearDown() public function tearDown() { unset($this->gpg); $this->_tearDownKeyring(); $this->_tearDownTempdir(); } // }}} // {{{ _tearDownKeyring() private function _tearDownKeyring() { $filenames = array( $this->getKeyringFilename('pubring.gpg~'), $this->getKeyringFilename('secring.gpg~'), $this->getKeyringFilename('trustdb.gpg~'), $this->getKeyringFilename('pubring.gpg'), $this->getKeyringFilename('secring.gpg'), $this->getKeyringFilename('trustdb.gpg'), $this->getKeyringFilename('random_seed') ); foreach ($filenames as $filename) { if (file_exists($filename)) { unlink($filename); } } $dirnames = array( $this->getKeyringFilename('private-keys-v1.d') ); foreach ($dirnames as $dirname) { if (file_exists($dirname)) { rmdir($dirname); } } rmdir(dirname(__FILE__) . '/' . self::HOMEDIR); } // }}} // {{{ _tearDownTempdir() private function _tearDownTempdir() { $directoryName = dirname(__FILE__) . '/' . self::TEMPDIR; // remove temporary files and temporary directory $iterator = new DirectoryIterator($directoryName); foreach ($iterator as $file) { if (!$file->isDot()) { $filename = $this->getTempFilename($file->getFilename()); if (is_dir($filename)) { rmdir($filename); } else { unlink($filename); } } } rmdir($directoryName); } // }}} // file related helper methods // {{{ getMd5Sum() protected function getMd5Sum($filename) { if (`which md5sum` == '') { $this->markTestSkipped('md5sum not available. Cannot verify ' . 'files for file tests.'); } $sum = explode(' ', `md5sum $filename`); $sum = $sum[0]; return $sum; } // }}} // {{{ getKeyringFilename() protected function getKeyringFilename($filename) { return dirname(__FILE__) . '/'. self::HOMEDIR . '/' . $filename; } // }}} // {{{ getDataFilename() protected function getDataFilename($filename) { return dirname(__FILE__) . '/'. self::DATADIR . '/' . $filename; } // }}} // {{{ getTempFilename() protected function getTempFilename($filename) { return dirname(__FILE__) . '/' . self::TEMPDIR . '/' . $filename; } // }}} // signature related assertions // {{{ assertDecryptAndVerifyResultsEquals() protected function assertDecryptAndVerifyResultsEquals( array $expected, array $actual ) { $this->assertEquals( count($expected), count($actual), 'Result counts are different.' ); $this->assertArrayHasKey( 'data', $expected, 'Expected result does not include data.' ); $this->assertArrayHasKey( 'data', $actual, 'Actual result does not include data.' ); $this->assertArrayHasKey( 'signatures', $expected, 'Expected result does not include signatures.' ); $this->assertArrayHasKey( 'signatures', $actual, 'Actual result does not include signatures.' ); $this->assertEquals( $expected['data'], $actual['data'], 'Decrypted data does not match.' ); $this->assertSignaturesEquals( $expected['signatures'], $actual['signatures'] ); } // }}} // {{{ assertSignaturesEquals() protected function assertSignaturesEquals( array $expected, array $actual ) { $this->assertEquals( count($expected), count($actual), 'Signature counts are different.' ); for ($i = 0; $i < count($expected); $i++) { $this->assertSignatureEquals($expected[$i], $actual[$i]); } } // }}} // {{{ assertSignatureEquals() protected function assertSignatureEquals( Crypt_GPG_Signature $expected, Crypt_GPG_Signature $actual ) { $expectedUserId = $expected->getUserId(); $actualUserId = $actual->getUserId(); $this->assertEquals($expectedUserId, $actualUserId, 'Signature user ids do not match.' ); $expectedId = $expected->getId(); $actualId = $actual->getId(); $this->assertEquals( strlen($expectedId), strlen($actualId), 'Signature IDs are of different length.' ); $this->assertEquals( $expected->getKeyFingerprint(), $actual->getKeyFingerprint(), 'Signature key fingerprints do not match.' ); $this->assertEquals( $expected->getKeyId(), $actual->getKeyId(), 'Signature key IDs do not match.' ); $this->assertEquals( $expected->getCreationDate(), $actual->getCreationDate(), 'Signature creation dates do not match.' ); $this->assertEquals( $expected->getExpirationDate(), $actual->getExpirationDate(), 'Signature expiration dates do not match.' ); $this->assertEquals( $expected->isValid(), $actual->isValid(), 'Signature validity does match.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/UserIdTest.php0000664000175000017500000003201112610161626015612 0ustar alecalec * $ phpunit UserIdTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * User Id class. */ require_once 'Crypt/GPG/UserId.php'; /** * User id class tests for Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2008-2010 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class UserIdTestCase extends Crypt_GPG_TestCase { // construct // {{{ testConstructFromString() /** * @group construct */ public function testConstructFromString() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', 'email' => 'test@example.com' )); $string = 'Example User (This is a test comment) '; $userId = new Crypt_GPG_UserId($string); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testConstructFromUserId() /** * @group construct */ public function testConstructFromUserId() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', 'email' => 'test@example.com', 'revoked' => true, 'valid' => false )); $userId = new Crypt_GPG_UserId($expectedUserId); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testConstructFromArray() /** * @group construct */ public function testConstructFromArray() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', 'email' => 'test@example.com', 'revoked' => true, 'valid' => false )); $this->assertEquals('Example User', $userId->getName()); $this->assertEquals('This is a test comment', $userId->getComment()); $this->assertEquals('test@example.com', $userId->getEmail()); $this->assertTrue($userId->isRevoked()); $this->assertFalse($userId->isValid()); } // }}} // parse // {{{ testParseFull() /** * @group parse */ public function testParseFull() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', 'email' => 'test@example.com' )); $string = 'Example User (This is a test comment) '; $userId = Crypt_GPG_UserId::parse($string); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testParseNameOnly() /** * @group parse */ public function testParseNameOnly() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User' )); $string = 'Example User'; $userId = Crypt_GPG_UserId::parse($string); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testParseNameComment() /** * @group parse */ public function testParseNameComment() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment' )); $string = 'Example User (This is a test comment)'; $userId = Crypt_GPG_UserId::parse($string); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testParseNameEmail() /** * @group parse */ public function testParseNameEmail() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'email' => 'test@example.com' )); $string = 'Example User '; $userId = Crypt_GPG_UserId::parse($string); $this->assertEquals($expectedUserId, $userId); } // }}} // to-string // {{{ testToStringFull() /** * @group to-string */ public function testToStringFull() { $expected = 'Example User (This is a test comment) '; $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', 'email' => 'test@example.com' )); $string = strval($userId); $this->assertEquals($expected, $string); } // }}} // {{{ testToStringNameOnly() /** * @group to-string */ public function testToStringNameOnly() { $expected = 'Example User'; $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', )); $string = strval($userId); $this->assertEquals($expected, $string); } // }}} // {{{ testToStringNameComment() /** * @group to-string */ public function testToStringNameComment() { $expected = 'Example User (This is a test comment)'; $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment', )); $string = strval($userId); $this->assertEquals($expected, $string); } // }}} // {{{ testToStringNameEmail() /** * @group to-string */ public function testToStringNameEmail() { $expected = 'Example User '; $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'email' => 'test@example.com' )); $string = strval($userId); $this->assertEquals($expected, $string); } // }}} // accessors // {{{ testGetName() /** * @group accessors */ public function testGetName() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User' )); $this->assertEquals('Example User', $userId->getName()); } // }}} // {{{ testGetComment() /** * @group accessors */ public function testGetComment() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'This is a test comment' )); $this->assertEquals('This is a test comment', $userId->getComment()); } // }}} // {{{ testGetEmail() /** * @group accessors */ public function testGetEmail() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'email' => 'test@example.com' )); $this->assertEquals('test@example.com', $userId->getEmail()); } // }}} // {{{ testIsRevoked() /** * @group accessors */ public function testIsRevoked() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'revoked' => true, )); $this->assertTrue($userId->isRevoked()); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'revoked' => false, )); $this->assertFalse($userId->isRevoked()); } // }}} // {{{ testIsValid() /** * @group accessors */ public function testIsValid() { $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'valid' => true, )); $this->assertTrue($userId->isValid()); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'valid' => false, )); $this->assertFalse($userId->isValid()); } // }}} // mutators // {{{ testSetName() /** * @group mutators */ public function testSetName() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Second Name' )); $userId = new Crypt_GPG_UserId(array( 'name' => 'First Name' )); $userId->setName('Second Name'); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testSetComment() /** * @group mutators */ public function testSetComment() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'Second comment text' )); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'comment' => 'First comment text' )); $userId->setComment('Second comment text'); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testSetEmail() /** * @group mutators */ public function testSetEmail() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'email' => 'second@example.com' )); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'email' => 'first@example.com' )); $userId->setEmail('second@example.com'); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testSetRevoked() /** * @group mutators */ public function testSetRevoked() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'revoked' => true, )); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'revoked' => false, )); $userId->setRevoked(true); $this->assertEquals($expectedUserId, $userId); } // }}} // {{{ testSetValid() /** * @group mutators */ public function testSetValid() { $expectedUserId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'valid' => true, )); $userId = new Crypt_GPG_UserId(array( 'name' => 'Example User', 'valid' => false, )); $userId->setValid(true); $this->assertEquals($expectedUserId, $userId); } // }}} // fluent interface // {{{ testFluentInterface /** * @group fluent */ public function testFluentInterface() { $userId = new Crypt_GPG_UserId(); $returnedUserId = $userId->setName('Alice'); $this->assertEquals( $userId, $returnedUserId, 'Failed asserting fluent interface works for setName() method.' ); $userId = new Crypt_GPG_UserId(); $returnedUserId = $userId->setComment('encryption is fun'); $this->assertEquals( $userId, $returnedUserId, 'Failed asserting fluent interface works for setComment() method.' ); $userId = new Crypt_GPG_UserId(); $returnedUserId = $userId->setEmail('test@example.com'); $this->assertEquals( $userId, $returnedUserId, 'Failed asserting fluent interface works for setEmail() method.' ); $userId = new Crypt_GPG_UserId(); $returnedUserId = $userId->setRevoked(true); $this->assertEquals( $userId, $returnedUserId, 'Failed asserting fluent interface works for setRevoked() method.' ); $userId = new Crypt_GPG_UserId(); $returnedUserId = $userId->setValid(true); $this->assertEquals( $userId, $returnedUserId, 'Failed asserting fluent interface works for setValid() method.' ); } // }}} } ?> Crypt_GPG-1.4.0/tests/VerifyTest.php0000664000175000017500000006563112610161626015701 0ustar alecalec * $ phpunit VerifyTestCase * * * LICENSE: * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @version CVS: $Id$ * @link http://pear.php.net/package/Crypt_GPG */ /** * Base test case. */ require_once 'TestCase.php'; /** * Tests verification abilities of Crypt_GPG. * * @category Encryption * @package Crypt_GPG * @author Michael Gauthier * @copyright 2005-2008 silverorange * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 * @link http://pear.php.net/package/Crypt_GPG */ class VerifyTestCase extends Crypt_GPG_TestCase { // string // {{{ testVerifyNoDataException_invalid() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testVerifyNoDataException_invalid() { $signedData = 'Invalid OpenPGP data.'; $this->gpg->verify($signedData); } // }}} // {{{ testVerifyNoDataException_empty() /** * @expectedException Crypt_GPG_NoDataException * * @group string */ public function testVerifyNoDataException_empty() { $signedData = ''; $this->gpg->verify($signedData); } // }}} // {{{ testVerifyKeyNotFoundException() /** * @expectedException Crypt_GPG_KeyNotFoundException * * @group string */ public function testVerifyKeyNotFoundException() { $data = 'Hello, Alice! Goodbye, Bob!'; // {{{ detached signature $detachedSignature = <<gpg->verify($data, $detachedSignature); } // }}} // {{{ testVerifyNormalSignedData() /** * @group string */ public function testVerifyNormalSignedData() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('KuhELanvhPRXozEjFWb2mam1q20'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221785858); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} // {{{ normal signed data $normalSignedData = <<gpg->verify($normalSignedData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyClearsignedData() /** * @group string */ public function testVerifyClearsignedData() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('wwm5gqNiFS+E/tmqbt1uXvVy3Ck'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221785858); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} // {{{ clearsigned data $clearsignedData = <<gpg->verify($clearsignedData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyDetachedSignature() /** * @group string */ public function testVerifyDetachedSignature() { $data = 'Hello, Alice! Goodbye, Bob!'; // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('E4HEDmMtecF457JFb88UAtPBVWY'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221785858); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} // {{{ detached signature $detachedSignature = <<gpg->verify($data, $detachedSignature); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyDualNormalSignedData() /** * @group string */ public function testVerifyDualNormalSignedData() { // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('4BunvSK18HPx6Xt4tEzyAqcNVzY'); $firstSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $firstSignature->setKeyId('03CC890AFA1DAD4B'); $firstSignature->setCreationDate(1221785858); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('oAZ64v4sFarc7dssFOAJPB0D7zs'); $secondSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $secondSignature->setKeyId('C097D9EC94C06363'); $secondSignature->setCreationDate(1221785858); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $secondSignature->setUserId($userId); // }}} // {{{ dual normal signed data $dualNormalSignedData = <<gpg->verify($dualNormalSignedData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyDualClearsignedData() /** * @group string */ public function testVerifyDualClearsignedData() { // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('MCn4/0Giq0njPh2smOs3Lrdc7yY'); $firstSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $firstSignature->setKeyId('03CC890AFA1DAD4B'); $firstSignature->setCreationDate(1221785858); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('O5tcpOAXJhd0v5TBxqhIixgphn8'); $secondSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $secondSignature->setKeyId('C097D9EC94C06363'); $secondSignature->setCreationDate(1221785858); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $secondSignature->setUserId($userId); // }}} // {{{ dual clearsigned data $dualClearsignedData = <<gpg->verify($dualClearsignedData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyDualDetachedSignature() /** * @group string */ public function testVerifyDualDetachedSignature() { $data = 'Hello, Alice! Goodbye, Bob!'; // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('tejKd9+9OBUM+EsrbV3fVuOiBeE'); $firstSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $firstSignature->setKeyId('03CC890AFA1DAD4B'); $firstSignature->setCreationDate(1221785858); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('7oizks/aha+bSONesnWDu1x2jn8'); $secondSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $secondSignature->setKeyId('C097D9EC94C06363'); $secondSignature->setCreationDate(1221785858); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $secondSignature->setUserId($userId); // }}} // {{{ dual detached signature $dualDetachedSignature = <<gpg->verify($data, $dualDetachedSignature); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyBadSignature() /** * @group string */ public function testVerifyBadSignature() { $modifiedData = 'Hello, Bob! Goodbye, Alice!'; // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setKeyId('C097D9EC94C06363'); $signature->setValid(false); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} // {{{ detached signature $detachedSignature = <<gpg->verify($modifiedData, $detachedSignature); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyDualBadSignatures() /** * @group string */ public function testVerifyDualBadSignatures() { $modifiedData = 'Hello, Bob! Goodbye, Alice!'; // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setExpirationDate(0); $firstSignature->setValid(false); $firstSignature->setKeyId('03CC890AFA1DAD4B'); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setValid(false); $secondSignature->setKeyId('C097D9EC94C06363'); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $secondSignature->setUserId($userId); // }}} // {{{ dual detached signature $dualDetachedSignature = <<gpg->verify($modifiedData, $dualDetachedSignature); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // file // {{{ testVerifyFileNormalSignedData() /** * @group file */ public function testVerifyFileNormalSignedData() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('vctnI/HnsRYmqcVwCJcJhS60lKU'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221960707); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedSignatures = array($signature); $filename = $this->getDataFilename('testVerifyFileNormalSignedData.asc'); $signatures = $this->gpg->verifyFile($filename); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileClearsignedData() /** * @group file */ public function testVerifyFileClearsignedData() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('6sXJXKZB5lvRSCXBAYl6R2EiDmw'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221960707); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} $expectedSignatures = array($signature); $filename = $this->getDataFilename('testVerifyFileClearsignedData.asc'); $signatures = $this->gpg->verifyFile($filename); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileDetachedSignature() /** * @group file */ public function testVerifyFileDetachedSignature() { // {{{ signature $signature = new Crypt_GPG_Signature(); $signature->setId('tdsH/ulxOnoWEMPDamZTq7wzF/0'); $signature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $signature->setKeyId('C097D9EC94C06363'); $signature->setCreationDate(1221960707); $signature->setExpirationDate(0); $signature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $signature->setUserId($userId); // }}} // {{{ signatureData $signatureData = <<getDataFilename('testFileMedium.plain'); $signatures = $this->gpg->verifyFile($filename, $signatureData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileDualNormalSignedData() /** * @group file */ public function testVerifyFileDualNormalSignedData() { // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('Kl3Mds4ABT9JyE3iqfPGpUHzKQs'); $firstSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $firstSignature->setKeyId('C097D9EC94C06363'); $firstSignature->setCreationDate(1221960707); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('KGrEm3hGqiKaLbjvOUO9kvUjRXc'); $secondSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $secondSignature->setKeyId('03CC890AFA1DAD4B'); $secondSignature->setCreationDate(1221960707); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $secondSignature->setUserId($userId); // }}} $expectedSignatures = array($firstSignature, $secondSignature); $filename = $this->getDataFilename('testVerifyFileDualNormalSignedData.asc'); $signatures = $this->gpg->verifyFile($filename); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileDualClearsignedData() /** * @group file */ public function testVerifyFileDualClearsignedData() { // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('eRRcEecpFk0YK/iswddS/KBxEXI'); $firstSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $firstSignature->setKeyId('C097D9EC94C06363'); $firstSignature->setCreationDate(1221960707); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('jsWYGJe/0hmte7tYt8zuJd7rFMM'); $secondSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $secondSignature->setKeyId('03CC890AFA1DAD4B'); $secondSignature->setCreationDate(1221960707); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $secondSignature->setUserId($userId); // }}} $expectedSignatures = array($firstSignature, $secondSignature); $filename = $this->getDataFilename('testVerifyFileDualClearsignedData.asc'); $signatures = $this->gpg->verifyFile($filename); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileDualDetachedSignature() /** * @group file */ public function testVerifyFileDualDetachedSignature() { // {{{ first signature $firstSignature = new Crypt_GPG_Signature(); $firstSignature->setId('T7+toJbsFr8KMTWN+M7lF3xSmmA'); $firstSignature->setKeyFingerprint( '8D2299D9C5C211128B32BBB0C097D9EC94C06363'); $firstSignature->setKeyId('C097D9EC94C06363'); $firstSignature->setCreationDate(1221960707); $firstSignature->setExpirationDate(0); $firstSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('First Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('first-keypair@example.com'); $firstSignature->setUserId($userId); // }}} // {{{ second signature $secondSignature = new Crypt_GPG_Signature(); $secondSignature->setId('HJd1yvMbEbW5facuxkDtvwymKrw'); $secondSignature->setKeyFingerprint( '880922DBEA733E906693E4A903CC890AFA1DAD4B'); $secondSignature->setKeyId('03CC890AFA1DAD4B'); $secondSignature->setCreationDate(1221960707); $secondSignature->setExpirationDate(0); $secondSignature->setValid(true); $userId = new Crypt_GPG_UserId(); $userId->setName('Second Keypair Test Key'); $userId->setComment('do not encrypt important data with this key'); $userId->setEmail('second-keypair@example.com'); $secondSignature->setUserId($userId); // }}} // {{{ signature data $signatureData = <<getDataFilename('testFileMedium.plain'); $signatures = $this->gpg->verifyFile($filename, $signatureData); $this->assertSignaturesEquals($expectedSignatures, $signatures); } // }}} // {{{ testVerifyFileFileException() /** * @expectedException Crypt_GPG_FileException * * @group file */ public function testVerifyFileFileException() { $filename = './non-existent/testVerifyFileFileException.asc'; $this->gpg->verifyFile($filename); } // }}} // {{{ testVerifyFileNoDataException() /** * @expectedException Crypt_GPG_NoDataException * * @group file */ public function testVerifyFileNoDataException() { $filename = $this->getDataFilename('testFileEmpty.plain'); $this->gpg->verifyFile($filename); } // }}} } ?> Crypt_GPG-1.4.0/LICENSE0000664000175000017500000006351012610161626012721 0ustar alecalec GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Crypt_GPG-1.4.0/README.md0000664000175000017500000000252712610161626013174 0ustar alecalec# Crypt_GPG # Crypt_GPG is a PHP package to interact with the [GNU Privacy Guard (GnuPG)](http://www.gnupg.org/). GnuPG is a free and open-source implementation of the [OpenPGP](http://www.ietf.org/rfc/rfc4880.txt) protocol, providing key management, data encryption and data signing. Crypt_GPG provides an object-oriented API for performing OpenPGP actions using GnuPG. [Crypt_GPG](http://pear.php.net/package/Crypt_GPG) has been migrated from [PEAR SVN](https://svn.php.net/repository/pear/packages/Crypt_GPG). ## Documentation ## ### Quick Example ```php addEncryptKey('test@example.com'); $data = $gpg->encrypt('my secret data'); ?> ``` ### Further Documentation ### * [High-Level Documentation](http://pear.php.net/manual/en/package.encryption.crypt-gpg.intro.php) * [Detailed API Documentation](http://pear.php.net/package/Crypt_GPG/docs/latest/) ## Bugs and Issues ## Please report all new issues via the [PEAR bug tracker](http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Crypt_GPG). Please submit pull requests for your bug reports! ## Testing ## To test, run either $ phpunit tests/ or $ pear run-tests -r ## Building ## To build, simply $ pear package ## Installing ## To install from scratch $ pear install package.xml To upgrade $ pear upgrade -f package.xml