package.xml 0000664 0001750 0001750 00000025322 14203233501 011564 0 ustar alec alec
Crypt_GPGpear.php.netGNU 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.4.8 or greater.Mike Gauthiergauthiermmike@silverorange.comyesNathan Fredricksonnrfnathan@silverorange.comyesAleksander Machniakalecalec@alec.plyes2022-02-161.6.71.6.7stablestableLGPL
[CVE-2022-24953] Insert the end-of-options marker before operation arguments [thomas-chauchefoin-sonarsource].
Ignore tests/debug.log and .gitattributes itself.
5.4.81.4.0Console_CommandLinepear.php.net1.1.10mbstringwindowsposix1.6.71.6.7stablestable2022-02-16LGPL
[CVE-2022-24953] Insert the end-of-options marker before operation arguments [thomas-chauchefoin-sonarsource].
Ignore tests/debug.log and .gitattributes itself.
Crypt_GPG-1.6.7/Crypt/GPG/Engine.php 0000664 0001750 0001750 00000201776 14203233501 015361 0 ustar alec alec
*
* @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/
*/
/**
* Crypt_GPG base class.
*/
require_once 'Crypt/GPG.php';
/**
* GPG exception classes.
*/
require_once 'Crypt/GPG/Exceptions.php';
/**
* Status/Error handler class.
*/
require_once 'Crypt/GPG/ProcessHandler.php';
/**
* Process control methods.
*/
require_once 'Crypt/GPG/ProcessControl.php';
/**
* Information about a created signature
*/
require_once 'Crypt/GPG/SignatureCreationInfo.php';
/**
* Standard PEAR exception is used if GPG binary is not found.
*/
require_once 'PEAR/Exception.php';
/**
* 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
{
/**
* Size of data chunks that are sent to and retrieved from the IPC pipes.
*
* The value of 65536 has been chosen empirically
* as the one with best performance.
*
* @see https://pear.php.net/bugs/bug.php?id=21077
*/
const CHUNK_SIZE = 65536;
/**
* 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';
/**
* Whether or not to use strict mode
*
* When set to true, any clock problems (e.g. keys generate in future)
* are errors, otherwise they are just warnings.
*
* Strict mode is disabled by default.
*
* @var boolean
* @see Crypt_GPG_Engine::__construct()
*/
private $_strict = false;
/**
* 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.
*
* This can be set to a callable function where first argument is the
* debug line to process.
*
* Debugging is off by default.
*
* @var mixed
* @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 = '';
/**
* Location of GnuPG conf binary
*
* Only used for GnuPG 2.1.x
*
* @var string
* @see Crypt_GPG_Engine::__construct()
* @see Crypt_GPG_Engine::_getGPGConf()
*/
private $_gpgconf = null;
/**
* 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;
/**
* Message digest algorithm.
*
* @var string
*/
private $_digest_algo = null;
/**
* Symmetric cipher algorithm.
*
* @var string
*/
private $_cipher_algo = null;
/**
* Compress algorithm.
*
* @var string
*/
private $_compress_algo = null;
/**
* Additional per-command arguments
*
* @var array
*/
private $_options = array();
/**
* Commands to be sent to GPG's command input stream
*
* @var string
* @see Crypt_GPG_Engine::sendCommand()
*/
private $_commandBuffer = '';
/**
* A status/error handler
*
* @var Crypt_GPG_ProcessHanler
*/
private $_processHandler = null;
/**
* 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 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 = '';
/**
* Creates a new GPG engine
*
* @param array $options An array of options used to create the engine object.
* All options are optional and are represented as key-value
* pairs. See Crypt_GPGAbstract::__construct() for more info.
*
* @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
* could 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'];
if ($this->_agent && !is_executable($this->_agent)) {
throw new PEAR_Exception(
'Specified gpg-agent binary is not executable.'
);
}
} else {
$this->_agent = $this->_getAgent();
}
if (array_key_exists('gpgconf', $options)) {
$this->_gpgconf = $options['gpgconf'];
if ($this->_gpgconf && !is_executable($this->_gpgconf)) {
throw new PEAR_Exception(
'Specified gpgconf binary is not executable.'
);
}
}
/*
* 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 = $options['debug'];
}
$this->_strict = !empty($options['strict']);
if (!empty($options['digest-algo'])) {
$this->_digest_algo = $options['digest-algo'];
}
if (!empty($options['cipher-algo'])) {
$this->_cipher_algo = $options['cipher-algo'];
}
if (!empty($options['compress-algo'])) {
$this->_compress_algo = $options['compress-algo'];
}
if (!empty($options['options'])) {
$this->_options = $options['options'];
}
}
/**
* 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();
$this->_closeIdleAgents();
}
/**
* 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
);
}
/**
* 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
);
}
/**
* 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;
}
}
/**
* 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->_commandBuffer = '';
$this->_statusHandlers = array();
$this->_errorHandlers = array();
if ($this->_debug) {
$this->addStatusHandler(array($this, '_handleDebugStatus'));
$this->addErrorHandler(array($this, '_handleDebugError'));
}
$this->_processHandler = new Crypt_GPG_ProcessHandler($this);
$this->addStatusHandler(array($this->_processHandler, 'handleStatus'));
$this->addErrorHandler(array($this->_processHandler, 'handleError'));
}
/**
* Runs the current GPG operation.
*
* This creates and manages the GPG subprocess.
* This will close input/output file handles.
*
* 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.
* @throws Crypt_GPG_Exception if an unknown or unexpected error occurs.
*
* @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();
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
foreach ($this->_options as $optname => $args) {
if (strpos($operation, '--' . $optname) !== false) {
$this->_arguments[] = $args;
}
}
$this->_processHandler->setOperation($operation);
}
/**
* Sets the PINENTRY_USER_DATA environment variable with the currently
* added keys and passphrases
*
* Keys and passphrases are stored as an indexed array of passphrases
* in 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
*/
public function setPins(array $keys)
{
$envKeys = array();
foreach ($keys as $keyId => $key) {
$envKeys[$keyId] = is_array($key) ? $key['passphrase'] : $key;
}
$_ENV['PINENTRY_USER_DATA'] = json_encode($envKeys);
}
/**
* Sets per-command additional arguments
*
* @param array $options Additional per-command options for GPG command.
* Note: This will unset options set previously.
* Key of the array is a command (e.g.
* gen-key, import, sign, encrypt, list-keys).
* Value is a string containing command line arguments to be
* added to the related command. For example:
* array('sign' => '--emit-version').
*
* @return void
*/
public function setOptions(array $options)
{
$this->_options = $options;
}
/**
* 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,
'agent' => $this->_agent,
);
$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();
$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;
}
/**
* Get data from the last process execution.
*
* @param string $name Data element name (e.g. 'SignatureInfo')
*
* @return mixed
* @see Crypt_GPG_ProcessHandler::getData()
*/
public function getProcessData($name)
{
if ($this->_processHandler) {
switch ($name) {
case 'SignatureInfo':
if ($data = $this->_processHandler->getData('SigCreated')) {
return new Crypt_GPG_SignatureCreationInfo($data);
}
break;
case 'Signatures':
case 'Warnings':
return (array) $this->_processHandler->getData($name);
default:
return $this->_processHandler->getData($name);
}
}
}
/**
* Set some data for the process execution.
*
* @param string $name Data element name (e.g. 'Handle')
* @param mixed $value Data value
*
* @return void
*/
public function setProcessData($name, $value)
{
if ($this->_processHandler) {
$this->_processHandler->setData($name, $value);
}
}
/**
* Displays debug output for status lines
*
* @param string $line the status line to handle.
*
* @return void
*/
private function _handleDebugStatus($line)
{
$this->_debug('STATUS: ' . $line);
}
/**
* Displays debug output for error lines
*
* @param string $line the error line to handle.
*
* @return void
*/
private function _handleDebugError($line)
{
$this->_debug('ERROR: ' . $line);
}
/**
* 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;
$inputPosition = 0;
$eolLength = mb_strlen(PHP_EOL, '8bit');
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 = mb_substr($inputBuffer, $inputPosition, self::CHUNK_SIZE, '8bit');
$length = mb_strlen($chunk, '8bit');
$this->_debug(
'=> about to write ' . $length . ' bytes to GPG input'
);
$length = fwrite($fdInput, $chunk, $length);
if ($length === 0 || $length === false) {
// 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 error 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');
// Move the position pointer, don't modify $inputBuffer (#21081)
if (is_string($this->_input)) {
$inputPosition += $length;
} else {
$inputPosition = 0;
$inputBuffer = mb_substr($inputBuffer, $length, null, '8bit');
}
}
}
// read input (from PHP stream)
// If the buffer is too big wait until it's smaller, we don't want
// to use too much memory
if (in_array($this->_input, $inputStreams, true)
&& mb_strlen($inputBuffer, '8bit') < self::CHUNK_SIZE
) {
$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 = mb_strlen($chunk, '8bit');
$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 = mb_substr($messageBuffer, 0, self::CHUNK_SIZE, '8bit');
$length = mb_strlen($chunk, '8bit');
$this->_debug(
'=> about to write ' . $length . ' bytes to GPG message'
);
$length = fwrite($fdMessage, $chunk, $length);
if ($length === 0 || $length === false) {
// 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 error 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 = mb_substr($messageBuffer, $length, null, '8bit');
}
}
// 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 = mb_strlen($chunk, '8bit');
$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 = mb_strlen($chunk, '8bit');
$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 = mb_substr($outputBuffer, 0, self::CHUNK_SIZE, '8bit');
$length = mb_strlen($chunk, '8bit');
$this->_debug(
'=> about to write ' . $length . ' bytes to output stream'
);
$length = fwrite($this->_output, $chunk, $length);
if ($length === 0 || $length === false) {
// 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 error code in PHP. See
// PHP Bug #39598. https://bugs.php.net/bug.php?id=39598
$this->_debug('=> broken pipe on output stream');
$this->_debug('=> closing pipe output stream');
$this->_closePipe(self::FD_OUTPUT);
} else {
$this->_debug('=> wrote ' . $length . ' bytes');
$outputBuffer = mb_substr($outputBuffer, $length, null, '8bit');
}
}
// 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 = mb_strlen($chunk, '8bit');
$errorBuffer .= $chunk;
$this->_debug('=> read ' . $length . ' bytes');
// pass lines to error handlers
while (($pos = strpos($errorBuffer, PHP_EOL)) !== false) {
$line = mb_substr($errorBuffer, 0, $pos, '8bit');
foreach ($this->_errorHandlers as $handler) {
array_unshift($handler['args'], $line);
call_user_func_array(
$handler['callback'],
$handler['args']
);
array_shift($handler['args']);
}
$errorBuffer = mb_substr($errorBuffer, $pos + $eolLength, null, '8bit');
}
}
// 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 = mb_strlen($chunk, '8bit');
$statusBuffer .= $chunk;
$this->_debug('=> read ' . $length . ' bytes');
// pass lines to status handlers
while (($pos = strpos($statusBuffer, PHP_EOL)) !== false) {
$line = mb_substr($statusBuffer, 0, $pos, '8bit');
// only pass lines beginning with magic prefix
if (mb_substr($line, 0, 9, '8bit') == '[GNUPG:] ') {
$line = mb_substr($line, 9, null, '8bit');
foreach ($this->_statusHandlers as $handler) {
array_unshift($handler['args'], $line);
call_user_func_array(
$handler['callback'],
$handler['args']
);
array_shift($handler['args']);
}
}
$statusBuffer = mb_substr($statusBuffer, $pos + $eolLength, null, '8bit');
}
}
// write command (to GPG)
if (in_array($fdCommand, $outputStreams, true)) {
$this->_debug('GPG is ready for command data');
// send commands
$chunk = mb_substr($this->_commandBuffer, 0, self::CHUNK_SIZE, '8bit');
$length = mb_strlen($chunk, '8bit');
$this->_debug(
'=> about to write ' . $length . ' bytes to GPG command'
);
$length = fwrite($fdCommand, $chunk, $length);
if ($length === 0 || $length === false) {
// 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 error 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 = mb_substr($this->_commandBuffer, $length, null, '8bit');
}
}
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');
}
/**
* 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();
// log versions, but not when looking for the version number
if ($version !== '1.0.0') {
$this->_debug('USING GPG ' . $version . ' with PHP ' . PHP_VERSION);
}
// 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 < 2.1.13 start the gpg-agent
if (version_compare($version, '2.0.0', 'ge')
&& version_compare($version, '2.1.13', 'lt')
) {
if (!$this->_agent) {
throw new Crypt_GPG_OpenSubprocessException(
'Unable to open gpg-agent subprocess (gpg-agent not found). ' .
'Please specify location of the gpg-agent binary ' .
'using the \'agent\' driver option.'
);
}
$agentArguments = array(
'--daemon',
'--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);
}
if ($version21 = version_compare($version, '2.1.0', 'ge')) {
// This is needed to get socket file location in stderr output
// Note: This does not help when the agent already is running
$agentArguments[] = '--verbose';
}
$agentCommandLine = $this->_agent . ' ' . implode(' ', $agentArguments);
$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);
// For GnuPG 2.1 we need to read both stderr and stdout
if ($version21) {
$agentInfo .= "\n" . fread($this->_agentPipes[self::FD_ERROR], self::CHUNK_SIZE);
}
if ($agentInfo) {
foreach (explode("\n", $agentInfo) as $line) {
if ($version21) {
if (preg_match('/listening on socket \'([^\']+)/', $line, $m)) {
$this->_agentInfo = $m[1];
} else if (preg_match('/gpg-agent\[([0-9]+)\].* started/', $line, $m)) {
$this->_agentInfo .= ':' . $m[1] . ':1';
}
} else if (preg_match('/GPG_AGENT_INFO[=\s]([^;]+)/', $line, $m)) {
$this->_agentInfo = $m[1];
break;
}
}
}
$this->_debug('GPG-AGENT-INFO: ' . $this->_agentInfo);
$env['GPG_AGENT_INFO'] = $this->_agentInfo;
// gpg-agent daemon is started, we can close the launching process
$this->_closeAgentLaunchProcess();
// Terminate processes if something went wrong
register_shutdown_function(array($this, '__destruct'));
}
// "Register" GPGConf existence for _closeIdleAgents()
if (version_compare($version, '2.1.0', 'ge')) {
if ($this->_gpgconf === null) {
$this->_gpgconf = $this->_getGPGConf();
}
} else {
$this->_gpgconf = false;
}
$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';
}
// Since 2.1.13 we can use "loopback mode" instead of gpg-agent
if (version_compare($version, '2.1.13', 'ge')) {
$defaultArguments[] = '--pinentry-mode loopback';
}
if (!$this->_strict) {
$defaultArguments[] = '--ignore-time-conflict';
$defaultArguments[] = '--ignore-valid-from';
}
if (!empty($this->_digest_algo)) {
$defaultArguments[] = '--digest-algo ' . escapeshellarg($this->_digest_algo);
$defaultArguments[] = '--s2k-digest-algo ' . escapeshellarg($this->_digest_algo);
}
if (!empty($this->_cipher_algo)) {
$defaultArguments[] = '--cipher-algo ' . escapeshellarg($this->_cipher_algo);
$defaultArguments[] = '--s2k-cipher-algo ' . escapeshellarg($this->_cipher_algo);
}
if (!empty($this->_compress_algo)) {
$defaultArguments[] = '--compress-algo ' . escapeshellarg($this->_compress_algo);
}
$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);
stream_set_write_buffer($pipe, self::CHUNK_SIZE);
stream_set_chunk_size($pipe, self::CHUNK_SIZE);
stream_set_read_buffer($pipe, self::CHUNK_SIZE);
}
$this->_openPipes = $this->_pipes;
}
/**
* Closes 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);
}
$status = proc_get_status($this->_process);
$exitCode = proc_close($this->_process);
// proc_close() can return -1 in some cases,
// get the real exit code from the process status
if ($exitCode < 0 && $status && !$status['running']) {
$exitCode = $status['exitcode'];
}
if ($exitCode > 0) {
$this->_debug(
'=> subprocess returned an unexpected exit code: ' .
$exitCode
);
}
$this->_process = null;
$this->_pipes = array();
// close file handles before throwing an exception
if (is_resource($this->_input)) {
fclose($this->_input);
}
if (is_resource($this->_output)) {
fclose($this->_output);
}
$this->_processHandler->throwException($exitCode);
}
$this->_closeAgentLaunchProcess();
if ($this->_agentInfo !== null) {
$parts = explode(':', $this->_agentInfo, 3);
if (!empty($parts[1])) {
$this->_debug('STOPPING GPG-AGENT DAEMON');
$process = new Crypt_GPG_ProcessControl($parts[1]);
// terminate agent daemon
$process->terminate();
while ($process->isRunning()) {
usleep(10000); // 10 ms
$process->terminate();
}
$this->_debug('GPG-AGENT DAEMON STOPPED');
}
$this->_agentInfo = null;
}
}
/**
* Closes a the internal GPG-AGENT subprocess
*
* Closes the internal GPG-AGENT subprocess. Sets the private class property
* {@link Crypt_GPG_Engine::$_agentProcess} to null.
*
* @return void
*
* @see Crypt_GPG_Engine::_openSubprocess()
* @see Crypt_GPG_Engine::$_agentProcess
*/
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');
}
}
/**
* 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]);
}
}
/**
* Forces automatically started gpg-agent process to cleanup and exit
* within a minute.
*
* This is needed in GnuPG 2.1 where agents are started
* automatically by gpg process, not our code.
*
* @return void
*/
private function _closeIdleAgents()
{
if ($this->_gpgconf) {
// before 2.1.13 --homedir wasn't supported, use env variable
$env = array('GNUPGHOME' => $this->_homedir);
$cmd = $this->_gpgconf . ' --kill gpg-agent';
if ($process = proc_open($cmd, array(), $pipes, null, $env)) {
proc_close($process);
}
}
}
/**
* 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()
{
if ($binary = $this->_findBinary('gpg')) {
return $binary;
}
return $this->_findBinary('gpg2');
}
/**
* Gets the name of the GPG-AGENT binary for the current operating system
*
* @return string the name of the GPG-AGENT binary for the current operating
* system. If no suitable binary could be found, an empty
* string is returned.
*/
private function _getAgent()
{
return $this->_findBinary('gpg-agent');
}
/**
* Gets the name of the GPGCONF binary for the current operating system
*
* @return string the name of the GPGCONF binary for the current operating
* system. If no suitable binary could be found, an empty
* string is returned.
*/
private function _getGPGConf()
{
return $this->_findBinary('gpgconf');
}
/**
* Gets the location of a binary for the current operating system
*
* @param string $name Name of a binary program
*
* @return string The location of the binary for the current operating
* system. If no suitable binary could be found, an empty
* string is returned.
*/
private function _findBinary($name)
{
$binary = '';
if ($this->_isDarwin) {
$locations = array(
'/opt/local/bin/', // MacPorts
'/usr/local/bin/', // Mac GPG
'/sw/bin/', // Fink
'/usr/bin/'
);
} else {
$locations = array(
'/usr/bin/',
'/usr/local/bin/',
'/run/current-system/sw/bin/' // NixOS
);
}
foreach ($locations as $location) {
if (is_executable($location . $name)) {
$binary = $location . $name;
break;
}
}
return $binary;
}
/**
* Gets the location of the PinEntry script
*
* @return string the location of the PinEntry script.
*/
private function _getPinEntry()
{
// Find PinEntry program depending on the way how the package is installed
$ds = DIRECTORY_SEPARATOR;
$root = __DIR__ . $ds . '..' . $ds . '..' . $ds;
$paths = array(
'@bin-dir@', // PEAR
$root . 'scripts', // Git
$root . 'bin', // Composer
);
foreach ($paths as $path) {
if (file_exists($path . $ds . 'crypt-gpg-pinentry')) {
return $path . $ds . 'crypt-gpg-pinentry';
}
}
}
/**
* 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 (is_callable($this->_debug)) {
call_user_func($this->_debug, $text);
} elseif (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.6.7/Crypt/GPG/Exceptions.php 0000664 0001750 0001750 00000032337 14203233501 016270 0 ustar alec alec
*
* @category Encryption
* @package Crypt_GPG
* @author Nathan Fredrickson
* @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
*/
/**
* PEAR Exception handler and base class
*/
require_once 'PEAR/Exception.php';
/**
* 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
{
}
/**
* 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
{
/**
* The name of the file that caused this exception
*
* @var string
*/
private $_filename = '';
/**
* 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);
}
/**
* 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;
}
}
/**
* 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
{
/**
* The command used to try to open the subprocess
*
* @var string
*/
private $_command = '';
/**
* 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);
}
/**
* 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;
}
}
/**
* 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
{
/**
* The attempted operation
*
* @var string
*/
private $_operation = '';
/**
* 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);
}
/**
* Returns the contents of the internal _operation property
*
* @return string the attempted operation.
*
* @see Crypt_GPG_InvalidOperationException::$_operation
*/
public function getOperation()
{
return $this->_operation;
}
}
/**
* 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
{
/**
* The key identifier that was searched for
*
* @var string
*/
private $_keyId = '';
/**
* 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);
}
/**
* 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;
}
}
/**
* 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
{
}
/**
* 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
{
/**
* 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();
/**
* Creates a new Crypt_GPG_BadPassphraseException
*
* @param string $message an error message.
* @param integer $code a user defined error code.
* @param array $badPassphrases an array containing user ids of keys
* for which the passphrase is incorrect.
* @param array $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 = (array) $badPassphrases;
$this->_missingPassphrases = (array) $missingPassphrases;
parent::__construct($message, $code);
}
/**
* 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;
}
/**
* 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;
}
}
/**
* 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
{
/**
* The key identifier the deletion attempt was made upon
*
* @var string
*/
private $_keyId = '';
/**
* 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);
}
/**
* 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;
}
}
/**
* 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
{
}
/**
* 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
{
/**
* The key algorithm
*
* @var integer
*/
private $_algorithm = 0;
/**
* The key size
*
* @var integer
*/
private $_size = 0;
/**
* The key usage
*
* @var integer
*/
private $_usage = 0;
/**
* 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;
}
/**
* Gets the key algorithm
*
* @return integer the key algorithm.
*/
public function getAlgorithm()
{
return $this->_algorithm;
}
/**
* Gets the key size
*
* @return integer the key size.
*/
public function getSize()
{
return $this->_size;
}
/**
* Gets the key usage
*
* @return integer the key usage.
*/
public function getUsage()
{
return $this->_usage;
}
}
Crypt_GPG-1.6.7/Crypt/GPG/Key.php 0000664 0001750 0001750 00000012107 14203233501 014670 0 ustar alec alec
*
* @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
*/
/**
* Sub-key class definition
*/
require_once 'Crypt/GPG/SubKey.php';
/**
* User id class definition
*/
require_once 'Crypt/GPG/UserId.php';
/**
* 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
{
/**
* 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();
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* String representation of the key
*
* @return string The key ID.
*/
public function __toString()
{
foreach ($this->_subKeys as $subKey) {
if ($id = $subKey->getId()) {
return $id;
}
}
return '';
}
}
Crypt_GPG-1.6.7/Crypt/GPG/KeyGenerator.php 0000664 0001750 0001750 00000051501 14203233501 016540 0 ustar alec alec
*
* @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/
*/
/**
* Base class for GPG methods
*/
require_once 'Crypt/GPGAbstract.php';
/**
* 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
{
/**
* 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;
/**
* Creates a new GnuPG key generator
*
* @param array $options An array of options used to create the object.
* All options are optional and are represented as key-value
* pairs. See Crypt_GPGAbstract::__construct() for more info.
*
* @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
* could be found.
*/
public function __construct(array $options = array())
{
parent::__construct($options);
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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),
'Handle' => $handle,
);
if ($this->expirationDate != 0) {
// GnuPG only accepts granularity of days
$expirationDate = date('Y-m-d', $this->expirationDate);
$keyParams['Expire-Date'] = $expirationDate;
}
if (strlen($this->passphrase)) {
$keyParams['Passphrase'] = $this->passphrase;
}
$name = $userId->getName();
$email = $userId->getEmail();
$comment = $userId->getComment();
if (strlen($name) > 0) {
$keyParams['Name-Real'] = $name;
}
if (strlen($email) > 0) {
$keyParams['Name-Email'] = $email;
}
if (strlen($comment) > 0) {
$keyParams['Name-Comment'] = $comment;
}
$keyParamsFormatted = array();
foreach ($keyParams as $name => $value) {
$keyParamsFormatted[] = $name . ': ' . $value;
}
// This is required in GnuPG 2.1
if (!strlen($this->passphrase)) {
$keyParamsFormatted[] = '%no-protection';
}
$input = implode("\n", $keyParamsFormatted) . "\n%commit\n";
$this->engine->reset();
$this->engine->setProcessData('Handle', $handle);
$this->engine->setInput($input);
$this->engine->setOutput($output);
$this->engine->setOperation('--gen-key', array('--batch'));
try {
$this->engine->run();
} catch (Crypt_GPG_InvalidKeyParamsException $e) {
switch ($this->engine->getProcessData('LineNumber')) {
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 $e;
}
}
$fingerprint = $this->engine->getProcessData('KeyCreated');
$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];
}
/**
* 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);
}
/**
* 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.6.7/Crypt/GPG/PinEntry.php 0000664 0001750 0001750 00000053477 14203233501 015727 0 ustar alec alec
*
* @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
*/
/**
* CLI user-interface and parser.
*/
require_once 'Console/CommandLine.php';
/**
* 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.
*
* The 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
{
/**
* 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;
/**
* 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();
/**
* 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;
/**
* 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);
}
}
/**
* 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;
}
/**
* 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;
}
/**
* 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()
{
// Find PinEntry config depending on the way how the package is installed
$ds = DIRECTORY_SEPARATOR;
$root = __DIR__ . $ds . '..' . $ds . '..' . $ds;
$paths = array(
'@data-dir@' . $ds . '@package-name@' . $ds . 'data', // PEAR
$root . 'data', // Git
$root . 'data' . $ds . 'Crypt_GPG' . $ds . 'data', // Composer
);
foreach ($paths as $path) {
if (file_exists($path . $ds . 'pinentry-cli.xml')) {
return $path . $ds . 'pinentry-cli.xml';
}
}
}
/**
* 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());
}
/**
* 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;
}
/**
* 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;
}
/**
* 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 '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();
default:
return $this->sendNotImplementedOK();
}
}
/**
* 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;
}
/**
* 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;
}
/**
* 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());
}
/**
* 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];
if ($this->currentPin === null || $this->currentPin['keyId'] !== $keyId) {
$this->currentPin = array(
'userId' => $userId,
'keyId' => $keyId
);
$this->log(
'-- looking for PIN for ' . $keyId . PHP_EOL,
self::VERBOSITY_ALL
);
}
}
return $this->send($this->getOK());
}
/**
* Tells the assuan server to confirm the operation
*
* @return Crypt_GPG_PinEntry the current object, for fluent interface.
*/
protected function sendConfirm()
{
return $this->send($this->getOK());
}
/**
* 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');
}
/**
* 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");
}
/**
* 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 $_keyId => $pin) {
// Warning: GnuPG 2.1 asks 3 times for passphrase if it is invalid
$keyId = $this->currentPin['keyId'];
$_keyIdLength = mb_strlen($_keyId, '8bit');
// Get last X characters of key identifier to compare
// Most GnuPG versions use 8 characters, but recent ones can use 16,
// We support 8 for backward compatibility
if ($keyIdLength < $_keyIdLength) {
$_keyId = mb_substr($_keyId, -$keyIdLength, $keyIdLength, '8bit');
} else if ($keyIdLength > $_keyIdLength) {
$keyId = mb_substr($keyId, -$_keyIdLength, $_keyIdLength, '8bit');
}
if ($_keyId === $keyId) {
$foundPin = $pin;
break;
}
}
}
return $this
->send($this->getData($foundPin))
->send($this->getOK());
}
/**
* 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;
}
/**
* 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());
}
/**
* 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;
}
/**
* Resets this pinentry and sends an OK response
*
* @return Crypt_GPG_PinEntry the current object, for fluent interface.
*/
protected function sendReset()
{
$this->currentPin = null;
return $this->send($this->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";
}
/**
* 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;
}
/**
* 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, '#');
}
/**
* 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);
}
/**
* 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.6.7/Crypt/GPG/ProcessControl.php 0000664 0001750 0001750 00000007667 14203233501 017136 0 ustar alec alec
*
* @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
*/
/**
* 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
{
/**
* The PID (process identifier) being monitored
*
* @var integer
*/
protected $pid;
/**
* 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;
}
/**
* Gets the PID (process identifier) being controlled
*
* @return integer the PID being controlled.
*/
public function getPid()
{
return $this->pid;
}
/**
* Checks if the process is running
*
* If the posix extension is available, posix_getpgid()
* is used. Otherwise ps is used 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 (function_exists('posix_getpgid')) {
$running = false !== posix_getpgid($this->pid);
} elseif (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;
}
/**
* 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.6.7/Crypt/GPG/ProcessHandler.php 0000664 0001750 0001750 00000073462 14203233501 017067 0 ustar alec alec
*
* @category Encryption
* @package Crypt_GPG
* @author Nathan Fredrickson
* @author Michael Gauthier
* @author Aleksander Machniak
* @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/
*/
/**
* GPG exception classes.
*/
require_once 'Crypt/GPG/Exceptions.php';
/**
* Signature object class definition
*/
require_once 'Crypt/GPG/Signature.php';
/**
* Status/Error handler for GPG process pipes.
*
* This class is used internally by Crypt_GPG_Engine and does not need to be used
* directly. See the {@link Crypt_GPG} class for end-user API.
*
* @category Encryption
* @package Crypt_GPG
* @author Nathan Fredrickson
* @author Michael Gauthier
* @author Aleksander Machniak
* @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_ProcessHandler
{
/**
* Engine used to control the GPG subprocess
*
* @var Crypt_GPG_Engine
*/
protected $engine;
/**
* The error code of the current operation
*
* @var integer
*/
protected $errorCode = Crypt_GPG::ERROR_NONE;
/**
* 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
*/
protected $needPassphrase = 0;
/**
* Some data collected while processing the operation
* or set for the operation
*
* @var array
* @see self::setData()
* @see self::getData()
*/
protected $data = array();
/**
* The name of the current operation
*
* @var string
* @see self::setOperation()
*/
protected $operation = null;
/**
* The value of the argument of current operation
*
* @var string
* @see self::setOperation()
*/
protected $operationArg = null;
/**
* Creates a new instance
*
* @param Crypt_GPG_Engine $engine Engine object
*/
public function __construct($engine)
{
$this->engine = $engine;
}
/**
* Sets the operation that is being performed by the engine.
*
* @param string $operation The GPG operation to perform.
*
* @return void
*/
public function setOperation($operation)
{
$op = null;
$opArg = null;
// Regexp matching all GPG "operational" arguments
$regexp = '/--('
. 'version|import|list-public-keys|list-secret-keys'
. '|list-keys|delete-key|delete-secret-key|encrypt|sign|clearsign'
. '|detach-sign|decrypt|verify|export-secret-keys|export|gen-key'
. ')/';
if (strpos($operation, ' ') === false) {
$op = trim($operation, '- ');
} else if (preg_match($regexp, $operation, $matches, PREG_OFFSET_CAPTURE)) {
$op = trim($matches[0][0], '-');
$op_len = $matches[0][1] + mb_strlen($op, '8bit') + 3;
$command = mb_substr($operation, $op_len, null, '8bit');
// we really need the argument if it is a key ID/fingerprint or email
// address se we can use simplified regexp to "revert escapeshellarg()"
if (preg_match('/^[\'"]([a-zA-Z0-9:@._-]+)[\'"]/', $command, $matches)) {
$opArg = $matches[1];
}
}
$this->operation = $op;
$this->operationArg = $opArg;
$this->data['Warnings'] = array();
}
/**
* Handles error values in the status output from GPG
*
* This method is responsible for setting the
* {@link self::$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
*/
public function handleStatus($line)
{
$tokens = explode(' ', $line);
switch ($tokens[0]) {
case 'NODATA':
$this->errorCode = Crypt_GPG::ERROR_NO_DATA;
break;
case 'DECRYPTION_OKAY':
// If the message is encrypted, this is the all-clear signal.
$this->data['DecryptionOkay'] = true;
$this->errorCode = Crypt_GPG::ERROR_NONE;
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_OK':
$this->data['Import']['fingerprint'] = $tokens[2];
if (empty($this->data['Import']['fingerprints'])) {
$this->data['Import']['fingerprints'] = array($tokens[2]);
} else if (!in_array($tokens[2], $this->data['Import']['fingerprints'])) {
$this->data['Import']['fingerprints'][] = $tokens[2];
}
break;
case 'IMPORT_RES':
$this->data['Import']['public_imported'] = intval($tokens[3]);
$this->data['Import']['public_unchanged'] = intval($tokens[5]);
$this->data['Import']['private_imported'] = intval($tokens[11]);
$this->data['Import']['private_unchanged'] = intval($tokens[12]);
break;
case 'NO_PUBKEY':
case 'NO_SECKEY':
$this->data['ErrorKeyId'] = $tokens[1];
if ($this->errorCode != Crypt_GPG::ERROR_MISSING_PASSPHRASE
&& $this->errorCode != Crypt_GPG::ERROR_BAD_PASSPHRASE
&& !(
$this->operation == 'decrypt'
&& $tokens[0] == 'NO_PUBKEY'
&& !empty($this->data['IgnoreVerifyErrors'])
)
) {
$this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
}
// note: this message is also received if there are multiple
// recipients and a previous key had a correct passphrase.
$this->data['MissingKeys'][$tokens[1]] = $tokens[1];
// @FIXME: remove missing passphrase registered in ENC_TO handler
// This is for GnuPG 2.1
unset($this->data['MissingPassphrases'][$tokens[1]]);
break;
case 'KEY_CONSIDERED':
// In GnuPG 2.1.x exporting/importing a secret key requires passphrase
// However, no NEED_PASSPRASE is returned, https://bugs.gnupg.org/gnupg/issue2667
// So, handling KEY_CONSIDERED and GET_HIDDEN is needed.
if (!array_key_exists('KeyConsidered', $this->data)) {
$this->data['KeyConsidered'] = $tokens[1];
}
break;
case 'USERID_HINT':
// remember the user id for pretty exception messages
// GnuPG 2.1.15 gives me: "USERID_HINT 0000000000000000 [?]"
$keyId = $tokens[1];
if (strcspn($keyId, '0')) {
$username = implode(' ', array_splice($tokens, 2));
$this->data['BadPassphrases'][$keyId] = $username;
}
break;
case 'ENC_TO':
// Now we know the message is encrypted. Set flag to check if
// decryption succeeded.
$this->data['DecryptionOkay'] = false;
// this is the new key message
$this->data['CurrentSubKeyId'] = $keyId = $tokens[1];
// For some reason in GnuPG 2.1.11 I get only ENC_TO and no
// NEED_PASSPHRASE/MISSING_PASSPHRASE/USERID_HINT
// This is not needed for GnuPG 2.1.15
if (!empty($_ENV['PINENTRY_USER_DATA'])) {
$passphrases = json_decode($_ENV['PINENTRY_USER_DATA'], true);
} else {
$passphrases = array();
}
// @TODO: Get user name/email
$this->data['BadPassphrases'][$keyId] = $keyId;
if (empty($passphrases) || empty($passphrases[$keyId])) {
$this->data['MissingPassphrases'][$keyId] = $keyId;
}
break;
case 'GOOD_PASSPHRASE':
// if we got a good passphrase, remove the key from the list of
// bad passphrases.
if (isset($this->data['CurrentSubKeyId'])) {
unset($this->data['BadPassphrases'][$this->data['CurrentSubKeyId']]);
unset($this->data['MissingPassphrases'][$this->data['CurrentSubKeyId']]);
}
$this->needPassphrase--;
break;
case 'BAD_PASSPHRASE':
$this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
break;
case 'MISSING_PASSPHRASE':
if (isset($this->data['CurrentSubKeyId'])) {
$this->data['MissingPassphrases'][$this->data['CurrentSubKeyId']]
= $this->data['CurrentSubKeyId'];
}
$this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
break;
case 'GET_HIDDEN':
if ($tokens[1] == 'passphrase.enter' && isset($this->data['KeyConsidered'])) {
$tokens[1] = $this->data['KeyConsidered'];
} else {
break;
}
// no break
case 'NEED_PASSPHRASE':
$passphrase = $this->getPin($tokens[1]);
$this->engine->sendCommand($passphrase);
if ($passphrase === '') {
$this->needPassphrase++;
}
break;
case 'SIG_CREATED':
$this->data['SigCreated'] = $line;
break;
case 'SIG_ID':
// note: signature id comes before new signature line and may not
// exist for some signature types
$this->data['SignatureId'] = $tokens[1];
break;
case 'EXPSIG':
case 'EXPKEYSIG':
case 'REVKEYSIG':
case 'BADSIG':
case 'ERRSIG':
$this->errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE;
// no break
case 'GOODSIG':
$signature = new Crypt_GPG_Signature();
// if there was a signature id, set it on the new signature
if (!empty($this->data['SignatureId'])) {
$signature->setId($this->data['SignatureId']);
$this->data['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 (mb_strlen($tokens[1], '8bit') > 16) {
$signature->setKeyFingerprint($tokens[1]);
$signature->setKeyId(mb_substr($tokens[1], -16, null, '8bit'));
} else {
$signature->setKeyId($tokens[1]);
}
// get user id string
if ($tokens[0] != 'ERRSIG') {
$string = implode(' ', array_splice($tokens, 2));
$string = rawurldecode($string);
$signature->setUserId(Crypt_GPG_UserId::parse($string));
}
$this->data['Signatures'][] = $signature;
break;
case 'VALIDSIG':
if (empty($this->data['Signatures'])) {
break;
}
$signature = end($this->data['Signatures']);
$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 'KEY_CREATED':
if (isset($this->data['Handle']) && $tokens[3] == $this->data['Handle']) {
$this->data['KeyCreated'] = $tokens[2];
}
break;
case 'KEY_NOT_CREATED':
if (isset($this->data['Handle']) && $tokens[1] == $this->data['Handle']) {
$this->errorCode = Crypt_GPG::ERROR_KEY_NOT_CREATED;
}
break;
case 'PROGRESS':
// todo: at some point, support reporting status async
break;
// GnuPG 2.1 uses FAILURE and ERROR responses
case 'FAILURE':
case 'ERROR':
$errnum = (int) $tokens[2];
$source = $errnum >> 24;
$errcode = $errnum & 0xFFFFFF;
switch ($errcode) {
case 11: // bad passphrase
case 87: // bad PIN
$this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
break;
case 177: // no passphrase
case 178: // no PIN
$this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
break;
case 58:
$this->errorCode = Crypt_GPG::ERROR_NO_DATA;
break;
}
break;
}
}
/**
* 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
*/
public function handleError($line)
{
if (stripos($line, 'gpg: WARNING: ') !== false) {
$this->data['Warnings'][] = substr($line, 14);
}
if ($this->errorCode !== Crypt_GPG::ERROR_NONE) {
return;
}
$pattern = '/no valid OpenPGP data found/';
if (preg_match($pattern, $line) === 1) {
$this->errorCode = Crypt_GPG::ERROR_NO_DATA;
return;
}
$pattern = '/No secret key|secret key not available/';
if (preg_match($pattern, $line) === 1) {
$this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
return;
}
$pattern = '/No public key|public key not found/';
if (preg_match($pattern, $line) === 1) {
if ($this->operation == 'decrypt' && !empty($this->data['IgnoreVerifyErrors'])) {
return;
}
$this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
return;
}
$pattern = '/can\'t (?:access|open) `(.*?)\'/';
if (preg_match($pattern, $line, $matches) === 1) {
$this->data['ErrorFilename'] = $matches[1];
$this->errorCode = Crypt_GPG::ERROR_FILE_PERMISSIONS;
return;
}
// GnuPG 2.1: It should return MISSING_PASSPHRASE, but it does not
// we have to detect it this way. This happens e.g. on private key import
$pattern = '/key ([0-9A-F]+).* (Bad|No) passphrase/';
if (preg_match($pattern, $line, $matches) === 1) {
$keyId = $matches[1];
// @TODO: Get user name/email
if (empty($this->data['BadPassphrases'][$keyId])) {
$this->data['BadPassphrases'][$keyId] = $keyId;
}
if ($matches[2] == 'Bad') {
$this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
} else {
$this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
if (empty($this->data['MissingPassphrases'][$keyId])) {
$this->data['MissingPassphrases'][$keyId] = $keyId;
}
}
return;
}
if ($this->operation == 'gen-key') {
$pattern = '/:([0-9]+): invalid algorithm$/';
if (preg_match($pattern, $line, $matches) === 1) {
$this->errorCode = Crypt_GPG::ERROR_BAD_KEY_PARAMS;
$this->data['LineNumber'] = intval($matches[1]);
}
}
}
/**
* On error throws exception
*
* @param int $exitcode GPG process exit code
*
* @return void
* @throws Crypt_GPG_Exception
*/
public function throwException($exitcode = 0)
{
if ($exitcode > 0 && $this->errorCode === Crypt_GPG::ERROR_NONE) {
$this->errorCode = $this->setErrorCode($exitcode);
}
if ($this->errorCode === Crypt_GPG::ERROR_NONE) {
return;
}
$code = $this->errorCode;
$note = "Please use the 'debug' option when creating the Crypt_GPG " .
"object, and file a bug report at " . Crypt_GPG::BUG_URI;
switch ($this->operation) {
case 'version':
throw new Crypt_GPG_Exception(
'Unknown error getting GnuPG version information. ' . $note,
$code
);
case 'list-secret-keys':
case 'list-public-keys':
case 'list-keys':
switch ($code) {
case Crypt_GPG::ERROR_KEY_NOT_FOUND:
// ignore not found key errors
break;
case Crypt_GPG::ERROR_FILE_PERMISSIONS:
if (!empty($this->data['ErrorFilename'])) {
throw new Crypt_GPG_FileException(
sprintf(
'Error reading GnuPG data file \'%s\'. Check to make ' .
'sure it is readable by the current user.',
$this->data['ErrorFilename']
),
$code,
$this->data['ErrorFilename']
);
}
throw new Crypt_GPG_FileException(
'Error reading GnuPG data file. Check to make sure that ' .
'GnuPG data files are readable by the current user.',
$code
);
default:
throw new Crypt_GPG_Exception(
'Unknown error getting keys. ' . $note, $code
);
}
break;
case 'delete-key':
case 'delete-secret-key':
switch ($code) {
case Crypt_GPG::ERROR_KEY_NOT_FOUND:
throw new Crypt_GPG_KeyNotFoundException(
'Key not found: ' . $this->operationArg,
$code,
$this->operationArg
);
case Crypt_GPG::ERROR_DELETE_PRIVATE_KEY:
throw new Crypt_GPG_DeletePrivateKeyException(
'Private key must be deleted before public key can be ' .
'deleted.',
$code,
$this->operationArg
);
default:
throw new Crypt_GPG_Exception(
'Unknown error deleting key. ' . $note, $code
);
}
break;
case 'import':
switch ($code) {
case Crypt_GPG::ERROR_NO_DATA:
throw new Crypt_GPG_NoDataException(
'No valid GPG key data found.', $code
);
case Crypt_GPG::ERROR_BAD_PASSPHRASE:
case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
throw $this->badPassException($code, 'Cannot import private key.');
default:
throw new Crypt_GPG_Exception(
'Unknown error importing GPG key. ' . $note, $code
);
}
break;
case 'export':
case 'export-secret-keys':
switch ($code) {
case Crypt_GPG::ERROR_BAD_PASSPHRASE:
case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
throw $this->badPassException($code, 'Cannot export private key.');
default:
throw new Crypt_GPG_Exception(
'Unknown error exporting a key. ' . $note, $code
);
}
break;
case 'encrypt':
case 'sign':
case 'clearsign':
case 'detach-sign':
switch ($code) {
case Crypt_GPG::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,
!empty($this->data['ErrorKeyId']) ? $this->data['ErrorKeyId'] : null
);
case Crypt_GPG::ERROR_BAD_PASSPHRASE:
throw new Crypt_GPG_BadPassphraseException(
'Cannot sign data. Incorrect passphrase provided.', $code
);
case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
throw new Crypt_GPG_BadPassphraseException(
'Cannot sign data. No passphrase provided.', $code
);
default:
throw new Crypt_GPG_Exception(
"Unknown error {$this->operation}ing data. $note", $code
);
}
break;
case 'verify':
switch ($code) {
case Crypt_GPG::ERROR_BAD_SIGNATURE:
// ignore bad signature errors
break;
case Crypt_GPG::ERROR_NO_DATA:
throw new Crypt_GPG_NoDataException(
'No valid signature data found.', $code
);
case Crypt_GPG::ERROR_KEY_NOT_FOUND:
throw new Crypt_GPG_KeyNotFoundException(
'Public key required for data verification not in keyring.',
$code,
!empty($this->data['ErrorKeyId']) ? $this->data['ErrorKeyId'] : null
);
default:
throw new Crypt_GPG_Exception(
'Unknown error validating signature details. ' . $note,
$code
);
}
break;
case 'decrypt':
switch ($code) {
case Crypt_GPG::ERROR_BAD_SIGNATURE:
// ignore bad signature errors
break;
case Crypt_GPG::ERROR_KEY_NOT_FOUND:
if (!empty($this->data['MissingKeys'])) {
$keyId = reset($this->data['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:
case Crypt_GPG::ERROR_MISSING_PASSPHRASE:
throw $this->badPassException($code, 'Cannot decrypt data.');
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
);
}
break;
case 'gen-key':
switch ($code) {
case Crypt_GPG::ERROR_BAD_KEY_PARAMS:
throw new Crypt_GPG_InvalidKeyParamsException(
'Invalid key algorithm specified.', $code
);
default:
throw new Crypt_GPG_Exception(
'Unknown error generating key-pair. ' . $note, $code
);
}
}
}
/**
* Check exit code of the GPG operation.
*
* @param int $exitcode GPG process exit code
*
* @return int Internal error code
*/
protected function setErrorCode($exitcode)
{
if ($this->needPassphrase > 0) {
return Crypt_GPG::ERROR_MISSING_PASSPHRASE;
}
if ($this->operation == 'import') {
return Crypt_GPG::ERROR_NONE;
}
if ($this->operation == 'decrypt' && !empty($this->data['DecryptionOkay'])) {
if (!empty($this->data['IgnoreVerifyErrors'])) {
return Crypt_GPG::ERROR_NONE;
}
if (!empty($this->data['MissingKeys'])) {
return Crypt_GPG::ERROR_KEY_NOT_FOUND;
}
}
return Crypt_GPG::ERROR_UNKNOWN;
}
/**
* Get data from the last process execution.
*
* @param string $name Data element name:
* - SigCreated: The last SIG_CREATED status.
* - KeyConsidered: The last KEY_CONSIDERED status identifier.
* - KeyCreated: The KEY_CREATED status (for specified Handle).
* - Signatures: Signatures data from verification process.
* - LineNumber: Number of the gen-key error line.
* - Import: Result of IMPORT_OK/IMPORT_RES
* - Warnings: An array of all collected GnuPG warnings
*
* @return mixed
*/
public function getData($name)
{
return isset($this->data[$name]) ? $this->data[$name] : null;
}
/**
* Set data for the process execution.
*
* @param string $name Data element name:
* - Handle: The unique key handle used by this handler
* The key handle is used to track GPG status output
* for a particular key on --gen-key command before
* the key has its own identifier.
* - IgnoreVerifyErrors: Do not throw exceptions
* when signature verification failes because
* of a missing public key.
* @param mixed $value Data element value
*
* @return void
*/
public function setData($name, $value)
{
switch ($name) {
case 'Handle':
$this->data[$name] = strval($value);
break;
case 'IgnoreVerifyErrors':
$this->data[$name] = (bool) $value;
break;
}
}
/**
* Create Crypt_GPG_BadPassphraseException from operation data.
*
* @param int $code Error code
* @param string $message Error message
*
* @return Crypt_GPG_BadPassphraseException
*/
protected function badPassException($code, $message)
{
$badPassphrases = array_diff_key(
isset($this->data['BadPassphrases']) ? $this->data['BadPassphrases'] : array(),
isset($this->data['MissingPassphrases']) ? $this->data['MissingPassphrases'] : array()
);
$missingPassphrases = array_intersect_key(
isset($this->data['BadPassphrases']) ? $this->data['BadPassphrases'] : array(),
isset($this->data['MissingPassphrases']) ? $this->data['MissingPassphrases'] : array()
);
if (count($badPassphrases) > 0) {
$message .= ' Incorrect passphrase provided for keys: "' .
implode('", "', $badPassphrases) . '".';
}
if (count($missingPassphrases) > 0) {
$message .= ' No passphrase provided for keys: "' .
implode('", "', $missingPassphrases) . '".';
}
return new Crypt_GPG_BadPassphraseException(
$message,
$code,
$badPassphrases,
$missingPassphrases
);
}
/**
* Get registered passphrase for specified key.
*
* @param string $key Key identifier
*
* @return string Passphrase
*/
protected function getPin($key)
{
$passphrase = '';
$keyIdLength = mb_strlen($key, '8bit');
if ($keyIdLength && !empty($_ENV['PINENTRY_USER_DATA'])) {
$passphrases = json_decode($_ENV['PINENTRY_USER_DATA'], true);
foreach ($passphrases as $_keyId => $pass) {
$keyId = $key;
$_keyIdLength = mb_strlen($_keyId, '8bit');
// Get last X characters of key identifier to compare
if ($keyIdLength < $_keyIdLength) {
$_keyId = mb_substr($_keyId, -$keyIdLength, null, '8bit');
} else if ($keyIdLength > $_keyIdLength) {
$keyId = mb_substr($keyId, -$_keyIdLength, null, '8bit');
}
if ($_keyId === $keyId) {
$passphrase = $pass;
break;
}
}
}
return $passphrase;
}
}
Crypt_GPG-1.6.7/Crypt/GPG/Signature.php 0000664 0001750 0001750 00000026350 14203233501 016106 0 ustar alec alec
*
* @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
*/
/**
* User id class definition
*/
require_once 'Crypt/GPG/UserId.php';
/**
* 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
{
/**
* 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;
/**
* 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|null $signature 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);
}
}
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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.6.7/Crypt/GPG/SignatureCreationInfo.php 0000664 0001750 0001750 00000012066 14203233501 020406 0 ustar alec alec
* @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/
*/
/**
* 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',
8 => 'sha256',
9 => 'sha384',
10 => 'sha512',
11 => 'sha224',
);
/**
* 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.6.7/Crypt/GPG/SubKey.php 0000664 0001750 0001750 00000044412 14203233501 015346 0 ustar alec alec
*
* @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
*/
/**
* 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
{
/**
* 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;
/**
* 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;
/**
* 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 DateTime
*/
private $_creationDate;
/**
* Date this sub-key expires
*
* This is a Unix timestamp. If this sub-key does not expire, this will be
* null.
*
* @var DateTime
*/
private $_expirationDate;
/**
* 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;
/**
* 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|null $key 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']);
}
}
}
/**
* Gets the id of this sub-key
*
* @return string the id of this sub-key.
*/
public function getId()
{
return $this->_id;
}
/**
* 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;
}
/**
* Gets the creation date of this sub-key
*
* This is a Unix timestamp. Warning: On 32-bit systems it returns
* invalid value for dates after 2038-01-19. Use getCreationDateTime().
*
* @return integer the creation date of this sub-key.
*/
public function getCreationDate()
{
return $this->_creationDate ? (int) $this->_creationDate->format('U') : 0;
}
/**
* Gets the creation date-time (UTC) of this sub-key
*
* @return DateTime|null The creation date of this sub-key.
*/
public function getCreationDateTime()
{
return $this->_creationDate ? $this->_creationDate : null;
}
/**
* Gets the date this sub-key expires
*
* This is a Unix timestamp. If this sub-key does not expire, this will be
* zero. Warning: On 32-bit systems it returns invalid value for dates
* after 2038-01-19. Use getExpirationDateTime().
*
* @return integer the date this sub-key expires.
*/
public function getExpirationDate()
{
return $this->_expirationDate ? (int) $this->_expirationDate->format('U') : 0;
}
/**
* Gets the date-time (UTC) this sub-key expires
*
* @return integer the date this sub-key expires.
*/
public function getExpirationDateTime()
{
return $this->_expirationDate ? $this->_expirationDate : null;
}
/**
* Gets the fingerprint of this sub-key
*
* @return string the fingerprint of this sub-key.
*/
public function getFingerprint()
{
return $this->_fingerprint;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* Gets usage flags of this sub-key
*
* @return int Sum of usage flags
*/
public function usage()
{
return $this->_usage;
}
/**
* 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;
}
/**
* 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;
}
/**
* Sets the creation date of this sub-key
*
* The creation date is a Unix timestamp or DateTime object.
*
* @param integer|DateTime $creationDate the creation date of this sub-key.
*
* @return Crypt_GPG_SubKey the current object, for fluent interface.
*/
public function setCreationDate($creationDate)
{
if (empty($creationDate)) {
$this->_creationDate = null;
return $this;
}
if ($creationDate instanceof DateTime) {
$this->_creationDate = $creationDate;
} else {
$tz = new DateTimeZone('UTC');
$this->_creationDate = new DateTime("@$creationDate", $tz);
}
return $this;
}
/**
* 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|DateTime $expirationDate the expiration date of this sub-key.
*
* @return Crypt_GPG_SubKey the current object, for fluent interface.
*/
public function setExpirationDate($expirationDate)
{
if (empty($expirationDate)) {
$this->_expirationDate = null;
return $this;
}
if ($expirationDate instanceof DateTime) {
$this->_expirationDate = $expirationDate;
} else {
$tz = new DateTimeZone('UTC');
$this->_expirationDate = new DateTime("@$expirationDate", $tz);
}
return $this;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* Parses a date string as provided by GPG into a UNIX timestamp
*
* @param string $string the date string.
*
* @return DateTime|null the date corresponding to the provided date string.
*/
private static function _parseDate($string)
{
if (empty($string)) {
return null;
}
// all times are in UTC according to GPG documentation
$timeZone = new DateTimeZone('UTC');
if (strpos($string, 'T') === false) {
// interpret as UNIX timestamp
$string = '@' . $string;
}
return new DateTime($string, $timeZone);
}
}
Crypt_GPG-1.6.7/Crypt/GPG/UserId.php 0000664 0001750 0001750 00000021662 14203233501 015341 0 ustar alec alec
*
* @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
*/
/**
* 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
{
/**
* 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;
/**
* 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|null $userId 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']);
}
}
}
/**
* Gets the name field of this user id
*
* @return string the name field of this user id.
*/
public function getName()
{
return $this->_name;
}
/**
* Gets the comments field of this user id
*
* @return string the comments field of this user id.
*/
public function getComment()
{
return $this->_comment;
}
/**
* Gets the email field of this user id
*
* @return string the email field of this user id.
*/
public function getEmail()
{
return $this->_email;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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 (mb_strlen($this->_name, '8bit') > 0) {
$components[] = $this->_name;
}
if (mb_strlen($this->_comment, '8bit') > 0) {
$components[] = '(' . $this->_comment . ')';
}
if (mb_strlen($this->_email, '8bit') > 0) {
$components[] = '<' . $this->_email. '>';
}
return implode(' ', $components);
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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();
$name = '';
$email = '';
$comment = '';
// get email address from end of string if it exists
$matches = array();
if (preg_match('/^(.*?)<([^>]+)>$/', $string, $matches) === 1) {
$string = trim($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];
}
// there can be an email without a name
if (!$email && preg_match('/^[\S]+@[\S]+$/', $string, $matches) === 1) {
$email = $string;
} else {
$name = $string;
}
$userId->setName($name);
$userId->setComment($comment);
$userId->setEmail($email);
return $userId;
}
}
Crypt_GPG-1.6.7/Crypt/GPG.php 0000664 0001750 0001750 00000222513 14203233501 014144 0 ustar alec alec
* addEncryptKey($mySecretKeyId);
* $encryptedData = $gpg->encrypt($data);
* ?>
*
*
* 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, see
*
*
* @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://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';
/**
* GPG exception classes.
*/
require_once 'Crypt/GPG/Exceptions.php';
/**
* 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
{
/**
* 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;
/**
* 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;
/**
* 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;
/**
* 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();
/**
* Passphrases used on import/export of private keys in GnuPG 2.1
*
* The array is of the form:
*
* array($key_id => $passphrase);
*
*
* @var array
* @see Crypt_GPG::addPassphrase()
* @see Crypt_GPG::clearPassphrases()
*/
protected $passphrases = array();
/**
* 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_BadPassphraseException if a required passphrase is
* incorrect or if a required passphrase is not specified. See
* {@link Crypt_GPG::addPassphrase()}.
*
* @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::addPassphrase()
* @see Crypt_GPG::clearPassphrases()
*/
public function importKey($data)
{
return $this->_importKey($data, false);
}
/**
* 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_BadPassphraseException if a required passphrase is
* incorrect or if a required passphrase is not specified. See
* {@link Crypt_GPG::addPassphrase()}.
*
* @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);
}
/**
* Exports a private key from the keyring
*
* The exported key remains on the keyring. To delete the key, use
* {@link Crypt_GPG::deletePrivateKey()}.
*
* 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 exported.
*
* @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.
* @param boolean $armor optional. If true, ASCII armored data is returned;
* otherwise, binary data is returned. Defaults to
* true.
*
* @return string the private key data.
*
* @throws Crypt_GPG_KeyNotFoundException if a private key with the given
* $keyId is not found.
*
* @throws Crypt_GPG_BadPassphraseException if a required passphrase is
* incorrect or if a required passphrase is not specified. See
* {@link Crypt_GPG::addPassphrase()}.
*
* @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 exportPrivateKey($keyId, $armor = true)
{
return $this->_exportKey($keyId, $armor, true);
}
/**
* 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)
{
return $this->_exportKey($keyId, $armor, false);
}
/**
* 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.
* In GnuPG >= 2.1 this limitation does not exist.
* 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 (when using GnuPG < 2.1).
*
* @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();
}
/**
* 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();
}
/**
* 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);
}
/**
* 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();
$fingerprint = null;
foreach (explode(PHP_EOL, $output) as $line) {
if (mb_substr($line, 0, 3, '8bit') == '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;
}
/**
* Get information about the last signature that was created.
*
* @return Crypt_GPG_SignatureCreationInfo
*/
public function getLastSignatureInfo()
{
return $this->engine->getProcessData('SignatureInfo');
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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.
* @param boolean $ignoreVerifyErrors enables ignoring of signature
* verification errors caused by missing public key
* When enabled Crypt_GPG_KeyNotFoundException
* will not be thrown.
*
* @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 or the public key to verify the signature
* 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, $ignoreVerifyErrors = false)
{
return $this->_decryptAndVerify($encryptedData, false, null, $ignoreVerifyErrors);
}
/**
* 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.
* @param boolean $ignoreVerifyErrors enables ignoring of signature
* verification errors caused by missing public key
* When enabled Crypt_GPG_KeyNotFoundException
* will not be thrown.
*
* @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 or the public key to verify the signature
* 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, $ignoreVerifyErrors = false)
{
return $this->_decryptAndVerify($encryptedFile, true, $decryptedFile, $ignoreVerifyErrors);
}
/**
* 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 int $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);
}
/**
* 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 int $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
);
}
/**
* 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_KeyNotFoundException if the public key needed for
* signature verification is not in the user's keyring.
*
* @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);
}
/**
* 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_KeyNotFoundException if the public key needed for
* signature verification is not in the user's keyring.
*
* @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);
}
/**
* 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()
*
* @sensitive $passphrase
*/
public function addDecryptKey($key, $passphrase = null)
{
$this->_addKey($this->decryptKeys, false, false, $key, $passphrase);
return $this;
}
/**
* 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;
}
/**
* 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::_addKey()
*
* @sensitive $passphrase
*/
public function addSignKey($key, $passphrase = null)
{
$this->_addKey($this->signKeys, false, true, $key, $passphrase);
return $this;
}
/**
* Register a private key passphrase for import/export (GnuPG 2.1)
*
* @param mixed $key The key to use. This must be a key identifier,
* or fingerprint.
* @param string $passphrase The passphrase of the key.
*
* @return Crypt_GPG the current object, for fluent interface.
*
* @see Crypt_GPG::clearPassphrases()
* @see Crypt_GPG::importKey()
* @see Crypt_GPG::exportKey()
*
* @sensitive $passphrase
*/
public function addPassphrase($key, $passphrase)
{
$this->passphrases[$key] = $passphrase;
return $this;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
}
/**
* Clears all private key passphrases
*
* @return Crypt_GPG the current object, for fluent interface.
*
* @see Crypt_GPG::importKey()
* @see Crypt_GPG::exportKey()
* @see Crypt_GPG::addPassphrase()
*/
public function clearPassphrases()
{
$this->passphrases = array();
return $this;
}
/**
* 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;
}
/**
* Get list of GnuPG warnings collected on last operation.
*
* @return array List of warning messages
*/
public function getWarnings()
{
return $this->engine->getProcessData('Warnings');
}
/**
* 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 not found: ' . $key,
self::ERROR_KEY_NOT_FOUND,
$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)
|| (!$encrypt && !$sign)
) {
// 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
);
}
}
/**
* 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_BadPassphraseException if a required passphrase is
* incorrect or if a required passphrase is not specified. See
* {@link Crypt_GPG::addPassphrase()}.
*
* @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();
$arguments = array();
$input = $this->_prepareInput($key, $isFile, false);
$version = $this->engine->getVersion();
if (version_compare($version, '1.0.5', 'ge')
&& version_compare($version, '1.0.7', 'lt')
) {
$arguments[] = '--allow-secret-key-import';
}
if (empty($this->passphrases)) {
$arguments[] = '--batch';
}
$this->engine->reset();
$this->engine->setPins($this->passphrases);
$this->engine->setOperation('--import', $arguments);
$this->engine->setInput($input);
$this->engine->run();
return $this->engine->getProcessData('Import');
}
/**
* Exports a private or 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 key is exported.
*
* @param string $keyId either the full uid of the key, the email
* part of the uid of the key or the key id.
* @param boolean $armor optional. If true, ASCII armored data is returned;
* otherwise, binary data is returned. Defaults to
* true.
* @param boolean $private return private instead of public key
*
* @return string the key data.
*
* @throws Crypt_GPG_KeyNotFoundException if a key with the given
* $keyId is not found.
*
* @throws Crypt_GPG_BadPassphraseException if a required passphrase is
* incorrect or if a required passphrase is not specified. See
* {@link Crypt_GPG::addPassphrase()}.
*
* @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 _exportKey($keyId, $armor = true, $private = false)
{
$fingerprint = $this->getFingerprint($keyId);
if ($fingerprint === null) {
throw new Crypt_GPG_KeyNotFoundException(
'Key not found: ' . $keyId,
self::ERROR_KEY_NOT_FOUND,
$keyId
);
}
$keyData = '';
$operation = $private ? '--export-secret-keys' : '--export';
$operation .= ' -- ' . escapeshellarg($fingerprint);
$arguments = $armor ? array('--armor') : array();
$this->engine->reset();
$this->engine->setPins($this->passphrases);
$this->engine->setOutput($keyData);
$this->engine->setOperation($operation, $arguments);
$this->engine->run();
return $keyData;
}
/**
* 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.'
);
}
$input = $this->_prepareInput($data, $isFile);
$output = $this->_prepareOutput($outputFile, $input);
$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 ($outputFile === null) {
return $output;
}
}
/**
* 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)
{
$input = $this->_prepareInput($data, $isFile, false);
$output = $this->_prepareOutput($outputFile, $input);
$this->engine->reset();
$this->engine->setPins($this->decryptKeys);
$this->engine->setOperation('--decrypt --skip-verify');
$this->engine->setInput($input);
$this->engine->setOutput($output);
$this->engine->run();
if ($outputFile === null) {
return $output;
}
}
/**
* 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 int $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
) {
if (!$this->hasSignKeys()) {
throw new Crypt_GPG_KeyNotFoundException(
'No signing keys specified.'
);
}
$input = $this->_prepareInput($data, $isFile);
$output = $this->_prepareOutput($outputFile, $input);
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']);
}
$this->engine->reset();
$this->engine->setPins($this->signKeys);
$this->engine->setInput($input);
$this->engine->setOutput($output);
$this->engine->setOperation($operation, $arguments);
$this->engine->run();
if ($outputFile === null) {
return $output;
}
}
/**
* 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.'
);
}
$input = $this->_prepareInput($data, $isFile);
$output = $this->_prepareOutput($outputFile, $input);
$arguments = $armor ? array('--armor') : array();
foreach ($this->signKeys as $key) {
$arguments[] = '--local-user ' .
escapeshellarg($key['fingerprint']);
}
foreach ($this->encryptKeys as $key) {
$arguments[] = '--recipient ' . escapeshellarg($key['fingerprint']);
}
$this->engine->reset();
$this->engine->setPins($this->signKeys);
$this->engine->setInput($input);
$this->engine->setOutput($output);
$this->engine->setOperation('--encrypt --sign', $arguments);
$this->engine->run();
if ($outputFile === null) {
return $output;
}
}
/**
* 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_KeyNotFoundException if the public key needed for
* signature verification is not in the user's keyring.
*
* @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');
}
$input = $this->_prepareInput($data, $isFile, false);
$this->engine->reset();
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();
return $this->engine->getProcessData('Signatures');
}
/**
* 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.
* @param boolean $ignoreVerifyErrors enables ignoring of signature verification
* errors caused by missing public key.
* When enabled Crypt_GPG_KeyNotFoundException
* will not be thrown.
*
* @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 if 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, $ignoreVerifyErrors = false)
{
$input = $this->_prepareInput($data, $isFile, false);
$output = $this->_prepareOutput($outputFile, $input);
$this->engine->reset();
$this->engine->setPins($this->decryptKeys);
$this->engine->setInput($input);
$this->engine->setOutput($output);
$this->engine->setOperation('--decrypt');
$this->engine->setProcessData('IgnoreVerifyErrors', $ignoreVerifyErrors);
$this->engine->run();
$return = array(
'data' => null,
'signatures' => $this->engine->getProcessData('Signatures')
);
if ($outputFile === null) {
$return['data'] = $output;
}
return $return;
}
/**
* Prepares command input
*
* @param string $data the input data.
* @param boolean $isFile whether or not the input is a filename.
* @param boolean $allowEmpty whether to check if the input is not empty.
*
* @throws Crypt_GPG_NoDataException if the key data is missing.
* @throws Crypt_GPG_FileException if the file is not readable.
*
* @return string The command input
*/
protected function _prepareInput($data, $isFile = false, $allowEmpty = true)
{
if ($isFile) {
$input = @fopen($data, 'rb');
if ($input === false) {
throw new Crypt_GPG_FileException(
'Could not open input file "' . $data . '"',
0,
$data
);
}
} else {
$input = strval($data);
if (!$allowEmpty && $input === '') {
throw new Crypt_GPG_NoDataException(
'No valid input data found.',
self::ERROR_NO_DATA
);
}
}
return $input;
}
/**
* Prepares command output
*
* @param string $outputFile the name of the file in which the output
* data should be stored. If null, the output
* data is returned as a string.
* @param boolean $input the input resource, in case it would need
* to be released (closed) on exception.
*
* @throws Crypt_GPG_FileException if the file is not writeable.
*
* @return string The command output
*/
protected function _prepareOutput($outputFile, $input = null)
{
if ($outputFile === null) {
$output = '';
} else {
$output = @fopen($outputFile, 'wb');
if ($output === false) {
if (is_resource($input)) {
fclose($input);
}
throw new Crypt_GPG_FileException(
'Could not open output file "' . $outputFile . '"',
0,
$outputFile
);
}
}
return $output;
}
}
Crypt_GPG-1.6.7/Crypt/GPGAbstract.php 0000664 0001750 0001750 00000037476 14203233501 015644 0 ustar alec alec
*
* @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://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';
/**
* 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
{
/**
* 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;
/**
* URI at which package bugs may be reported.
*/
const BUG_URI = 'http://pear.php.net/bugs/report.php?package=Crypt_GPG';
/**
* Engine used to control the GPG subprocess
*
* @var Crypt_GPG_Engine
*
* @see Crypt_GPGAbstract::setEngine()
*/
protected $engine = null;
/**
* 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.
* - 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.
* - string|false gpgconf - the location of the GnuPG conf binary.
* The gpgconf is only used for GnuPG >= 2.1. If not
* specified, the engine attempts to auto-detect
* the location using a list of know default locations.
* When set to FALSE `gpgconf --kill` will not be executed
* via destructor.
* - string digest-algo - Sets the message digest algorithm.
* - string cipher-algo - Sets the symmetric cipher.
* - string compress-algo - Sets the compression algorithm.
* - boolean strict - In strict mode clock problems on subkeys
* and signatures are not ignored (--ignore-time-conflict
* and --ignore-valid-from options).
* - mixed 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.
* - array options - additional per-command options to the GPG
* command. Key of the array is a command (e.g.
* gen-key, import, sign, encrypt, list-keys).
* Value is a string containing command line arguments to be
* added to the related command. For example:
* array('sign' => '--emit-version').
*
* @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
* could be found.
*/
public function __construct(array $options = array())
{
$this->setEngine(new Crypt_GPG_Engine($options));
}
/**
* 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;
}
/**
* Sets per-command additional arguments
*
* @param array $options Additional per-command options for GPG command.
* Note: This will unset options set previously.
* Key of the array is a command (e.g.
* gen-key, import, sign, encrypt, list-keys).
* Value is a string containing command line arguments to be
* added to the related command. For example:
* array('sign' => '--emit-version').
*
* @return Crypt_GPGAbstract the current object, for fluent interface.
*/
public function setEngineOptions(array $options)
{
$this->engine->setOptions($options);
return $this;
}
/**
* Returns version of the engine (GnuPG) used for operation.
*
* @return string GnuPG version.
*
* @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 getVersion()
{
return $this->engine->getVersion();
}
/**
* 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 = '--utf8-strings --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();
$privateKeyFingerprints = array();
foreach (explode(PHP_EOL, $output) as $line) {
$lineExp = explode(':', $line);
if ($lineExp[0] == 'fpr') {
$privateKeyFingerprints[] = $lineExp[9];
}
}
// get public keys
if ($keyId == '') {
$operation = '--list-public-keys';
} else {
$operation = '--utf8-strings --list-public-keys -- ' . escapeshellarg($keyId);
}
$output = '';
$this->engine->reset();
$this->engine->setOutput($output);
$this->engine->setOperation($operation, $arguments);
$this->engine->run();
$keys = array();
$key = null; // current key
$subKey = null; // current sub-key
foreach (explode(PHP_EOL, $output) 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.6.7/data/pinentry-cli.xml 0000664 0001750 0001750 00000001225 14203233501 015760 0 ustar alec alec
Utility that emulates GnuPG 1.x passphrase handling over pipe-based IPC for GnuPG 2.x.1.6.7
Crypt_GPG-1.6.7/scripts/crypt-gpg-pinentry 0000775 0001750 0001750 00000002017 14203233501 017107 0 ustar alec alec #! /usr/bin/env php
$path) {
if (!is_dir($path)) {
unset($paths[$idx]);
}
}
// We depend on Console_CommandLine, so we append also the default include path
set_include_path(implode(PATH_SEPARATOR, $paths) . PATH_SEPARATOR . get_include_path());
require_once 'Crypt/GPG/PinEntry.php';
$pinentry = new Crypt_GPG_PinEntry();
$pinentry->__invoke();
?>
Crypt_GPG-1.6.7/tests/data-files/testDecryptFile.asc 0000664 0001750 0001750 00000044630 14203233501 020674 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.6 (GNU/Linux)
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
5UNMRFSCudtMy/S5sRJocg==
=ctge
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptFileDual.asc 0000664 0001750 0001750 00000046147 14203233501 021507 0 ustar alec alec -----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.6.7/tests/data-files/testDecryptFileDualOnePassphrase.asc 0000664 0001750 0001750 00000046163 14203233501 024201 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.6 (GNU/Linux)
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
71wBmFq9y72NvJ6XRA8jOYkCofrFdQbxK2N2jQc=
=dl8Z
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptFileKeyNotFoundException.asc 0000664 0001750 0001750 00000044660 14203233501 024704 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.6 (GNU/Linux)
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
=GNXS
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptFileNoPassphrase.asc 0000664 0001750 0001750 00000044644 14203233501 023230 0 ustar alec alec -----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.6.7/tests/data-files/testDecryptFileToString.asc 0000664 0001750 0001750 00000001644 14203233501 022364 0 ustar alec alec -----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.6.7/tests/data-files/testDecryptVerifyFile.asc 0000664 0001750 0001750 00000045167 14203233501 022067 0 ustar alec alec -----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.6.7/tests/data-files/testDecryptVerifyFileDual.asc 0000664 0001750 0001750 00000046502 14203233501 022667 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (GNU/Linux)
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
=0M/D
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptVerifyFileDualOnePassphrase.asc 0000664 0001750 0001750 00000046502 14203233501 025363 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (GNU/Linux)
hQIOA5+T+RFnKO8SEAf7Bo9CxQf8AKQVRpgXAeHYBXTE6ekZFUAqB5CRxvE5ozp+
zgy9v6opM72FMYNChpskKDK856lnRlRhYB84m25cNK/6+cB6QhUEloab5cuz1Bt3
lkxoQw+t9yjPonhz/1/9bSjJDTkHOd2iia/RW1bCB61CFZ7Sk431xwbjmGiz2eG0
Lv2sW13ZJ7627aSEU1OFAx9wglwV7maean9bzXJlYBykL3HdgAHZCzOPEh7rw9S+
bwoV1jZbrK5rE3Jezyz3dm5HxnbBTzyJMTaPo9FTgzdsbGqKq182AUwCEaEXSAfZ
Dc4SK/BllZPHSZFKLN4QHXa2cUwoTS+t9SZZQL2GBwf+IZNrALBuwlyICO6qBtO8
EzRXsBDmsab5XTXdW/s+X7tcr8qjkFtmICDU1m21AbZ98+um2OQd005Ip/PK7Scq
Ck/gOHJ4xoYvzqJ0HaWjsf+nxo3vExsCL+/Z6G/1KGQpCGiEEFS5W2MFgRhcGeLG
8OvORoOqlvTKmMwYXwYnLAmwrOu0MMAw8qlB7n9ODTDnT3dkU5DUYS8S3xVijFxA
Qx6kBrtE5GA8eZx2MwQGUGi3EdgnMfEUkIWOJswImrZoPfRNX8gUpjkwHcZNKwBk
Ry54M0/mNLcdbbdOdrYcV5K8AEkD5+eYmQsHZklGt33eIwaAbI7Os2NNIsuhn64L
X4UCDgMkvzgHAMFLTxAH/Rb9x7Kc2lkjPMNqWYIUoDh32WsBxPZt/2SaFdDayT6Q
52iLYnUKTTeIiVR7ZcnG8nqwGIRycE8pLi6t0zSrXpVjg2MZrV+4+lcnmn5DF6mf
xlpoa59ykisQfMisAe6Baqa/n7Jz8znGjfzppwrpLomNOYk53tiOvOG153BDDB/c
11ERD2dXVxI6PBNGXcObd72NYuUJEga4k0VlReAxJbOylW7gXYakIv0a3XTxnM5H
JO89qbcQ7txtTRBcK6mTWx5YC2PtOL5tfvAHNsrqF/UIYRF3/LEvpoAhr+Buops0
4F1MM6u1bIup/cm4+2qDD7yxtJ483tTjCt00QO5mcXcH/1hSDP5yCDuWSoZ5sSET
05HR64AAlY/HPBaEP0b3bQlHswFdlVwMllpkqxiIARstTsptbFHL+buHNcFfley5
HqYiIIzngnsgLt7Te2rG6gs450SwF5koEnWHaitKixxk+169qfoQ6CAHk+KMSG73
9EYRWlAkGJ9DYTxrJP4nXlqMJWQc9vQjCdcvHQ8Pm8wfaBFe5MbevN24CzXcJ/rs
Fet+/vxaV0dcU2CQWy9tb2HO6nFeEVpADnANC+hP3X6un1dPsF/Rzb7t43YrfgRB
49A9UZCGHpeM8yXPxc/cUrVB6qJkVJVmUYB7CsQE2MsZNU4wzhUVHugVQ8caQwtO
F+nS7QFinYkYfO6NZ0HN1jc/jR9mdfCV5bSD+XbZVWrnUplXTtuqTqdaLvshHS1u
/1s42wAIN6ao688iQ9jsczb14AWsHXqCEC4HZyIbVJT314MALBSxtvyWC6j8tWI9
O+bo5tSN0Pk5Vshk8mKiwrZLTbCZCNFutqiqaZDW85DRoPDY9kum0/YuFs3rc9HC
V3Jtqh9Z2mh/C1LHDxd66MjN6XgCUgbmJhj7sD5mYDepGjvP9cAm8+ngvbWQDc8F
eDwle3GBD4/TZegQy2sVKDkUBQ17/lJuccVaLXJQskKYG3EsvtTGnMwIv3tpUmZ8
kcI3kjGLrxT5I+k3wg5pT9U5Y2dCGkWbFPnrkqaDfh2NdmgNIA//ajzdYeuTeM3a
QTr2jDl8jW0g2f9iogla2ROedI8jCAa25N2hb+B8owNLwMiYbnoAmL/HfHrgh6Oa
0ApHUHpJF8j0H1TiR3wgeTHOc1HndMUZJ4HABnkicg3bfP+sp4Nw2399ROtHpoIi
rooxKXqyn6FAOncPnFvojdvlCkllNku63KTGx0HNH0mXOA57TlvqotDo3w9iQF4k
479mjfgMUy7YkO0FMBCXFBcq1jyrlRGkFd2NLoYjqiVtH/AOtq2zuAvW6dPlQVlU
z4G+j3eb9Tn8fmcb4krINKopZxk82a9bzAq34yvi6ABieFLMWllz6l8C9J46h4rS
27VwbaQ7mX48XMVjgyPnN9jZPfFpThOSwqtHvcyzfd87mbKszWFUnUNhowdeEcvq
QqrOuTRgD62kXmS2sfe/zEhk5mMVniavb/2cdEIQOgBV78TRx7aXe56hKaZ2FayZ
3UKESn0HqmFaq/KZEJo84UWoXfFum5mkxxd21lHIkD3OymT0+TN/mcJR0h07pQ0c
xWxqT8sUy/s/xsT5pVEwC9I/U59GyZnXp9E5n+DcTuDvYA0y0s1G320z5arXlfI5
rMiXSZpl5cCJixwMjIwiQiAxED6dyocBjddlnYPXwY0kg61DouyOzLyI8IwOShGM
rdhjgGtUBE7hf/ZMnJ0R/xQx3gUDlEAOePaT6Kfb56z7iEuYfiLpis/Th/670q9C
h8D6kc4U0t2KC9y3RUnXDXX0d2KSIkv4rtUEUovQDwc+OfKuj77v30hXKHUdb58N
gqgg4zZOeiqNrfpknxtjtdIKVTXAqrYXRLBvihuzymVM2I7Gf2cIZqXzqup0ST/J
8m2/oNN1DAsxAOWhOUsGE/LcgYuw/GTmXnwtTa93voWK3yfhRvK13BCRfVsNRptb
F66jZL78O2zu7AR0rZKT4FE8rkpLj2rdDr19YRxQXkMWoUVF8OBPiA8OaerBG+eH
t7JuUpm9KFtFFNqOpDl8Ul2V+fxxqx6LtekRulXFwNFG5nOREYBjmopiUcXTOEXP
IIvi5uHZY4SLeUS7WWrPCASrOgGsTVRj7Ssm+jgp80PqR5jcrlansZt3HXfDSdAR
q+QQfMHX67GnOlRfFoD9XEGoLG7gBAlCjRm7Ads1HtjKdFO6PFnrfzM9Zi3vTA2/
p+QQ+KXZpHuVKVIy6UYF70QuzA6uyxCthX9XdvB880x9wHYrL+2F29kAsFm2w8kl
IOUV6ocaVwOEQtuVzx5Zj/k+5KQ9FxbHmuZIFLktntNi4dRqD/tAIOsIetfObt9H
t/ylZH+7Xi3ry7gw347CrD5+pD+TCkB/BfaNuaROUYcwOGiPmataPNgvVqeVYOqK
1dsOJRwZAb6bj4fjqjrw1W9da17ZrKOeiIcIrpV4q8dPYyJi+og7C1DrExEQ7q8f
1YRpOWKb0b4SUz+L/S4iHEbvFFIsh/JPJuQpWFBGHvajidgc+g51ilnOmkvk7lK8
+TRfSwZxQy3/oltU6GE9BlTNcXaCNM3C1EgwDVkW/t9VlfXJL8oK2RZyHKbBa5EG
0RNnX6lZsWGinenobCcmn8YgWAs8towxH4Mbhou6Q0RkADPhvKIH1kUOdTGIo/+j
Nh8+zriU6XCzZ7MQY47Z9boO+/hhRQ6Fl2EC5oLcK96uq6c/lkWj7a847+7dkvxb
4MBgDRGw+zDPxms+QQCKotk/CcgqXIoWUN7BlPK6IK3Sll4OXBBKooTR0wDWd4ve
rXTlVDkp0yXE6zXgsMzIIWKHlVup/wOSeXBwzdEAJCCD3BxsKfV5Dj46da0vRpP1
cA6GMH2n2i5zAavP38YR5Q8GUPZxkD3jJXGl6MU4hpF1/8yA7gXnIO0rLkav/slc
3KkcxtYVsxt+fFr0JfwglS1vu0PlDvnpxSKTVVqypoX2kItu/vpui/mR+KoIOeEh
O1F0smNQNeKBBH0H/ZxKOzQmF7vAGUVXIW30ej683JxLFtuXCVjycZhQ26XlKR1q
c9wJMNSZC4tI7zmehEYEj2zeUMEadGyY+59eAwNK3+8Q0LzAde3H9K8yMTx+nvWZ
12Ml3qpzvwFGPmOUuSAJVnszd0b/CfXhZPvrxiViBvyGKPeciJnzrmKfX62B6tTf
xMSeANpP8G8YbUteBy5kZIS56rJqcAI019psGNKZszBi4+Ijr6ZzMDtVv1MDeR2z
WTY6PIHUamCHls5caHV+1E4Zj+Gp+LpNF+/tzSIrea/YWHPrq8rm32HP9yYWxYdp
QD3GrFJ+g38E9EFZ7esWZRSwR4axDmwTvg7h47IBWZX51pHPHATuIgen6N8Mi+Kj
qdxEFwv/Z1CX2fddI59h+Nt1UFIXk7zz5TK5xu2UZ6BJresjVTcyuREie08Nq0uv
zW0lil1c4wSZDE55mmcn44OADSYDG1TAb3mMcQOMBpbuxj/8N9id0N5YKRlHtV9O
JawYEdb7xYOYTaXERxv+yxoCYrbK9au/O8pkUh0mBXX6aczEXUOGGZpR0VWcn19c
qVo4rz5BIgq7AZCkNHx2sFYgs4ZlzzZ65py2MwM4g8jjHc7pmHr0/+SXTC5PqRwk
zbZEG9BXrBcKfn3H0byOi4ljFiQPXZKXc7vwrYHZlz2s3Ip4+DvYAqcIV0LNo8yS
l/Ir9082GyVvOri1f5prqB7zLj+LGPNZBjxw9e2i2l+CpcgPQ3FZUREDA4ddvMae
bJR1jh7x5gPXEhqopf69R42Nuq0eX3SAmPADml0z0nmUGazBnqMN8JySfYZn3Qpa
xksaMH1ibfdVXxp7yz9K/RgJoEbikKcJ7vHLLJMp40HhxH5508akodCxOzbJn8IB
lhj0Kh+C7BBJwMyTIY2U15ilsSuIkD8//+fGjfLCOWz4CkoFNIOzd747qtlvwIUH
x86Mt80WOmMHDqgyO0fCVpm6ErGP4ngNXycEvRjxEFpvuxovRYvYLsyUIQO/EjdM
vRzzHCk5Gs15pSZu3rHWKYKrSj8r2Fz/tyQHopQxcA1JZZLbyt0psHJGbzeafb29
bH01pQKMuxfjL4uK9ybGc5tTcwdLMCgZhOtzOuAJqOE/Kr+pD+ciBQvXxnT9LXks
MATcX64OTZtNiMAhDfYmtoZ0WohNDmOC5XjjR7f5bPs4HntMZxu8g2XNAbuUnyvt
KsDUdrzK8AgE66hP8wHqACVzDHCiIgaIUANTdzHVdJ5r76D5oj0bAzYpZE/4omfA
PSilZUyY8sfDhRdeG5vhR8fLVGsE+lbhnOIu1qgsZh9TK2woGoo8lI/Bpo4ssLmM
x/RB5Xv9ENfprDWvQMd6UZZ2olUU7Yi9mSMW1+7auyE8YV3WUnH3AzAv8pyUtvjQ
6JAqhxuGaAUs8RYzlxvjAw6+3mMfub4DOp/GoJgLHwdi+MdlgQUewNd/cbxZqKuc
rlGXh394cYrBLvg70XeIpLEBBr8BpwsLVQFSvney49AC9Af+Ft7BFo/MaTVo9+DW
8v9pgqISLKOl0msKBHRGIX1uF29D6hB0tsizOFvTQufaRtfBHarz9igvB+LsPGEy
bmsr30HFnbrVFKOa7o2zVk7WNIPl5tH8bzqXfMXI/zATKD5GIJD52py6RdF/XZDZ
3qHUTBgeUB79Hy68+ot1hDqOoR3gnlm8+bcEg+tv7L6QnN8mkeBHPp6tpAupXhlt
Zi3ikD86QKVntNVHDFLEALWLTxhd3daObCL9FWlQstsZ99KubiV7KEqIk+LxWsDM
/5Kyw+p14mLJcmSTdex9uUGLk9hIdo8DKvcRZprgbhN4JCtiwbPkGGmoRBOLfuzw
JNeF7XoPDAwBlJMqANxGCdr3VrJHhUIScT/TCBCuKfUa4jeYufE1mZ3wrrQBE5/I
/J+NkhKpcdECGXjzbopxc1aXZoP8sBzE3Dyfws/fuzTbhXu6N0ta59SXYJ1nC0FA
YaHgbeZpWMQi7CSeuKuWvRbC7oSvyiNgRSagROYxRuek3SpgnhKY0dc04YL0f8jW
hVTJgQmD7lBicW4aUY9kb01cx+MXjLvWy2Brflbj8gVwdw/+MTVKceBNWQQSOENp
rnVdQjtK3OJzu8iofVgYMr3R4FflfE9nPAE7FdAfzipMprIlrj5DTTwFD4MgkIqu
MMW+YS2t32IWwTq0iJ6XtxRLKx1b6Ir2vqDE+yxQZQaPHCBjoaxLY30dnXVSzLzT
EL318d1QxEqZtIHMLNA7U0h/nnHeuVtbLx2+/SiUvYj6HEHE88X1uEXmF/E03pRZ
Qo7EGHdEOHM8eakH8S42aSS10XSvFDE4i+hebQdSLQaKV3ilu86GGAc3WZZ99CJl
tQ3XrqHoJxjmqeEVzgg/6+1cnGobyCIKOq6sjmcKHqTvuS1idn6vR3kR+PBIWN4n
WT0iJOjnGYzDtXlp+QN+FiaulgiCe0EKuoPSGdwdO+XOeQ2SmT4Tg2CiZYUmrWQJ
zZjV1ILups3OAt94+fv4e6NpiCLpSj6e9aQSm1qrAQ0rfyT8GAo2H9bNLUn9LZDd
N9aTz5Mks0CSDMbGBbL3Fty4DBYIBY8mirVZBQa4W0rkdQQ7zZBJKIcoZXJF7lch
/HdU1dqRw5ZASPrFX17od7HYEvOpZTR493YX/w93my9YHs9PLjMWRny7G8d7M+Uo
6+RRDu6FEz0yyhy2Alrqv7UCuJAuTHxbN8UD6HG5RBKJzwFxQxsvNlLCHVTIr9hZ
K3mzb0Gfm5+OWX8YFoLKI4VAsLJ9jt30izEZNgqcjC+eIJVb2NVLWh0UvSHLVAPh
tVGgUuJAl7VKNBPbJ3zliemc55nyJsmb3vt+YcwXmzMgsCIe41+sJ5zU0JpNLYhC
P9X1RdHU37fAXS0jdpEZVUgBZehBi3dvyj1868UIF+1/NQ9LLRcqYtELF2mDTVZv
nhiKHpcuz3dWryNvBb7SG/rP+TafUQaqd9OnjHXUXLcvT2Wjy1/A9MJY5E6TTzt3
+4CkyeNtSP3hVZHZBhsFy+ET6KSJthHinz61Cc5M1WeFuOgXaPi7PIig03eMYiBZ
Hk6fl6ScENa3BnVZY8HQLhQz/iPhstqm5dOdusYEiVlW74LNe+VJ5XkguXLdVTqV
GOXdB0ZUF25d06gXI7qQH/wccfjtCWxrRNQF3q3exECx+eGWlEjgLL/ZW56lJGBZ
jdLgFOy0/x+y44LJyNYxV0yuXl2PxsaMwoWEFgIa2+6l2KtSTD7QxldanhjUXQdK
decY74mkBgAy0SyvgmE0LuvPKBrJK9pKn67yJlMlf1cgn+NnnsA3i67JCBUufIpg
rRqYBAsSlNfGxcUJRkwp0brdhILFfpeYlXAYKmM2ODJIqBFVlkdlkgki0HsY3oRy
HaxrnAnPaIOK4JftNE786kGGwM7dw4oSK69oThwP/EFhdrZDRY1iO9V7W3LL2hCQ
of4xQEjgUJxiDO4wILIdA76l/qhnk/R6gCr8mbqRKN812Mdkh7+zIFJl9ySI8Lir
KHeDk/WLBof+XzgytDurPHJ5KOgCfDyE7Bv/F5XJ7EdphzDijNf5nWlflPI7btAt
Ml16b3NREzZcwvXgS7Xxfn9kWM6Fb3JJWuaRrEoK2D+kcvoypZdo+m1r9uIGX3/K
d239B5dDsWXwkGLUiaCl/32ZcKEpoN3EJXzKWEcs3JGxnoY0VNztTPrct9oQ+0mg
o4/fdZ7qIDUsDiDmwFoSYk+VVPvY5CYfyhel6e+pMrbgRxHbnxJF5Ldtlx3uaRQC
CJyzwirK342PPE7+/goyDA0vzzCX7tN+nBMdZzVqgONnepdGk0UOnNnGXuGQv09u
TUCSvXyowG3up/99fNVq9uC+dds/ocKGJPC/nsUe4N4LGW4zMLTr1HxXY0WViiD/
yfHuBVKqSVF0d3uVydPTqC/mucTeOKJdIFMRZWyEmlgRDZeg8IDKxt0oo7OMpByl
30SFnw8UuglBIamnhCOMjIsoZEKBG2/kRWAbRU30mRitQsS2H1Xb0aBli5quSvLG
lqfydn6wyFteKP/FDYA/hDNTL7TOi+J7nwJM2WGNa0iHK86aE6+KSIzSpkGnqrSE
CjoyjS+WNf6uxtbqnItguSPYYkBRpu7ZRsWOw4QguBxoX9GTdHWSJx4tGli+4moA
onsMuFKEx9Jf2OtQtD1rgGLFJ29dvRMmuIWsKK85URQ5Jj2bU4Q7QFGu5mL7/uax
3buFAqYLqT9IVOKkBP1LsIWouQ6L74CypfpbjUW5tX7Gpp6F+HwWQwB7QH8XJ3+r
O5aWy8lvI1spX/+6gtqamK6qGQhGmNlIsqMVDfeUb9mK6TQOZXnT6R58Osns3i3v
nuWE0+B0JlKBTtCQUrIEf2MCCJIpAnwAbJ8+3kPGuZ2b31xvhCptXPt3/ofV331K
ZIDyGjGHdpdbCezRdlzwXh9OA5jRDddy50sUpiREKSMyslH5bvc3kX7ymLVRd7BS
N8OYcdvsuwLRvzufOr3p7Nu8+yLBJiJb5XCfnLeEIDmqqVjAjED4JY8MH2FKOEIo
TBL9UDGDAEki+P2wdLAc3uzmsuqCtFqGIeHlNsVKPkThpkyJOCDkUgbRpL5iR3s9
7+lY0tuBhWUGEtR4G1L7FhmXFeYW2JjEG20wZmVq6HrhfkT0FvPrPxwKe+Qtl3xR
vzZCynsOSyc4ih/MGYbDMRwHJqPOUoyYVUd8ReEC1DSZ852p+31qzXkNCK/glTiO
WKi191dhe4QRI55CD2xEkEWC0NeA0o86MxcR41krERc6pA3zCXHwK3Jxh7CsMFXu
do1X4SNHcXBBbgnON0m0/G8A4hfBWm5xBNa3QskSF6HEgd12JuLbd/2c9pfZjihB
/caH8gxvSGeeP/GjdJqkVfgiD3tXz/DkAkEhXN9/3FmhsPtr7nE7f6irFNLsnFCH
9cFvOxQW8NY06Ig5lFDj7iLT7j+SPx94ZSIRZ4wyUMSjq+6k9oOA/hvr49rIICth
QZJCLfgzBceWvvF9jxzYaafNevvqMUG/3dNxWbIZEG/W/y2RDul3YFPnpcvnPVpv
IlCNjjiyBV6d6jqwhgybd789qJi/sW5vOeOvWHQskMqYR3teVz+iyUOGXBrx+CP4
Vij/Um9ywG5Rj8OqKhcQSReTY2TSFs4BM+2uZaDX+1liiDgf1h7aOJiNiqDzKW2j
5KG03Yy1JZ51D53Do48B9DM8LSUjkWOIkAGtnbNSimE92vVm2LFOXXzAExKVzeKF
qYTKNCdxRu6UIe6+1IevRFF8ObUopSQs8DRIb9OFx9ynItwJdmkbSBfhOqj4ZlEW
MB9R7hGQZQ5wKAmcJBJ/gRwn+uGRn74QqYNR9rcU0WiljL9su8jChu69QKCUXtP5
Db3ei5P8sKG8wvh8WX8LUx/YArFnGi/sdgpQJYOEOCRTlWV7Hd7uLcHusOLUxsnu
a4OITSLX1FpU/tn/YRFEP4Ep4S1/aA+EzWD+eoQitaHcnwxrIZxCHegwktpO2ugX
22k/KyaY0DstuvIXa8aj3pZnsGlqf/IgE6Bnih6W0G/2/otIuVyYNPdIAIfI1boa
JKiPAAzH6jlohCcdbgUh8wBAfiRIuvYiU3VN1p11bWmeGMJZsA9qBVx4VWE+1mZM
osMZfM46GaIoe6IiPLEbXTBMG9UeE2q9r0ritdYJou68fhPnh11Px3cF902fTE6k
uNHkmc8Cb6qAFNICorfSxJNCcjZ0mnxFHW1Rf30a1pbDHS9j6yWcW9N2aUofI7rV
yrv1YMsIr9xnOzb/otC323lkE0puPO5deXYeff3Ayd4P1JKJhQugEb4PlNlxH2wJ
VQcFpZi3Orb90tjaqMIXasilvI2fM18/kf5DW4xwYdxmzwb5FNOJggLKS5qLfIW5
gIsd+jlWQB90i0sRtKIHmf+UcmlyvcFF0DpT1ve9+KTkMXHDEXoOqbVLzW04A2Xk
ni7PR4kPoBqOSq0PJqSNvClhFTbgONyWdMJ4YrHULHFdqhWVHtswt22XGE/ERiDf
tHQ94hzw4bq5aOSqVfczery0nxe7LaLTZSormH65Lf9EiqlOOYTeqoMZkg80A+wT
enfONiWgSbJoNuRuHIfb0XSHms0RrkKk/Er9+rpoixwVf0CIisPXeLxSRtjacVR4
b692jN0GvjGrKbJTfJKBatcW5LPAjHJMU91NIRv1itVyuqq9fyCWwdit2viuwieW
HSfZDtVasFN7uZd/9MnHRvZQqzqgLO6VJ6D2lOzr3Ir863JDiF7m/P/Iytx2pjFi
ncUCO1K9/WdOUJO1GLjvVRwnHzI2UMdaXD+0wFKLinQL7OpHPrV0sd+aCIs7gpZo
hv/ui3yZ8muYMUjIDE2hGYflXJxMAXyQbRonRpzmi5NEvPJ/fn6RVYbLikt/1OTk
IetaK7sjXNw9LhJbpaqiP3vr67qiGJP4GymSWIwghf2C4auCQcN82ntlnFxK22YC
fzLQRlmwswlOC1XdOP75upNJrVMty/IGSwKD2s4qLJVGX3oA3H+wyXZg2BIYLDS6
iP2G1pas0DLNEwnKJJ8dzpLUfY5wpSO+jQaPzpySE1F+l++jYYqwqYOVohF2AAwW
m5gR0DuNLssGFKVOjhO69m6uSz9a7S1/yykS9pQNy8yeSlw7lQ3E6wNeiLhtgo7U
l4okXMFijxjzZe4A6ez1/dSZ1lYIkT7VfaqN8sCAoXfbatKrUSsd+aRIm5RgQJ3o
crO8SyRQwszbp0hTLc7NIq+hkuQ2JtEbp/KUJirEbjlbnYfG/3Ob/d5CBhw0Xl/T
0juJiEb2Z6BhA7IAwfBr7+2NGdW8o86YgecuOrUZcSnWmPsvGdHvEsXNtEFbXAEO
OP4+2xUerB1Njwpmq6g668/RR6AcwG/1hlzTZiYvOZjJ6YuNX983sGYHPnesJpDl
68bIY9YcgTGY1XPB85I2hpXu2ha975fJSSKBD8dTVpG97lYaWxjLR8sKo+cIqyke
BtBxKsWk/j4w/GUx7RxDnOJdRRFMC3ytE3E6RVsRAj9o6NlYnJxRcpxbzxxhTlYJ
vuAvrO35qHK6nljz/lI9ZB+W/guggrRaS3gqRgaAiMNlh3a6NePT6yiDMtmVj7fH
spxbKJQEydsouAOArMWY/t96zaMlzAzEG+0BDfztYmPGBR7DDKShHV2FS0DS0mwn
Hpz+0ByY9u0FOrfBsbkwd/IsxwYRZnPGTguFsuxhDkAr39oh99b6KJfL4K6/L/yt
pY2YgtJp1p4L3h27WXNsUzeGhah8FDqOT4w7DEquMVHPGmH2uoB9u6kHZhdVYFU8
nW136fWI0NB32eprfO/F25Z0imtseiTwN3jG7e17brgXbVV8m6OF6Fa9fxVvvbVm
uLOZU+0h2x3+yEWmcyhxZnyb+fJMzPgc7EN+lN6ZsfW3mi9k5NB5YewuhO+QA5hY
AihxCr0Xi7CUSI7RFh2ILmCR5wu2vkP5CZqBSPbHi8LsJCH3s27N81TcTHBFnaed
3/PMVgdGKcOFBoc/u5spXF5NT88+Jv5vXxGqM6jaFMJ36hD5qQCUI9Qm7kN3ZI+y
1qLCNGg2pdK+aoFmspD/14r+zLoTWjFYy9HeJ+8Lyf6heJdd2yw7vD4qKhfU76zU
r44+anI93MOl5akhXHti4L3S8Ey5+nvpNIkH7mU2p01F2Ss2HrMFcqaN+CZMh6S8
N1ckpgC96ZnOZjvCNs52ogyiQfv7FUT2NfHO1MLZk4TGarkU6MWeo7N1z8PC9CBo
IZ/Ki9rM8ngqquA5tbRA8xEEZxrY4u/zp3WPNVsrk1UW2BqQWmEPrBpzNxJ/FpyV
gjg1Rp/ykzxGErBdz4Un4S+tvUU+Qdj/865T6SVvW87Hn02Wd0ThB0KOjz3x8V6C
j5OPnW3cWqK1TjislNoD+N+rcOw9mJH3Jj4osUiSH0yfy/RPMIS87l8pZmnyPehE
1CNDqzXi8C/IZE6aa9q9epOvuG1gzypM24OvbVWuFYD0xYvJsy5Jf20R9E+y5Agy
gxwcqVfJw84PGs6l4e0sUzpeANFobZUq0i0llGrlWXPLgB7lVLshxjnLiEYt9MYO
6HK7JBBons0P+6Hl0px18nmATYNV+KKIhwp2lMRsEZ8HMvjG1yPVhxW7OsClP8hi
cIxRR3w3z8Du6Fbx7F9zpKvJHOP0xVCGsZPbIE2KIg3hjjEOTEvrdSG2cUm0NFWE
N3twwnkLGjVhuMteOofLVbRz6O5sUe8pvzrfTCQihaAYGGVAOYMA6gk7/VGFdY8t
705aiX5/OsR1Z8DgYgWmQyWuQb7OfuZr++F+fnWN+fxbpW5d4eH+m41uBhL+YaR3
2S9laJ9CWECPA0DYA5vJhlj1WJWqnLoNBVr47WvFqn04tSpMaX+5BVQmPToqPZjV
Smoa//9z1LWV+hnNH5EBswhKhFqUsrGNX3jY3KAICxeTjN3of0dE4q6vV5Xp4fJ/
sPAop40oidZrOlvkerWxZOWlVHEwr+w6hNCWmrTZIDB10W4j5SB2mi98yVJe+ZCx
QvjYI0POQTgEXW0eu3FI8FCvm0xXuCw/zFquIycGr9C5n6on9lDQdqWINySoeTS4
RaCZYimPgmaQevrgwlthkSy4W2O7zPzkOpulbvLgnwVaicw57H3IICgYP867yokG
bKxi8uDE0Qi+S/FGlYpeyyCdlhynrEPYasr9H5l5QUqUIRFowQf23Slb1PAJ/UE0
QqXAycPI7AhwmhlTMvtwEuvgj+pxM7XxvVXlHulsP6z6pTxtCYhJa25IL8NaaX1j
0IPDNkamFBNS1RMdh6HSBZYte5vwLVFKwHwIeQxg6JJiq3qbTGrv3VycRK7Qi6ZT
X5j/EApeG/zB6XLpyjDH/3zh/ckRaNpoA8f3bbcdqJXKyl9R7rmu8fkTyPRK/43q
A66UpxkN9eXncvwb8q7KH3PcLnpIbQYZfdRuHiaQbCeamX4D2ufKduSgJj1AZ5zi
eIFmnrtVkfKh+nlk2HYvgUpJNgcgNp9N7WBjzGkiF0zG8oZwkFgs1yvwn7odQv60
PvumFHW8KoRRrxpKEsDhX/u+sRfeq1ujlqC6Iat2ZC7vlBDlG97KeBiyT068Pvhn
wQo/MBaPBo74gmust/EZ1Ib6CkokkFedxZgeuyBtqKNoLTPuNLOzTfNGtzD8rNfK
WRPLOqFcZvQpp+IjjL+srvai4pBOYXCGhpF2lutF167MOmCKg5mLrworsfxkW4zb
URFF4Qdznyg4oQEk2xbBbzxVaBL1HbkPggDyz5ZruPRYZ9+srpaEopC05fmJMHdM
tUoY6ehsMxb5HZWrRgtwKj0/99kDiHk+FUPDdlH6VmVuLarrN2FGMzqsKEhY8tHm
0BFpTX409fBaGYwJgNLZtHYbIEmLHYgr6rb8yppKaXqhNxE+arQ5EHCizA9Lz9bn
17538Y/Xi7c1LD3M4iWe2QyHG4ef6pNZRgxYHyQ+SJ4+34e5VLkDPKZ8tsJy7z2g
9olv5baESNWAxksbIr6PxkCKxuoaUxUwbVL11CEXZrGl6Q6pCQNGDEphU5mqE89v
me7kVE9hQTsRj31q13j/31KctHGc0Q3E0qnzAgJ7nyDvy3ecQGdeHsT6XfNf2gYF
mwfkpMMbkqcgFMwpA2jHeNxr9xHcMcnwf6nDtt544G6yxsOdKQg3KUiyKVsaSCxO
ZZsvHqW6SgsaVX8JPt8ekKNLOA0bw956D533oS2WSV7GVWwRo1KjT72Z7hZhAEBr
Gu9fgdNYvS5kLIEILNKClHSXYzJHmqOdpkHA0NGbuYhXR9b8UkT/9Eclch8lhnoO
ZoB9B3kAu2i4veILX8sQKR6kFZ+iwV1eSZAxbwYG6HI1/eqoSwOeyRzwGQI8kQpH
WhdrG0y3J5WQSzSYEU9bEnc4GS68m/DGE8SQweuF87twy+Dh8IZG84vQA7RNrvgp
Qji/tPRhoD1NP4HGOS5pWWBNy1HWgbwNtedEIqmeDKx+pGUVifjF3QRgGh2tln50
eQzaTNfLBeZTX5gpB1lW962fAA72JYiJ1aXLizeWv7rg9crqoNFvbtTFasYy24Of
o5tjNEKne0aT0FvyK7CCMIqHhTC8NN5zpovsorQE+Bl5tyUIwDI5S83VxgjYzG4B
NzQEYugfvUfkzHLCphTIy8/3lJWxdv/ducPR/qAlZrtx1hKXRtUk5753DgASNTsH
P6J5ESDH7ltlQwlN2daG3ns5ToCr8bmjsJqqqQIEo9LKe9dXp/DXuAQog0feY7N9
sSkIFPGG063LmCbjLjS36qk+YYxfVLGN21rfkti+DGv0UCMwvc3PfJ957y2mRK/L
c9D+T6BiRm5+byez7qP2SCNfE6QG14dCo0uVl/Oc4IQrHzbkKddlMF/QpzqYfwll
DVDLbLwciFjtZGMOqEKpiriZEF+uOChTLFfOhOo0TRDnHk7q2BSR75fwJCh/MLCG
iO+zxZdzNqkZWsTVhpvzAhoLmRPPi+xHN3P4mPwtHmLe1WfFxFJPQOzMtvnrZwLy
MhJy1dC9Yc6cwqzAyRYaPapRR9rj8R2SeIiYQYzYb1zGoxfOMVfF6A+oeb43RPeS
QnIsbOYQ++WJvFZ0zR0W8yYHSdg59vh9zMm+gFnPK2IA4rCPmRHYx8LW+9tmvi7W
t9U6A5/oB2X/AwZuY9mcRva2rkBxKbDmOpq9Y3pPVyT93bIl2degueVY36qtf0FA
GBC5IEOyf4I8tp9ec6xPHz92vHPKaqiEJI4QioV/Fr6qp9eHRrgBVlIlkv2AkfMa
WH3Yx2Y5T5VU9Z0U+CAisNFuu4ZeRm3TaW66Cv1nDdGEF6uzdJzQYpSxnz37sfF/
LCbRsnzpMRorlIs3zCIFYYej3gJHfg/QRJqOWnvcUKQT8822FEtXy9y08c1400tb
XAORoBjNHTVAPcCKMu4bZascwD0BCgXf8SGRYXWExWWntcUwsJ2Vr+07pbl7ot9m
Qw+zahBFSuM7cwiitsCpl4mhC5/IeWWYzTPvmjfifPe4uV4rIkYinXbGLfte4db8
bpbSre3xFWwcDVvcqQkXEDAq9CUSlZFOIomKVYFTtrtwyRvaUUu41OfeN+RmGgZo
O/+cDDO4x/OugemHNoM1rL6wzMtYTTt3YehYEz1If/x15s36mdX3xrd9SBiVG7L8
pW6pI0GXI64/L/2qro420vTqvVlwPXOkep+/XEXqZJI/McedzxrAuwGlW18cJrLw
d1LyLD5FHaFsij8Zy60kcHtZpYlaJc//9+jCm60rIN4HP2f/o5Ps3IkAUc0E/2fC
Rzq1xU7Pnz8CoBMW4qw4j7NzhPk5jp8YRsLU5p84CgXEuHoo6BcqP2OkBE09eTRc
DNXN0ED29uWyx+/mlfx7LjSKgapvy8WoLQUpmjmm1ayOPYh1YKEuvIYF6usta0G1
9v4R08jMO+t/qCvUm5Ee75uV5Faw6BtVkVEujtBjKToPs9oaP1G87WdgL8WxlFvp
P9apSmaIyrU6rqHrih6D0GoEGo2btBMABLdNMfTN+AZrbsVAnjpbBsTHW0A8OmBK
jJjDlOrZHFiLCQo4U2r5yxS2lzfoc4N2Hhquu+L5Zwa2ssICsW3X4JpsIQ/nXYx8
2h+BTh1BCKG9Usj8sNmyoyAy7NU+5dfgm1ZpiiEPUTEz8U6RSdZiRiZex0pDHtlH
SEnnN8e3GVnUqOap3nZmMzaAKZTB8LzgkgXdU2C4RyfqyswFUvpUvAyHs6EPYDFg
quGSi6ppaMK+qdU9JcM8vgurN5hI0crFMRVLATEBIZN1W8KJfcgQdiaUIq4q8ytR
Zq6ouS4rdt4B7AQgiSXV1n3JTp4wtjSDkXqrTP6jLOmdrPjLyqhQMinzBSNsS1CP
wJUuD0fZ9U5r6DdUtsA3j1w2Bst+GSNZyYl3VyI+gCMiGeMmYyoP5CI0sHYIl+Eq
IW+XB6vALVVNK6N9d2ZV9ElvlFu0BibTYm/D5llsntLiY4KwHOqOEy9cO2KZ+THa
8p559bOpmTUWMkXS8ahrbuxFIIUkw0bPZt4p8FMJTq7zi0gODW3N6HA4J30bLAc+
EFlP8HdngOtQDjcKBoGyF1mQXlbPhsxud+Psl57aHAdwDX9oiTpGZttpO1UsYhpF
F9ZrfY+A53x4+osYTp1XKSlhPs1PyPLFbbO91mg6lq8WFQBrHw9QhEPqwygCOh3E
IRx+tSvcxfhf2LLcb5X5YM5XBbaijqjOolCs+L08RheFNVyGnJS5vt9VE6Ku5490
WCrrA5s8OUQgOt0Mrot2eEy24ezDrtT7IqZPHJ13qw5Us+yMHxxlVDOVSxhmC6Yu
Uant+Cx7NoSgo6+6+A3a9pBya60iWQuYMPHsHwz+Hn63QUHqsS01o42P6iffba28
NdItMTg2U+CYO2JYVSS1pfS1BODJ+jD72SB0NGhAZMxEr/WZ2tc+xTjpd6MdfvMK
a5xuNoRd4W0WY4GZBfFsEsAKV9oHDrAV/esTrf2HLsq05jS3hGLCdyXniVhmpSCM
2eGT7Tfg8lyk5aLYHFYNEa4n+PGj78y1aGmGwRRk2Z4gM7urkJg4Fhc1+rHRGTwi
iPU520REor1KOi5b7gCG72i6VB9XM7yMHcyuwXGNZl8qjsc8yXj3TFeOs/hgW6Zd
SRGqqT6seonYh7cQdX/IorUtm4JZgjkCll1H8gEIGtAFBT9FwRK+X67XuKf0h1Lz
jMWHaPCZNGv7A5Q/k/UDoeyocpPY4Ycr9iCbc4beL+BaxXLPrw7CpPvS8EoXeqiv
TIHpStvtGGqrJ0S0QGCUSG63A02ZBR0v8cbo+Qz7YtKueNk1E73lkjVyqLYmhGRq
bhs84mHV3LMlYLirdjCgXjBkJ1gXdAqCoBFF1ChhzJ6wY9o7DKk82enB99OalACz
8Fr5JBR7EXalb8VssBh98RFQIWhaFhgMQgPV0AbOzPtYKGy/fpal1/e4Booadrph
yA7tq//1tNnHylxV97rLdZ2CrXbXUX0mf5/q5+aei/413pKeIBWoOqaAHX4VNKsG
tF8yMm5FJfVdwa4yXuKAkXIiUWCgqZKESWK2Nhn3W/LJygLtzkl5sxuWlYqzM9lE
7dy6KaOVdqrVckiG1X0lSD/1Xk+WzmybBqA2wysNAbDFPiq7DYVjdKbOocD4F+lv
2EC/Fy/Fch7oq6areU/Z53pWaex6K4asaoPl9ngCJbY4bhfN5EIUgjKIu2Pjf28G
Y0iKKjyPqv1EoaUFfvDxklVpdJA1hUnjE2AWfJJYOCMOeg1K36P6rYVM4tDF2sya
b7jIU6uGIvTsfjYCYtcnMwfv17voxHcHfjT7A3AgjWZ2DQMfKO6gGncamfhiuMj2
CdPE1D7QeTLH79t1KonOGFWRy2zTzxqcVvt5mgXXjZXIBUghttacx2umoJRSx6Mn
Wgl7xyBUDES7mfGOr8qH1yPsPKbHLS/IBCoOmvAKZCC/o/XAPhVjQ4IvRNX1GyyL
IycmkflmPjeC94ht+JZY1N6Hh8qE9I49P7Ts9EDHfZZ731bm8gQxbvthbl648vT1
+Lj2OvZKS6BBB4F6Wl6kKuotLuZHMYyAY+Uam6wFjTzBKouGu21wzjCamoBZRVmU
9SP90sZyX7CKVq0gWOo3XAyYwsSPPO8RAv2VA4QJFkxqz9YYdroy0DuIPeLmfHBW
wa4gvBOeYmM2cs1i/4dukE46hj+KYIiNAvFuDzL5hsfLs14Earu3GGLBBTllrStf
aJgUhUvarS6244+crkEow8CtGR1Tku5wn52ct0FSZvcyOEjg8pONBCJa4XhsjRWI
1hlighMSufJFiV9G7scVmV0IDyM12FCwDcNap5sHNpAk9gAmH5KWX6DUBt5Pj65s
xb/TezSQa8yZ7nIdeJdhxJjG6RlR8X83doAfyocYhlQDZ9FegpvPfXDNegXeZL9M
b2giu/46ebntOBPGMZZceyohEw0ludB1U1dtI6w16BDhza33g5fyK0kSMy+stN0N
RzEbdQt8FHhpQPQoPPmVn7R4j6+B6RrCfEy+rLpmC3OcGEhQZ//YRNFyEP4hb0bq
66bshFkMwTry0JyeM2GJtXbJu7HUUMqePBgYc2APAYzj4BFYPksaVFZyNd0QeNi7
IhI4K7TqwNMy7SmqC6fbkbDoEmGNyN1ifyzeAgxlvVIAxrmyV4jdxAsO95pHNqCF
GSA5SsxjTtaN2OhxW0t8pPlFCvGH6J/Nl2rr8QSLw6RA1IznuKo3wJgFVtiliiyQ
MkMsBuLKbV+phgiY4WdbyHflko7rOgt1ZT/r464otAv+B6+72z2ipjzBiUwrLMjn
njD9/zwd22DR3+pj7Y7b0v5tricCB60wZ7E9+nMvzejpBG9MNPnjLKBBKKF0tBFV
IpBGzaD55TCVqtnzZW1Py9r/PHyaQ37FW6nyT294qhVC6gRUIG59E7w5VWfgZS8r
efoM/eqtkF/ooowvIwsKSq13FLohOjR2Qfh5ve8uu7rVaUOQS8vNkiDSG6dpzwi1
9PRKHQgl/4K346KTTQ1J7GQVKkBXz8urxzLXGapg6AhtJFE0KJpMAsd6n40Ykg7/
dvqqjf/4hXEZ6vaPWRqv/xfuQsX3QAZRMUvxDsMPergwddPAxRa3dw5Vw48bwHut
IoqTCd5ptvuZe5yXTaWeKix/rKJJYLHh6zScu7X9a/5aD5s25sHJhkIegosK2Ovb
WtXvXwpychc97g30ByiKVq+36FC/t/SBFRgRIZhXaJmgbubvCWWrowMaM1LE0xSu
JTkx5fuvUf7YdnxNpqvJ8Rz5WUiY8MA3qvqVJbl72H1OhHhtdiRKuu109YRGyrCF
nhkBJnTlx2/H5l+G+vg+bUfzoqH8srxQe1/xvbs6tT4Fb7Dpz0ATP9yyu/QVp8gY
7I+jFGtLH2lZSmx3KT1bYDJeyV+2c9FUSg7m3vuzEjcRj7Hi+tvxIRxbYlaAetys
RVKsaaMMB/qbpHa249DnQwuE4DgChbs6HOWVgd274Zf39mxz/00pOCoDLyZRmk1D
d43oKblxEBZ0SjQ+3GnfMfffoi3hrHsxE0TtLg1kl3w7rt6uyrUZrZPHHcvMcXwR
nzMjlAYClHJxd64Wlv/fk6HNTnRspbKNLPi6yjaKNrtL8XnbIQwblbDGNy0FgNMr
oiWJ7W1SE0J+mVMJ6hp7VJlPKZ4kxN2VJI1KCF+0OFXFokmhX4oj9TTYXIiy0/nc
ZXUqiV06/nYmfLd3lFyrGxUhEQFWjmDjoZNmZwDtDTENiEwJywMpgsxP48jT1P5+
ZikikeKF7BHvF3+JDE8PwhCTl+HrLJsaexJyQhF7Z7HvA94Iaa9SZQsmLewpg5J4
6bMGdOrJAvUjUcC4wDF1LASueoV9iJox8PZjOXuwuO0/A9JOjh/e+pOuHHiU/Ale
sHonbBrUcO5BP3YU7DyMOns1i0aQKGAXZsnfQR57V0iJaZ+BLe6KLbLeyGR4iAtF
OX1jVjLqlsYhDlLi4ppIZJhkb+vykZ4CGggJvP7L1zECSfixatXZMoaqo9iE4Ks6
7yHqL2al+02yrMjGgevbbzP2VYyHoR9SmZm41EBbXbj/g95Kw9jdHn1wPP44o7p1
xUvOxeR8F3/DHCLXImURXiGdadEdxwQQ7NajhFbBWRu0PlrxwWnqaB+wgXygC4QR
zn8J70H6oHOzKW+bpotpKx2pVXZ8YAXaZgi7k3L4CyXAfYYizw==
=YlwY
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptVerifyFileDualSignatories.asc 0000664 0001750 0001750 00000045422 14203233501 025077 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (GNU/Linux)
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
rW5YqUDVQaR2
=/muA
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptVerifyFileNoPassphrase.asc 0000664 0001750 0001750 00000045163 14203233501 024412 0 ustar alec alec -----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.9 (GNU/Linux)
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
=Kbhy
-----END PGP MESSAGE-----
Crypt_GPG-1.6.7/tests/data-files/testDecryptVerifyFileToString.asc 0000664 0001750 0001750 00000002056 14203233501 023547 0 ustar alec alec -----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.6.7/tests/data-files/testFileEmpty.plain 0000664 0001750 0001750 00000000000 14203233501 020674 0 ustar alec alec Crypt_GPG-1.6.7/tests/data-files/testFileMedium.plain 0000664 0001750 0001750 00000140234 14203233501 021034 0 ustar alec alec 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.
Crypt_GPG-1.6.7/tests/data-files/testFileSmall.plain 0000664 0001750 0001750 00000000033 14203233501 020654 0 ustar alec alec Hello, Alice! Goodbye, Bob! Crypt_GPG-1.6.7/tests/data-files/testImportKeyFile_private.asc 0000664 0001750 0001750 00000003654 14203233501 022740 0 ustar alec alec -----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.6.7/tests/data-files/testImportKeyFile_public.asc 0000664 0001750 0001750 00000003347 14203233501 022543 0 ustar alec alec -----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.6.7/tests/data-files/testVerifyFileClearsignedData.asc 0000664 0001750 0001750 00000140610 14203233501 023454 0 ustar alec alec -----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.6.7/tests/data-files/testVerifyFileDualClearsignedData.asc 0000664 0001750 0001750 00000140741 14203233501 024267 0 ustar alec alec -----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.6.7/tests/data-files/testVerifyFileDualNormalSignedData.asc 0000664 0001750 0001750 00000044644 14203233501 024436 0 ustar alec alec -----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.6.7/tests/data-files/testVerifyFileNormalSignedData.asc 0000664 0001750 0001750 00000044402 14203233501 023620 0 ustar alec alec -----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.6.7/tests/config.php.dist 0000664 0001750 0001750 00000001205 14203233501 015770 0 ustar alec alec
* @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.6.7/tests/DecryptAndVerifyTest.php 0000664 0001750 0001750 00000143350 14203233501 017653 0 ustar alec alec
* $ 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, see
*
*
* @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 DecryptAndVerifyTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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);
}
/**
* @group string
*/
public function testDecryptVerifyKeyNotFoundException_decrypt()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// was encrypted with missing-key@example.com, signed with
// first-keypair@example.com
// {{{ encrypted data
$encryptedData = <<gpg->decryptAndVerify($encryptedData);
}
/**
* @group string
*/
public function testDecryptVerifyKeyNotFoundException_verify()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// 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);
}
/**
* @group string
*/
public function testDecryptVerifyKeyNotFoundException_both()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// was encrypted and signed with missing-key@example.com
// {{{ encrypted data
$encryptedData = <<gpg->decryptAndVerify($encryptedData);
}
/**
* @group string
*/
public function testDecryptVerifyKeyNotFoundIgnoreVerifyErrors()
{
$signature = new Crypt_GPG_Signature();
$signature->setKeyId('8E3D36B1EA5AC75E');
$expectedResults = array(
'data' => 'Hello, Alice! Goodbye, Bob!',
'signatures' => array($signature)
);
// was encrypted with first-keypair@example.com, signed with
// missing-key@example.com
// {{{ encrypted data
$encryptedData = <<gpg = new Crypt_GPG($this->getOptions());
$this->gpg->addDecryptKey('first-keypair@example.com', 'test1');
$results = $this->gpg->decryptAndVerify($encryptedData, true);
$this->assertDecryptAndVerifyResultsEquals($expectedResults, $results);
}
/**
* @group string
*/
public function testDecryptVerifyNoDataException_invalid()
{
$this->expectException('Crypt_GPG_NoDataException');
$encryptedData = 'Invalid OpenPGP data.';
$this->gpg->decryptAndVerify($encryptedData);
}
/**
* @group string
*/
public function testDecryptVerifyNoDataException_empty()
{
$this->expectException('Crypt_GPG_NoDataException');
$encryptedData = '';
$this->gpg->decryptAndVerify($encryptedData);
}
/**
* @group string
*/
public function testDecryptVerifyBadPassphraseException_missing()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// encrypted with first-keypair@example.com, signed with
// first-keypair@example.com
// {{{ encrypted data no passphrase
$encryptedData = <<gpg->decryptAndVerify($encryptedData);
}
/**
* @group string
*/
public function testDecryptVerifyBadPassphraseException_bad()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// 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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group string
*/
public function testDecryptAndVerifyDualNoPassphraseKeyMissing()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// encrypted with both first-keypair@example.com and
// second-keypair@example.com
// {{{ dual encrypted data
$encryptedData = <<gpg->deletePrivateKey('first-keypair@example.com');
$this->gpg->decryptAndVerify($encryptedData);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group file
*/
public function testDecryptVerifyFileFileException_input()
{
$this->expectException('Crypt_GPG_FileException');
// input file does not exist
$inputFilename = $this->getDataFilename(
'testDecryptVerifyFileFileException_input.asc'
);
$this->gpg->decryptAndVerifyFile($inputFilename);
}
/**
* @group file
*/
public function testDecryptVerifyFileFileException_output()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @group file
*/
public function testDecryptVerifyFileKeyNotFoundException_decrypt()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// 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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group file
*/
public function testDecryptVerifyFileNoDataException()
{
$this->expectException('Crypt_GPG_NoDataException');
$filename = $this->getDataFilename('testFileEmpty.plain');
$this->gpg->decryptAndVerifyFile($filename);
}
/**
* @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.6.7/tests/DecryptTest.php 0000664 0001750 0001750 00000061754 14203233501 016052 0 ustar alec alec
* $ 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, see
*
*
* @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 DecryptTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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);
}
/**
* @group string
*/
public function testDecryptKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// was encrypted with missing-key@example.com
// {{{ encrypted data
$encryptedData = <<gpg->decrypt($encryptedData);
}
/**
* @group string
*/
public function testDecryptNoDataException_invalid()
{
$this->expectException('Crypt_GPG_NoDataException');
$encryptedData = 'Invalid OpenPGP data.';
$this->gpg->decrypt($encryptedData);
}
/**
* @group string
*/
public function testDecryptNoDataException_empty()
{
$this->expectException('Crypt_GPG_NoDataException');
$encryptedData = '';
$this->gpg->decrypt($encryptedData);
}
/**
* @group string
*/
public function testDecryptBadPassphraseException_missing()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// encrypted with first-keypair@example.com
// {{{ encrypted data
$encryptedData = <<gpg->decrypt($encryptedData);
}
/**
* @group string
*/
public function testDecryptBadPassphraseException_bad()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// encrypted with first-keypair@example.com
// {{{ encrypted data
$encryptedData = <<gpg->addDecryptKey('first-keypair@example.com', 'incorrect');
$this->gpg->decrypt($encryptedData);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group string
*/
public function testDecryptDualNoPassphraseKeyMissing()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
// encrypted with both first-keypair@example.com and
// second-keypair@example.com
// {{{ dual encrypted data
$encryptedData = <<gpg->deletePrivateKey('first-keypair@example.com');
$this->gpg->decrypt($encryptedData);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group file
*/
public function testDecryptFileFileException_input()
{
$this->expectException('Crypt_GPG_FileException');
// input file does not exist
$inputFilename =
$this->getDataFilename('testDecryptFileFileException_input.asc');
$this->gpg->decryptFile($inputFilename);
}
/**
* @group file
*/
public function testDecryptFileFileException_output()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @group file
*/
public function testDecryptFileKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
// file is encrypted with missing-key@example.com
$inputFilename =
$this->getDataFilename('testDecryptFileKeyNotFoundException.asc');
$outputFilename =
$this->getTempFilename('testDecryptFileKeyNotFoundException.plain');
$this->gpg->decryptFile($inputFilename, $outputFilename);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group file
*/
public function testDecryptFileNoDataException()
{
$this->expectException('Crypt_GPG_NoDataException');
$filename = $this->getDataFilename('testFileEmpty.plain');
$this->gpg->decryptFile($filename);
}
/**
* @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.6.7/tests/DeletePrivateKeyTest.php 0000664 0001750 0001750 00000010121 14203233501 017624 0 ustar alec alec
* $ 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, see
*
*
* @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 DeletePrivateKeyTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @group delete-private
*/
public function testDeletePrivateKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$keyId = 'non-existent-key@example.com';
$this->gpg->deletePrivateKey($keyId);
}
/**
* @group delete-private
*/
public function testDeletePrivateKeyNotFoundException_public_only()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$keyId = 'public-only@example.com';
$this->gpg->deletePrivateKey($keyId);
}
}
Crypt_GPG-1.6.7/tests/DeletePublicKeyTest.php 0000664 0001750 0001750 00000006656 14203233501 017452 0 ustar alec alec
* $ 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, see
*
*
* @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 DeletePublicKeyTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @group delete-public
*/
public function testDeletePublicKeyDeletePrivateKeyException()
{
$this->expectException('Crypt_GPG_DeletePrivateKeyException');
// GnuPG 2.1(.11) allows public key deletion in this case
if (version_compare($this->gpg->getVersion(), '2.1.0', 'ge')) {
$this->markTestSkipped('GnuPG >= 2.1 allows public key deletion if private key exists.');
}
$keyId = 'first-keypair@example.com';
$this->gpg->deletePublicKey($keyId);
}
/**
* @group delete-public
*/
public function testDeletePublicKey_privExists()
{
// GnuPG 2.1(.11) allows public key deletion in this case
if (version_compare($this->gpg->getVersion(), '2.1.0', 'lt')) {
$this->markTestSkipped('GnuPG >= 2.1 allows public key deletion if private key exists.');
}
$keyId = 'first-keypair@example.com';
$this->gpg->deletePublicKey($keyId);
$this->assertTrue(true);
}
/**
* @group delete-public
*/
public function testDeletePublicKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$keyId = 'non-existent-key@example.com';
$this->gpg->deletePublicKey($keyId);
}
}
Crypt_GPG-1.6.7/tests/EncryptAndSignTest.php 0000664 0001750 0001750 00000036151 14203233501 017321 0 ustar alec alec
* $ 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, see
*
*
* @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 EncryptAndSignTest extends Crypt_GPG_TestCase
{
/**
* @group string
*/
public function testEncryptAndSignKeyNotFoundException_invalid_sign_key()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('non-existent-key@example.com');
$this->gpg->addEncryptKey('first-keypair@example.com');
$this->gpg->encryptAndSign($data);
}
/**
* @group string
*/
public function testEncryptAndSignKeyNotFoundException_no_sign_key()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addEncryptKey('first-keypair@example.com');
$this->gpg->encryptAndSign($data);
}
/**
* @group string
*/
public function testEncryptAndSignKeyNotFoundException_invalid_encrypt_key()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$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);
}
/**
* @group string
*/
public function testEncryptAndSignKeyNotFoundException_no_encrypt_key()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('first-keypair@example.com', 'test1');
$this->gpg->encryptAndSign($data);
}
/**
* @group string
*/
public function testEncryptAndSignBadPassphraseException_missing_sign_key()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('first-keypair@example.com');
$this->gpg->addEncryptKey('first-keypair@example.com');
$this->gpg->encryptAndSign($data);
}
/**
* @group string
*/
public function testEncryptAndSignBadPassphraseException_bad_sign_key()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('first-keypair@example.com', 'incorrect');
$this->gpg->addEncryptKey('first-keypair@example.com');
$this->gpg->encryptAndSign($data);
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @group file
*/
public function testEncryptAndSignFileFileException_input()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @group file
*/
public function testEncryptAndSignFileFileException_output()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @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.6.7/tests/EncryptTest.php 0000664 0001750 0001750 00000020277 14203233501 016057 0 ustar alec alec
* $ 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, see
*
*
* @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 EncryptTest extends Crypt_GPG_TestCase
{
public function testHasEncryptKeys()
{
$this->assertFalse($this->gpg->hasEncryptKeys());
$this->gpg->addEncryptKey('no-passphrase@example.com');
$this->assertTrue($this->gpg->hasEncryptKeys());
}
/**
* @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);
}
/**
* @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);
}
/**
* @group string
*/
public function testEncryptNotFoundException_invalid()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addEncryptKey('non-existent-key@example.com');
$this->gpg->encrypt($data);
}
/**
* @group string
*/
public function testEncryptNotFoundException_none()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->encrypt($data);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group file
*/
public function testEncryptFileFileException_input()
{
$this->expectException('Crypt_GPG_FileException');
// input file does not exist
$filename =
$this->getDataFilename('testEncryptFileFileException_input.plain');
$this->gpg->addEncryptKey('first-keypair@example.com');
$this->gpg->encryptFile($filename);
}
/**
* @group file
*/
public function testEncryptFileFileException_output()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @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.6.7/tests/ExceptionsTest.php 0000664 0001750 0001750 00000015453 14203233501 016554 0 ustar alec alec
* $ 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, see
*
*
* @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 ExceptionsTest extends Crypt_GPG_TestCase
{
/**
* @group exception
*/
public function testException()
{
$this->expectException('Crypt_GPG_Exception');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_Exception('test exception');
}
/**
* @group file-exception
*/
public function testFileException()
{
$this->expectException('Crypt_GPG_FileException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_FileException('test exception');
}
/**
* @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());
}
/**
* @group open-subprocess-exception
*/
public function testOpenSubprocessException()
{
$this->expectException('Crypt_GPG_OpenSubprocessException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_OpenSubprocessException('test exception');
}
/**
* @group open-subprocess-exception
*/
public function testOpenSubprocessException_getCommand()
{
$e = new Crypt_GPG_OpenSubprocessException('test exception', 0,
'gpg --verify');
$this->assertEquals('gpg --verify', $e->getCommand());
}
/**
* @group invalid-operation-exception
*/
public function testInvalidOperationException()
{
$this->expectException('Crypt_GPG_InvalidOperationException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_InvalidOperationException('test exception');
}
/**
* @group invalid-operation-exception
*/
public function testInvalidOperationException_getOperation()
{
$e = new Crypt_GPG_InvalidOperationException('test exception', 0,
'--verify');
$this->assertEquals('--verify', $e->getOperation());
}
/**
* @group key-not-found-exception
*/
public function testKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_KeyNotFoundException('test exception');
}
/**
* @group key-not-found-exception
*/
public function testKeyNotFoundException_getKeyId()
{
$e = new Crypt_GPG_KeyNotFoundException('test exception', 0,
'9F93F9116728EF12');
$this->assertEquals('9F93F9116728EF12', $e->getKeyId());
}
/**
* @group no-data-exception
*/
public function testNoDataException()
{
$this->expectException('Crypt_GPG_NoDataException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_NoDataException('test exception');
}
/**
* @group bad-passphrase-exception
*/
public function testBadPassphraseException()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_BadPassphraseException('test exception');
}
/**
* @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);
}
/**
* @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);
}
/**
* @group delete-private-key-exception
*/
public function testDeletePrivateKeyException()
{
$this->expectException('Crypt_GPG_DeletePrivateKeyException');
$this->expectExceptionMessage('test exception');
throw new Crypt_GPG_DeletePrivateKeyException('test exception');
}
/**
* @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.6.7/tests/ExportPrivateKeyTest.php 0000664 0001750 0001750 00000007647 14203233501 017726 0 ustar alec alec
* $ phpunit ExportPrivateKeyTestCase
*
*
* 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, see
*
*
* @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 ExportPrivateKeyTest extends Crypt_GPG_TestCase
{
/**
* @group export
*/
public function testExportPrivateKey()
{
$keyId = 'no-passphrase@example.com';
// We can't expect the key data to be identical as the one
// at the creation time, so we only check if it's valid format
$expectedKeyData = "-----END PGP PRIVATE KEY BLOCK-----\n";
// Note: This operation expects passphrase in GnuPG 2.1 < 2.1.15
// because of https://bugs.gnupg.org/gnupg/issue2070.
$keyData = $this->gpg->exportPrivateKey($keyId);
$this->assertStringEndsWith($expectedKeyData, $keyData);
}
/**
* @group export
*/
public function testExportPrivateKey_with_good_pass()
{
if (version_compare($this->gpg->getVersion(), '2.1.0', 'lt')) {
$this->markTestSkipped('GnuPG >= 2.1 requires passphrase to export private key.');
}
$keyId = 'first-keypair@example.com';
// This operation requires passphrase in GnuPG 2.1
$this->gpg->addPassphrase('94C06363', 'test1');
$keyData = $this->gpg->exportPrivateKey($keyId);
// Here we're really testing only the passphrase handling in GnuPG 2.1
$this->assertStringStartsWith('-----BEGIN PGP PRIVATE KEY BLOCK-----', $keyData);
}
/**
* @group export
*/
public function testExportPrivateKey_with_bad_pass()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
if (version_compare($this->gpg->getVersion(), '2.1.0', 'lt')) {
$this->markTestSkipped('GnuPG >= 2.1 requires passphrase to export private key.');
}
$keyId = 'first-keypair@example.com';
// This operation requires passphrase in GnuPG 2.1
$this->gpg->addPassphrase('94C06363', 'bad');
$keyData = $this->gpg->exportPrivateKey($keyId);
}
/**
* @group export
*/
public function testExportPrivateKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$keyId = 'non-existent-key@example.com';
$this->gpg->exportPrivateKey($keyId);
}
}
Crypt_GPG-1.6.7/tests/ExportPublicKeyTest.php 0000664 0001750 0001750 00000005050 14203233501 017514 0 ustar alec alec
* $ 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, see
*
*
* @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 ExportPublicKeyTest extends Crypt_GPG_TestCase
{
/**
* @group export
*/
public function testExportPublicKey()
{
$keyId = 'public-only@example.com';
// We can't expect the key data to be identical as the one
// at the creation time, so we only check if it's valid format
$expectedKeyData = "-----END PGP PUBLIC KEY BLOCK-----\n";
$keyData = $this->gpg->exportPublicKey($keyId);
$this->assertStringEndsWith($expectedKeyData, $keyData);
}
/**
* @group export
*/
public function testExportPublicKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$keyId = 'non-existent-key@example.com';
$this->gpg->exportPublicKey($keyId);
}
}
Crypt_GPG-1.6.7/tests/GeneralTest.php 0000664 0001750 0001750 00000015512 14203233501 016004 0 ustar alec alec
* $ 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, see
*
*
* @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 GeneralTest extends Crypt_GPG_TestCase
{
public function testPublicKeyringFileException()
{
$this->expectException('Crypt_GPG_FileException');
$publicKeyringFile = $this->getTempFilename('pubring.gpg');
new Crypt_GPG(
array(
'publicKeyring' => $publicKeyringFile
)
);
}
public function testPrivateKeyringFileException()
{
$this->expectException('Crypt_GPG_FileException');
$privateKeyringFile = $this->getTempFilename('secring.gpg');
new Crypt_GPG(
array(
'privateKeyring' => $privateKeyringFile
)
);
}
public function testTrustDatabaseFileException()
{
$this->expectException('Crypt_GPG_FileException');
$trustDbFile = $this->getTempFilename('secring.gpg');
new Crypt_GPG(
array(
'trustDb' => $trustDbFile
)
);
}
public function testHomedirFileException_NoCreate()
{
$this->expectException('Crypt_GPG_FileException');
$this->expectExceptionMessage('cannot be created');
if (posix_getuid() === 0) {
$this->markTestSkipped('Root can write to any homedir.');
}
$nonCreatableDirectory = '//.gnupg';
new Crypt_GPG(array('homedir' => $nonCreatableDirectory));
}
public function testHomedirFileException_NoExecute()
{
$this->expectException('Crypt_GPG_FileException');
$this->expectExceptionMessage('is not enterable');
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));
}
public function testHomedirFileException_NoWrite()
{
$this->expectException('Crypt_GPG_FileException');
$this->expectExceptionMessage('is not writable');
if (posix_getuid() === 0) {
$this->markTestSkipped('Root can write to any homedir.');
}
$nonWriteableDirectory = $this->getTempFilename('home-no-write');
mkdir($nonWriteableDirectory);
chmod($nonWriteableDirectory, 0500); // r-x --- ---
new Crypt_GPG(array('homedir' => $nonWriteableDirectory));
}
public function testBinaryPEARException()
{
$this->expectException('PEAR_Exception');
new Crypt_GPG(array('binary' => './non-existent-binary'));
}
public function testGPGBinaryPEARException()
{
$this->expectException('PEAR_Exception');
new Crypt_GPG(array('gpgBinary' => './non-existent-binary'));
}
public function testSetEngine()
{
$engine = new Crypt_GPG_Engine($this->getOptions());
$gpg = new Crypt_GPG();
$gpg->setEngine($engine);
$this->assertSame($this->getPropertyValue('Crypt_GPG', $gpg, 'engine'), $engine);
}
/**
* @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.6.7/tests/GetFingerprintTest.php 0000664 0001750 0001750 00000006350 14203233501 017356 0 ustar alec alec
* $ 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, see
*
*
* @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 GetFingerprintTest extends Crypt_GPG_TestCase
{
/**
* @group get-fingerprint
*/
public function testGetFingerprint()
{
$keyId = 'public-only@example.com';
$expectedFingerprint = 'F83118CB6F5892DC1C3E936DABA81EF54E8C0DEB';
$fingerprint = $this->gpg->getFingerprint($keyId);
$this->assertEquals($expectedFingerprint, $fingerprint);
}
/**
* @group get-fingerprint
*/
public function testGetFingerprintNull()
{
$keyId = 'non-existent-key@example.com';
$fingerprint = $this->gpg->getFingerprint($keyId);
$this->assertNull($fingerprint);
}
/**
* @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);
}
/**
* @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.6.7/tests/GetKeysTest.php 0000664 0001750 0001750 00000026337 14203233501 016011 0 ustar alec alec
* $ 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, see
*
*
* @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 GetKeysTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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);
}
/**
* @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.6.7/tests/ImportKeyTest.php 0000664 0001750 0001750 00000043363 14203233501 016357 0 ustar alec alec
* $ 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, see
*
*
* @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 ImportKeyTest extends Crypt_GPG_TestCase
{
public function setUp(): void
{
parent::setUp();
// In GnuPG 2.1 first operation on a keyring in v1 format
// will cause format update and several IMPORT_OK responses
// This way we clean the state first
$this->gpg->getKeys();
}
/**
* @group string
*/
public function testImportKey_private()
{
// Note: Some of GnuPG 2.1.x versions return different private_imported
// and private_uchanged values, bug? GnuPG 2.1.15 returns 1 as expected.
$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);
}
/**
* @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);
}
/**
* @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' => version_compare($this->gpg->getVersion(), '2.1.0', 'ge') ? 1 : 0,
'private_imported' => 0,
'private_unchanged' => 1,
);
$this->assertEquals($expectedResult, $result);
}
/**
* @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);
}
/**
* @group string
*/
public function testImportKeyNoDataException_invalid()
{
$this->expectException('Crypt_GPG_NoDataException');
$keyData = 'Invalid OpenPGP data.';
$this->gpg->importKey($keyData);
}
/**
* @group string
*/
public function testImportKeyNoDataException_empty()
{
$this->expectException('Crypt_GPG_NoDataException');
$keyData = '';
$this->gpg->importKey($keyData);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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' => version_compare($this->gpg->getVersion(), '2.1.0', 'ge') ? 1 : 0,
'private_imported' => 0,
'private_unchanged' => 1,
);
$this->assertEquals($expectedResult, $result);
}
/**
* @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);
}
/**
* @group file
*/
public function testImportKeyFileFileException()
{
$this->expectException('Crypt_GPG_FileException');
// input file does not exist
$filename =
$this->getDataFilename('testImportKeyFileFileException.asc');
$this->gpg->importKeyFile($filename);
}
/**
* @group file
*/
public function testImportKeyFileNoDataException()
{
$this->expectException('Crypt_GPG_NoDataException');
$filename = $this->getDataFilename('testFileEmpty.plain');
$this->gpg->importKeyFile($filename);
}
}
Crypt_GPG-1.6.7/tests/KeyGeneratorTest.php 0000664 0001750 0001750 00000064353 14203233501 017035 0 ustar alec alec
* $ 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, see
*
*
* @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 KeyGeneratorTest extends Crypt_GPG_TestCase
{
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.'
);
}
public function setUp(): void
{
parent::setUp();
$this->generator = new Crypt_GPG_KeyGenerator($this->getOptions());
}
/**
* @group mutators
*/
public function testSetExpirationDate_zero()
{
$expectedDate = 0;
$this->generator->setExpirationDate(0);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'expirationDate');
$this->assertSame($expectedDate, $value, 'Setting expiration date to zero failed.');
}
/**
* @group mutators
*/
public function testSetExpirationDate_integer()
{
$expectedDate = 2000000000;
$this->generator->setExpirationDate(2000000000);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'expirationDate');
$this->assertSame($expectedDate, $value, 'Setting expiration date by integer failed.');
}
/**
* @group mutators
*/
public function testSetExpirationDate_string()
{
date_default_timezone_set('UTC');
$expectedDate = 2000000000;
$this->generator->setExpirationDate('2033-05-18T03:33:20');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'expirationDate');
$this->assertSame($expectedDate, $value, 'Setting expiration date by string failed.');
}
/**
* @group mutators
*/
public function testSetExpirationDate_invalid_format()
{
$this->expectException('InvalidArgumentException');
date_default_timezone_set('UTC');
$this->generator->setExpirationDate('this is not a date');
}
/**
* @group mutators
*/
public function testSetExpirationDate_too_early_date()
{
$this->expectException('InvalidArgumentException');
$this->generator->setExpirationDate(1301088055);
}
/**
* @group mutators
*/
public function testSetExpirationDate_today()
{
$this->expectException('InvalidArgumentException');
$this->generator->setExpirationDate(time());
}
/**
* @group mutators
*/
public function testSetExpirationDate_too_late_date()
{
$this->expectException('InvalidArgumentException');
$this->generator->setExpirationDate(2147483648);
}
/**
* @group mutators
*/
public function testSetPassphrase()
{
$expectedPassphrase = 'test1';
$this->generator->setPassphrase('test1');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'passphrase');
$this->assertSame($expectedPassphrase, $value, 'Setting passphrase failed.');
}
/**
* @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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keySize');
$this->assertSame($expectedSize, $value, 'Setting key algorithm changed key size.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyUsage');
$this->assertSame($expectedUsage, $value, 'Setting key algorithm changed key usage.');
}
/**
* @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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keySize');
$this->assertSame($expectedSize, $value, 'Setting key size failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyUsage');
$this->assertSame($expectedUsage, $value, 'Setting key algorithm and size changed key 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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keySize');
$this->assertSame($expectedSize, $value, 'Setting key size failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'keyUsage');
$this->assertSame($expectedUsage, $value, 'Setting key algorithm and size changed key usage.');
}
/**
* @group mutators
*/
public function testSetKeyParams_invalid_algorithm()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
$this->generator->setKeyParams(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC);
}
/**
* @group mutators
*/
public function testSetKeyParams_invalid_dsa_usage()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
$this->generator->setKeyParams(
Crypt_GPG_SubKey::ALGORITHM_DSA,
2048,
Crypt_GPG_SubKey::USAGE_ENCRYPT | Crypt_GPG_SubKey::USAGE_CERTIFY
);
}
/**
* @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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting sub-key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeySize');
$this->assertSame($expectedSize, $value, 'Setting sub-key algorithm changed key size.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyUsage');
$this->assertSame($expectedUsage, $value, 'Setting sub-key algorithm changed key usage.');
}
/**
* @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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting sub-key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeySize');
$this->assertSame($expectedSize, $value, 'Setting sub-key algorithm changed key size.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyUsage');
$this->assertSame($expectedUsage, $value, 'Setting sub-key algorithm changed key 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
);
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyAlgorithm');
$this->assertSame($expectedAlgorithm, $value, 'Setting sub-key algorithm failed.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeySize');
$this->assertSame($expectedSize, $value, 'Setting sub-key algorithm changed key size.');
$value = $this->getPropertyValue('Crypt_GPG_KeyGenerator', $this->generator, 'subKeyUsage');
$this->assertSame($expectedUsage, $value, 'Setting sub-key algorithm changed key usage.');
}
/**
* @group mutators
*/
public function testSetSubKeyParams_invalid_elgamal_usage()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
$this->generator->setSubKeyParams(
Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC,
2048,
Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT
);
}
/**
* @group mutators
*/
public function testSetSubKeyParams_invalid_dsa_usage()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
$this->generator->setSubKeyParams(
Crypt_GPG_SubKey::ALGORITHM_DSA,
2048,
Crypt_GPG_SubKey::USAGE_SIGN | Crypt_GPG_SubKey::USAGE_ENCRYPT
);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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 '
)
);
// @TODO: I've got difference in expiration dates here
$this->assertKeyEquals($expectedKey, $key);
}
/**
* @group generate-key
*/
public function testGenerateKeyWithInvalidPrimaryKeyAlgorithm()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
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 '
)
);
}
/**
* @group generate-key
*/
public function testGenerateKeyWithInvalidSubKeyAlgorithm()
{
$this->expectException('Crypt_GPG_InvalidKeyParamsException');
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 '
)
);
}
}
Crypt_GPG-1.6.7/tests/KeyTest.php 0000664 0001750 0001750 00000041744 14203233501 015165 0 ustar alec alec
* $ 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, see
*
*
* @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 KeyTest extends Crypt_GPG_TestCase
{
/**
* @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.');
}
/**
* @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.');
}
/**
* @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.');
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @group accessors
*/
public function test__toString()
{
$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
));
$this->assertSame((string) $key, '');
$key->addSubKey($firstSubKey);
$this->assertSame((string) $key, $firstSubKey->getId());
}
/**
* @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.');
}
/**
* @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.');
}
/**
* @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.6.7/tests/phpunit.xml 0000664 0001750 0001750 00000000332 14203233501 015261 0 ustar alec alec .%3A..
Crypt_GPG-1.6.7/tests/SignatureCreationInfoTest.php 0000664 0001750 0001750 00000004713 14203233501 020672 0 ustar alec alec
*
* @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';
//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.6.7/tests/SignatureTest.php 0000664 0001750 0001750 00000041655 14203233501 016377 0 ustar alec alec
* $ 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, see
*
*
* @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 SignatureTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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()));
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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.6.7/tests/SignTest.php 0000664 0001750 0001750 00000042544 14203233501 015334 0 ustar alec alec
* $ 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, see
*
*
* @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 SignTest extends Crypt_GPG_TestCase
{
public function testHasSignKeys()
{
$this->assertFalse($this->gpg->hasSignKeys());
$this->gpg->addSignKey('no-passphrase@example.com');
$this->assertTrue($this->gpg->hasSignKeys());
}
/**
* @group string
*/
public function testSignKeyNotFoundException_invalid()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('non-existent-key@example.com');
$this->gpg->sign($data);
}
/**
* @group string
*/
public function testSignKeyNotFoundException_none()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->sign($data);
}
/**
* @group string
*/
public function testSignBadPassphraseException_missing()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('first-keypair@example.com');
$this->gpg->sign($data);
}
/**
* @group string
*/
public function testSignBadPassphraseException_bad()
{
$this->expectException('Crypt_GPG_BadPassphraseException');
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('first-keypair@example.com', 'incorrect');
$this->gpg->sign($data);
}
/**
* @group string
*/
public function testSignNoPassphrase()
{
$this->gpg->setEngineOptions(array('sign' => '--emit-version'));
$data = 'Hello, Alice! Goodbye, Bob!';
$this->gpg->addSignKey('no-passphrase@example.com');
$signedData = $this->gpg->sign($data);
// Check if --emit-version option works
$this->assertTrue(strpos($signedData, 'Version:') !== false);
$this->gpg->setEngineOptions(array());
$signatures = $this->gpg->verify($signedData);
$this->assertEquals(1, count($signatures));
foreach ($signatures as $signature) {
$this->assertTrue($signature->isValid());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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.'
);
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @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());
}
}
/**
* @group file
*/
public function testSignFileFileException_input()
{
$this->expectException('Crypt_GPG_FileException');
// input file does not exist
$inputFilename =
$this->getDataFilename('testSignFileFileFileException_input.plain');
$this->gpg->addSignKey('first-keypair@example.com', 'test1');
$this->gpg->signFile($inputFilename);
}
/**
* @group file
*/
public function testSignFileFileException_output()
{
$this->expectException('Crypt_GPG_FileException');
// 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);
}
/**
* @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());
}
}
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.6.7/tests/SubKeyTest.php 0000664 0001750 0001750 00000101046 14203233501 015627 0 ustar alec alec
* $ 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, see
*
*
* @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 SubKeyTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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);
}
/**
* @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' => 3321785858,
'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->assertFalse($subKey->canSign());
$this->assertTrue($subKey->canEncrypt());
$this->assertTrue($subKey->hasPrivate());
$this->assertTrue($subKey->isRevoked());
$this->assertSame('2008-09-19T00:57:38+00:00', $subKey->getCreationDateTime()->format('c'));
$this->assertSame('2075-04-06T14:17:38+00:00', $subKey->getExpirationDateTime()->format('c'));
$this->assertSame(1221785858, $subKey->getCreationDate());
// will fail on 32-bit
if (PHP_INT_MAX > 2147483647) {
$this->assertSame(3321785858, $subKey->getExpirationDate());
}
}
/**
* @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' => 3321785858,
'canSign' => false,
'canEncrypt' => true,
'isRevoked' => true
));
$string = 'sub:r:2048:16:8C37DBD2A01B7976:1221528655:3321785858:::::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());
}
/**
* @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);
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @group accessors
*/
public function testGetCreationDateTime()
{
$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->assertSame('2008-09-19T00:57:38+00:00', $subKey->getCreationDateTime()->format('c'));
$subKey = new Crypt_GPG_SubKey(array(
'id' => '8C37DBD2A01B7976',
'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC,
'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363',
'length' => 2048,
'creation' => 0,
'expiration' => 1421785858,
'canSign' => false,
'canEncrypt' => true,
'hasPrivate' => true
));
$this->assertSame(null, $subKey->getCreationDateTime());
}
/**
* @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());
}
/**
* @group accessors
*/
public function testGetExpirationDateTime()
{
$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->assertSame('2015-01-20T20:30:58+00:00', $subKey->getExpirationDateTime()->format('c'));
$subKey = new Crypt_GPG_SubKey(array(
'id' => '8C37DBD2A01B7976',
'algorithm' => Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC,
'fingerprint' => '8D2299D9C5C211128B32BBB0C097D9EC94C06363',
'length' => 2048,
'creation' => 0,
'expiration' => 0,
'canSign' => false,
'canEncrypt' => true,
'hasPrivate' => true
));
$this->assertSame(null, $subKey->getExpirationDateTime());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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.6.7/tests/TestCase.php 0000664 0001750 0001750 00000100511 14203233501 015274 0 ustar alec alec
*
* @category Encryption
* @package Crypt_GPG
* @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
*/
/**
* 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
{
const HOMEDIR = 'test-keychain';
const TEMPDIR = 'temp-files';
const DATADIR = 'data-files';
protected $gpg;
protected function getOptions()
{
$debugFunction = function ($text) {
file_put_contents(__DIR__ . '/debug.log', $text . "\n", FILE_APPEND);
};
$config = array(
'homedir' => __DIR__ . '/' . self::HOMEDIR,
// 'binary' => '/usr/bin/gpg2',
// 'agent' => '/usr/bin/gpg-agent',
// 'gpgconf' => '/usr/local/bin/gpgconf',
// 'cipher-algo' => 'AES256',
// 'digest-algo' => 'SHA512',
// 'compress-algo' => 'zip',
'debug' => $debugFunction,
// 'options' => array(),
);
if ($binary = getenv('TESTS_GPG_BINARY')) {
$config['binary'] = $binary;
}
return $config;
}
public function setUp(): void
{
// load test configuration file if it exists
$configFilename = __DIR__ . '/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());
}
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);
}
private function _setUpTempdir()
{
$directoryName = __DIR__ . '/' . self::TEMPDIR;
if (!file_exists($directoryName)) {
mkdir($directoryName);
}
}
public function tearDown(): void
{
unset($this->gpg);
$this->_tearDownKeyring();
$this->_tearDownTempdir();
}
private function _tearDownKeyring()
{
$dirnames = array(
$this->getKeyringFilename('private-keys-v1.d'),
$this->getKeyringFilename('openpgp-revocs.d')
);
foreach ($dirnames as $dirname) {
if (file_exists($dirname)) {
$iterator = new DirectoryIterator($dirname);
foreach ($iterator as $file) {
if (!$file->isDot()) {
$filename = $dirname . '/' . $file->getFilename();
if (file_exists($filename)) {
unlink($filename);
}
}
}
rmdir($dirname);
}
}
$homedir = __DIR__ . '/' . self::HOMEDIR;
$iterator = new DirectoryIterator($homedir);
foreach ($iterator as $file) {
if (!$file->isDot()) {
$filename = $homedir . '/' . $file->getFilename();
if (file_exists($filename)) {
unlink($filename);
}
}
}
rmdir($homedir);
}
private function _tearDownTempdir()
{
$directoryName = __DIR__ . '/' . 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 (file_exists($filename)) {
if (is_dir($filename)) {
rmdir($filename);
} else {
unlink($filename);
}
}
}
}
rmdir($directoryName);
}
protected function getMd5Sum($filename)
{
return md5_file($filename);
}
protected function getKeyringFilename($filename)
{
return __DIR__ . '/'. self::HOMEDIR . '/' . $filename;
}
protected function getDataFilename($filename)
{
return __DIR__ . '/'. self::DATADIR . '/' . $filename;
}
protected function getTempFilename($filename)
{
return __DIR__ . '/' . self::TEMPDIR . '/' . $filename;
}
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']
);
}
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]);
}
}
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.'
);
}
protected function getPropertyValue($class, $object, $property)
{
$reflectionClass = new ReflectionClass($class);
$prop = $reflectionClass->getProperty($property);
$prop->setAccessible(true);
return $prop->getValue($object);
}
/**
* This method is used only when we run tests under PHPUnit 4.8 via Github Actions
*/
protected function setExpectedExceptionMessage($message)
{
// do nothing
}
}
Crypt_GPG-1.6.7/tests/UserIdTest.php 0000664 0001750 0001750 00000032134 14203233501 015621 0 ustar alec alec
* $ 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, see
*
*
* @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 UserIdTest extends Crypt_GPG_TestCase
{
/**
* @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);
}
/**
* @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);
}
/**
* @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());
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @group parse
*/
public function testParseEmailOnly()
{
$expectedUserId = new Crypt_GPG_UserId(
array(
'name' => '',
'email' => 'test@example.com'
)
);
$string = '';
$userId = Crypt_GPG_UserId::parse($string);
$this->assertEquals($expectedUserId, $userId);
$string = 'test@example.com';
$userId = Crypt_GPG_UserId::parse($string);
$this->assertEquals($expectedUserId, $userId);
}
/**
* @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'
)
);
$this->assertEquals($expected, strval($userId));
}
/**
* @group to-string
*/
public function testToStringNameOnly()
{
$expected = 'Example User';
$userId = new Crypt_GPG_UserId(array('name' => 'Example User'));
$this->assertEquals($expected, strval($userId));
}
/**
* @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',
)
);
$this->assertEquals($expected, strval($userId));
}
/**
* @group to-string
*/
public function testToStringNameEmail()
{
$expected = 'Example User ';
$userId = new Crypt_GPG_UserId(
array(
'name' => 'Example User',
'email' => 'test@example.com'
)
);
$this->assertEquals($expected, strval($userId));
}
/**
* @group accessors
*/
public function testGetName()
{
$userId = new Crypt_GPG_UserId(
array(
'name' => 'Example User'
)
);
$this->assertEquals('Example User', $userId->getName());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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());
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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.6.7/tests/VerifyTest.php 0000664 0001750 0001750 00000063167 14203233501 015704 0 ustar alec alec
* $ 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, see
*
*
* @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 VerifyTest extends Crypt_GPG_TestCase
{
/**
* @group string
*/
public function testVerifyNoDataExceptionInvalid()
{
$this->expectException('Crypt_GPG_NoDataException');
$signedData = 'Invalid OpenPGP data.';
$this->gpg->verify($signedData);
}
/**
* @group string
*/
public function testVerifyNoDataExceptionEmpty()
{
$this->expectException('Crypt_GPG_NoDataException');
$signedData = '';
$this->gpg->verify($signedData);
}
/**
* @group string
*/
public function testVerifyKeyNotFoundException()
{
$this->expectException('Crypt_GPG_KeyNotFoundException');
$data = 'Hello, Alice! Goodbye, Bob!';
// {{{ detached signature
$detachedSignature = <<gpg->verify($data, $detachedSignature);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
}
/**
* @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);
$warnings = $this->gpg->getWarnings();
$this->assertTrue(is_array($warnings));
}
/**
* @group file
*/
public function testVerifyFileFileException()
{
$this->expectException('Crypt_GPG_FileException');
$filename = './non-existent/testVerifyFileFileException.asc';
$this->gpg->verifyFile($filename);
}
/**
* @group file
*/
public function testVerifyFileNoDataException()
{
$this->expectException('Crypt_GPG_NoDataException');
$filename = $this->getDataFilename('testFileEmpty.plain');
$this->gpg->verifyFile($filename);
}
}
Crypt_GPG-1.6.7/LICENSE 0000664 0001750 0001750 00000063616 14203233501 012731 0 ustar alec alec 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.6.7/README.md 0000664 0001750 0001750 00000002327 14203233501 013173 0 ustar alec alec # Crypt_GPG #
Crypt_GPG is a PHP package to interact with the [GNU Privacy Guard
(GnuPG)](https://www.gnupg.org/). GnuPG is a free and open-source
implementation of the [OpenPGP](https://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.
## Documentation ##
### Quick Example
```php
addEncryptKey('test@example.com');
$data = $gpg->encrypt('my secret data');
?>
```
### Further Documentation ###
* [High-Level Documentation](https://pear.php.net/manual/en/package.encryption.crypt-gpg.intro.php)
* [Detailed API Documentation](https://pear.php.net/package/Crypt_GPG/docs/latest/)
## Bugs and Issues ##
Please report all new issues via the [PEAR bug tracker](https://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`