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