137 Commits
0.0.1 ... 0.2.0

Author SHA1 Message Date
Stephen Paul Weber
f4fabd04e7 Merge pull request #9 from adecaneda/Partial-body-lengths
Support for Partial body lengths
2015-08-14 13:15:15 -05:00
adecaneda
cc52cb9dab Missing parameter in parse_old_format 2015-08-05 11:35:23 +02:00
adecaneda
4281c8fa97 Missing parameter 2015-08-05 11:18:28 +02:00
adecaneda
01a1f00edb Inclued partial body lengths
Partial body lengths based on https://github.com/toofishes/python-pgpdump/blob/master/pgpdump/packet.py
2015-08-05 10:54:57 +02:00
Stephen Paul Weber
4fe3c5db72 Merge pull request #8 from adecaneda/adecaneda-patch-1
Typo in variable $p->encrypted_data
2015-07-31 19:28:07 -05:00
adecaneda
9bffda3ef2 Update openpgp_crypt_rsa.php
Typo in variable $p->encrypted_data
2015-07-31 11:12:17 +02:00
Stephen Paul Weber
5291a06b97 Merge pull request #7 from Hoffstadt/patch-1
Changed require Crypt/RSA.php to require_once
2015-07-06 10:02:16 -05:00
Stephen Paul Weber
055b5c5459 Add clearsign example 2015-07-04 16:14:42 -05:00
Hoffstadt
cb4fe9c632 Changed require Crypt/RSA.php to require_once
This change allows the lib usage with an autoloader.
2015-06-18 13:32:51 +02:00
Stephen Paul Weber
4756c82118 Merge pull request #4 from vstm/composer-simple
Add composer.json
2015-03-16 15:04:34 -05:00
Stefan Vetsch
9d6d736a5d Add newline before end-of-file (PSR-2) 2015-03-15 21:55:40 +01:00
Stefan Vetsch
2fb1666bb5 Use composer to load dependencies 2015-03-14 19:36:35 +01:00
Stefan Vetsch
3835a48db8 Not needed at this point 2015-03-14 17:41:25 +01:00
Stefan Vetsch
ec8df93d19 Don't make a scene if there is no autoload.php (if someone isn't using composer). 2015-03-14 17:17:28 +01:00
Stefan Vetsch
6287ba89d0 Make use of the classmap, the current class/file structure does not allow for PSR-0 autoloading. 2015-03-14 13:22:14 +01:00
Stefan Vetsch
ae21dd0f56 Make autoload work for phpunit tests 2015-03-14 10:59:21 +01:00
Stefan Vetsch
68514c11c2 Add simple composer.json 2015-03-14 10:50:06 +01:00
Stephen Paul Weber
d6568d4925 Initial doxygen setup 2014-06-28 14:26:12 -05:00
Stephen Paul Weber
0262b038f1 Fix sign_key_userid 2014-06-28 12:27:25 -05:00
Stephen Paul Weber
775aa96118 Remove debug code 2014-06-28 11:38:14 -05:00
Stephen Paul Weber
d2913ccb8a Add support for CAST5 using mcrypt 2013-09-14 13:17:30 -05:00
Stephen Paul Weber
e1181bd25e Support for AES and 3DES are now optional 2013-09-14 11:45:49 -05:00
Stephen Paul Weber
6075d057d0 Use require_once in examples. 2013-09-14 11:41:46 -05:00
Stephen Paul Weber
82ed7d85bd Rename symmetric encrypt/decrypt class
I'm going to make this one more generic than one library, and have it
support ciphers based on what libraries are available, so this more
generic name is appropriate.
2013-09-14 11:36:58 -05:00
Stephen Paul Weber
7ae4d539f2 Better errors for unsupported ciphers. 2013-09-14 11:28:35 -05:00
Stephen Paul Weber
e78424131e Any secret key
Spews warnings, but that's fine for now
2013-06-24 14:34:00 -05:00
Stephen Paul Weber
e27f9e236f Full example of decrypting a message 2013-06-24 11:22:01 -05:00
Stephen Paul Weber
26860d3b98 Always an MPI for RSA 2013-06-24 11:21:26 -05:00
Stephen Paul Weber
c341d7f09e Fix byte encoding of some packets 2013-06-24 11:21:10 -05:00
Stephen Paul Weber
58d1b5cee0 Clean up encryptDecrypt example 2013-06-24 11:20:46 -05:00
Stephen Paul Weber
05b757ab6c No index anymore 2013-02-24 18:11:22 -05:00
Stephen Paul Weber
3afd401688 Whitespace and proper padAmount 2013-02-24 18:11:11 -05:00
Stephen Paul Weber
04b89decd1 Should not throw away the version 2013-02-24 18:10:57 -05:00
Stephen Paul Weber
1ecb990a02 Use key_from_input as originally intended 2013-02-24 18:10:46 -05:00
Stephen Paul Weber
778c83dbc3 Better pubring.gpg 2013-02-18 18:41:11 -05:00
Stephen Paul Weber
aab2a5e12b Data representation bugs in signature subpackets 2013-02-18 18:39:24 -05:00
Stephen Paul Weber
216ee4156d Add features to README 2013-01-26 17:19:14 -05:00
Stephen Paul Weber
2a331f7403 better random string 2013-01-26 17:14:38 -05:00
Stephen Paul Weber
cb9f918022 encrypt/decrypt example 2013-01-26 17:01:36 -05:00
Stephen Paul Weber
7d776fd605 Encryption support 2013-01-26 17:01:26 -05:00
Stephen Paul Weber
a56799955f Decrypt secret key 2013-01-26 14:55:51 -05:00
Stephen Paul Weber
ae062433b7 Fix for PHP 5.3 grammar 2013-01-26 14:15:09 -05:00
Stephen Paul Weber
cd15aec6f9 Asymmetric decryption 2013-01-26 14:00:00 -05:00
Stephen Paul Weber
641c07835b Support session keys 2013-01-26 11:26:55 -05:00
Stephen Paul Weber
8c60f4e37b Support the no-MDC (resync) case 2013-01-26 11:17:11 -05:00
Stephen Paul Weber
47a7f6e25c Keep trying on failure 2013-01-26 11:11:15 -05:00
Stephen Paul Weber
567b18c1b2 Support 3DES 2013-01-26 11:08:18 -05:00
Stephen Paul Weber
bf8201f432 Start work on decryption 2013-01-21 18:18:41 -05:00
Stephen Paul Weber
06cf887846 Forgot these data files 2013-01-21 16:00:18 -05:00
Stephen Paul Weber
68b2047508 Both kinds of EncryptedDataPacket 2013-01-21 15:33:46 -05:00
Stephen Paul Weber
dffa0ecaa2 Generalize S2K support, and support SymmetricSessionKeyPacket 2013-01-21 15:20:23 -05:00
Stephen Paul Weber
74afee6266 Test signing at all 2013-01-20 22:15:49 -05:00
Stephen Paul Weber
7a1510f2e1 Remove unsafe uses of reset 2013-01-20 21:49:48 -05:00
Stephen Paul Weber
4263d03188 Restructure signing code
All sorts of signatures can be verified now, and it is easier to extract
information from the verified signature packets.
2013-01-20 21:44:33 -05:00
Stephen Paul Weber
f9ea5ee0e5 Try without pear 2013-01-20 19:23:33 -05:00
Stephen Paul Weber
8d19f70bb1 dependencies for travis 2013-01-20 19:09:36 -05:00
Stephen Paul Weber
22585344c0 Message signature verification tests 2013-01-20 19:00:49 -05:00
Stephen Paul Weber
7d44211fc8 Clarify the verify example 2013-01-20 18:57:14 -05:00
Stephen Paul Weber
995a9d7840 Fingerprint tests 2013-01-20 17:51:37 -05:00
Stephen Paul Weber
f4af8a010b Remove unsafe use of array_pop 2013-01-20 17:41:37 -05:00
Stephen Paul Weber
825452e123 Support v3 sigs and keys properly 2013-01-20 17:34:08 -05:00
Stephen Paul Weber
c5600d2812 Enable meat of tests, all but one pass 2013-01-20 16:49:19 -05:00
Stephen Paul Weber
057c79440a poke travis 2013-01-20 14:48:22 -05:00
Stephen Paul Weber
5cba4f2697 Import Serialization tests from OpenPGP-Haskell 2013-01-20 14:41:37 -05:00
Stephen Paul Weber
ae7454c504 Example code for generating a self-signed key 2011-07-25 15:15:40 -05:00
Stephen Paul Weber
379c79d3ad Crypt_RSA wrapper for signing keys 2011-07-25 15:15:17 -05:00
Stephen Paul Weber
b84a2a8752 Allow using keys as data to sign over 2011-07-25 15:15:01 -05:00
Stephen Paul Weber
fb9fddde16 Working constructor for UserID 2011-07-25 15:14:45 -05:00
Stephen Paul Weber
4dbfbcb88d Working constructor for PublicKey 2011-07-25 15:13:24 -05:00
Stephen Paul Weber
6bf8e8cb6b UserIDPacket body 2011-07-25 12:51:08 -05:00
Stephen Paul Weber
c2c934fa6a Implement SecretKeyPacket output body 2011-07-25 12:46:50 -05:00
Stephen Paul Weber
69ade89111 refactor SecretKeyPacket read 2011-07-25 12:28:33 -05:00
Stephen Paul Weber
0f5742ba0d Implement output body for PublicKeyPacket 2011-07-25 12:23:00 -05:00
Stephen Paul Weber
dab71c1854 Implement FeaturesPacket 2011-07-25 12:06:21 -05:00
Stephen Paul Weber
82fb19cc31 Implement KeyFlagsPacket 2011-07-25 12:03:46 -05:00
Stephen Paul Weber
1322f45ded revert broken example script 2011-07-25 12:01:26 -05:00
Stephen Paul Weber
951ff2cacc use bitlength 2011-07-25 11:50:27 -05:00
Stephen Paul Weber
af3643c919 crc24 was not encoded 2011-04-28 08:10:10 -05:00
Stephen Paul Weber
6b8445737e Newline before crc24 on enarmor 2011-04-28 08:07:06 -05:00
Stephen Paul Weber
1f04075ef5 Example code on using the library 2011-04-23 09:20:17 -05:00
Stephen Paul Weber
6cbd7f6634 Check the actual format 2010-06-28 12:33:55 -05:00
Stephen Paul Weber
66ab5ccf46 Fingerprint calculation works on secret keys now 2010-06-28 12:33:42 -05:00
Stephen Paul Weber
377a86aee9 Added feature to the README 2010-04-01 18:42:28 -05:00
Stephen Paul Weber
5756085e85 Convenience function for expiry time of keys 2010-04-01 18:39:36 -05:00
Stephen Paul Weber
9cdc2500b1 Implement OpenPGP_SignaturePacket_KeyExpirationTimePacket 2010-04-01 18:39:04 -05:00
Stephen Paul Weber
99debc4540 Implement OpenPGP_SignaturePacket_SignatureExpirationTimePacket 2010-04-01 18:38:54 -05:00
Stephen Paul Weber
39e1d5c231 Conveniance function to get self signatures 2010-04-01 18:30:21 -05:00
Stephen Paul Weber
417c206bee Implement OpenPGP_SignaturePacket_EmbeddedSignaturePacket 2010-04-01 18:18:02 -05:00
Stephen Paul Weber
e931ebed25 Changes to allow using a set of keys (ie, key with subkeys) 2010-04-01 18:03:42 -05:00
Stephen Paul Weber
b42ec74ab4 Conveniance function to get issuer 2010-04-01 18:03:12 -05:00
Stephen Paul Weber
1e81ed0bb1 Wrapper to use OpenPGP with Crypt_RSA 2010-04-01 12:53:39 -05:00
Stephen Paul Weber
6dc7c1eb2a Abstract extracting a signature packet along with data 2010-04-01 12:51:45 -05:00
Stephen Paul Weber
191aeaa4d9 fingerprint works on secret key too 2010-04-01 12:50:08 -05:00
Stephen Paul Weber
0b2942e382 SignaturePacket method to do actual signing 2010-04-01 09:24:14 -05:00
Stephen Paul Weber
86c476807c Contructor for OpenPGP_SignaturePacket 2010-04-01 09:23:43 -05:00
Stephen Paul Weber
ec4b5c5f72 Generate SignaturePacket trailer 2010-04-01 09:22:37 -05:00
Stephen Paul Weber
1e2db5b249 This is the correct size 2010-04-01 09:22:08 -05:00
Stephen Paul Weber
1c7f759798 There may be no subpackets 2010-04-01 09:21:00 -05:00
Stephen Paul Weber
e3bc3757d1 Normalize before verifying 2010-04-01 09:20:27 -05:00
Stephen Paul Weber
fe7121efe3 Method for LiteralData normalization 2010-04-01 09:20:13 -05:00
Stephen Paul Weber
eb7aaf490e Ensure 2 hex digits per byte 2010-04-01 09:19:01 -05:00
Stephen Paul Weber
5829037d0b SignatureSubpacket constructor (for tag/type) 2010-04-01 09:17:40 -05:00
Stephen Paul Weber
36fba1596d Default packet constructor can take data 2010-04-01 09:17:09 -05:00
Stephen Paul Weber
6ac274b8ec Implement OpenPGP_SecretKeyPacket 2010-03-31 18:54:00 -05:00
Stephen Paul Weber
6e8dc4799f Constructor for OpenPGP_LiteralDataPacket 2010-03-31 17:15:11 -05:00
Stephen Paul Weber
8265522323 Function to verify signatures.
Call with a set of verifier callbacks and optionally the index of the
signature to verify (if there is more than one signature).
2010-03-31 14:26:16 -05:00
Stephen Paul Weber
3b6b29127f Get names for key/hash algorithm on signature 2010-03-31 14:26:16 -05:00
Stephen Paul Weber
bd9c9db00b Add publickey algorithm mappings 2010-03-31 14:26:16 -05:00
Stephen Paul Weber
8019d3c564 Add hash algorithm mappings 2010-03-31 14:26:16 -05:00
Stephen Paul Weber
b41bc2c533 Implement body for OpenPGP_CompressedDataPacket 2010-03-31 14:26:16 -05:00
Stephen Paul Weber
1a1b8980e6 No need to unwrap to an array
Since OpenPGP_Message implements the array interface
2010-03-31 14:26:14 -05:00
Stephen Paul Weber
975fc2ff7e Implement body for OpenPGP_OnePassSignaturePacket 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
0a85e214a6 Implement to_bytes for OpenPGP_Message 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
355ea44301 Set tag on packet creation 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
1333a1a035 unpack returns an array 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
acdf5d1ac0 Implement body for OpenPGP_SignaturePacket 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
408c912e12 Implement body for OpenPGP_SignaturePacket_IssuerPacket 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
7fc49b3530 Implement body for OpenPGP_SignaturePacket_SignatureCreationTimePacket 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
d4babbb948 Subpacket class for different header 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
5f6a93daca Type byte is part of body 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
97ad2cf72d CompressedDataPacket implements ArrayAccess 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
3c84dce8f9 LiteralDataPacket body 2010-03-31 14:25:21 -05:00
Stephen Paul Weber
a78b6dc8c1 Header calculation, body stub, and byte serialize 2010-03-31 14:25:11 -05:00
Stephen Paul Weber
b7122bbb5f Store the trailer for use in sig verification 2010-03-31 11:59:07 -05:00
Stephen Paul Weber
b0f4e73111 Use timestamp/mpi abstractions 2010-03-31 11:59:07 -05:00
Stephen Paul Weber
c7a5ec04fd That is done 2010-03-31 11:59:07 -05:00
Arto Bendiken
93569f967c Added a link to the Drupal project page. 2010-03-30 23:49:10 +02:00
Arto Bendiken
079eb984a7 Added Stephen Paul Weber as an author. 2010-03-30 23:48:03 +02:00
Stephen Paul Weber
8feb922a45 Implemented OpenPGP_SignaturePacket_SignatureCreationTimePacket 2010-03-30 14:46:37 -05:00
Stephen Paul Weber
417ac85088 Implemented OpenPGP_SignaturePacket_IssuerPacket 2010-03-30 14:46:36 -05:00
Stephen Paul Weber
2948aa3b77 Stub out signature subpackets 2010-03-30 14:46:33 -05:00
Stephen Paul Weber
4a287f7321 Add myself as an author 2010-03-30 13:38:28 -05:00
Stephen Paul Weber
f67dab6053 Implemented SignaturePacket 2010-03-30 13:23:35 -05:00
Stephen Paul Weber
f09335de1d Implement OnePassSignaturePacket 2010-03-30 13:23:25 -05:00
Stephen Paul Weber
e3f332c6ca Implement most of the "new" packet format 2010-03-30 13:04:32 -05:00
Stephen Paul Weber
dc7bc432ea Implement LiteralDataPacket 2010-03-30 12:56:50 -05:00
Stephen Paul Weber
73f93e70fd Implement CompressedDataPacket 2010-03-30 12:54:51 -05:00
116 changed files with 4451 additions and 50 deletions

6
.travis.yml Normal file
View File

@@ -0,0 +1,6 @@
language: php
php:
- "5.4"
- "5.3"
before_script:
- composer install --prefer-source --dev

View File

@@ -1 +1,2 @@
* Arto Bendiken <arto.bendiken@gmail.com> * Arto Bendiken <arto.bendiken@gmail.com>
* Stephen Paul Weber <singpolyma@singpolyma.net>

1890
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,15 @@ Features
* Encodes and decodes ASCII-armored OpenPGP messages. * Encodes and decodes ASCII-armored OpenPGP messages.
* Parses OpenPGP messages into their constituent packets. * Parses OpenPGP messages into their constituent packets.
* Supports both old-format (PGP 2.6.x) and new-format (RFC 4880) packets. * Supports both old-format (PGP 2.6.x) and new-format (RFC 4880) packets.
* Helper class for verifying, signing, encrypting, and decrypting messages using Crypt_RSA from <http://phpseclib.sourceforge.net>
* Helper class for encrypting and decrypting messages and keys using Crypt_AES and Crypt_TripleDES from <http://phpseclib.sourceforge.net>
Users
-----
OpenPGP.php is currently being used in the following projects:
* <http://drupal.org/project/openpgp>
Download Download
-------- --------
@@ -39,6 +48,7 @@ Authors
------- -------
* [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/> * [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
* [Stephen Paul Weber](mailto:singpolyma@singpolyma.net) - <http://singpolyma.net/>
License License
------- -------

24
composer.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "singpolyma/openpgp-php",
"description": "Pure-PHP implementation of the OpenPGP Message Format (RFC 4880)",
"license": "Unlicense",
"authors": [
{
"name": "Arto Bendiken",
"email": "arto.bendiken@gmail.com"
},
{
"name": "Stephen Paul Weber",
"email": "singpolyma@singpolyma.net"
}
],
"require": {
"phpseclib/phpseclib": "~0.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"autoload": {
"classmap": ["lib/"]
}
}

25
examples/clearsign.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
/* Parse secret key from STDIN, the key must not be password protected */
$wkey = OpenPGP_Message::parse(file_get_contents('php://stdin'));
$wkey = $wkey[0];
/* Create a new literal data packet */
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
/* Create a signer from the key */
$sign = new OpenPGP_Crypt_RSA($wkey);
/* The message is the signed data packet */
$m = $sign->sign($data);
/* Generate clearsigned data */
$packets = $m->signatures()[0];
echo "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA256\n\n";
echo preg_replace("/^-/", "- -", $packets[0]->data)."\n";
echo OpenPGP::enarmor($packets[1][0]->to_bytes(), "PGP SIGNATURE");
?>

View File

@@ -0,0 +1,27 @@
<?php
// USAGE: php examples/deASCIIdeCrypt.php secretkey.asc password message.asc
// This will fail if the algo on key or message is not 3DES or AES
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
$keyASCII = file_get_contents($argv[1]);
$msgASCII = file_get_contents($argv[3]);
$keyEncrypted = OpenPGP_Message::parse(OpenPGP::unarmor($keyASCII, 'PGP PRIVATE KEY BLOCK'));
// Try each secret key packet
foreach($keyEncrypted as $p) {
if(!($p instanceof OpenPGP_SecretKeyPacket)) continue;
$key = OpenPGP_Crypt_Symmetric::decryptSecretKey($argv[2], $p);
$msg = OpenPGP_Message::parse(OpenPGP::unarmor($msgASCII, 'PGP MESSAGE'));
$decryptor = new OpenPGP_Crypt_RSA($key);
$decrypted = $decryptor->decrypt($msg);
var_dump($decrypted);
}

View File

@@ -0,0 +1,15 @@
<?php
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_symmetric.php';
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/../tests/data/helloKey.gpg'));
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
$encrypted = OpenPGP_Crypt_Symmetric::encrypt($key, new OpenPGP_Message(array($data)));
// Now decrypt it with the same key
$decryptor = new OpenPGP_Crypt_RSA($key);
$decrypted = $decryptor->decrypt($encrypted);
var_dump($decrypted);

24
examples/keygen.php Normal file
View File

@@ -0,0 +1,24 @@
<?php
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
$rsa = new Crypt_RSA();
$k = $rsa->createKey(512);
$rsa->loadKey($k['privatekey']);
$nkey = new OpenPGP_SecretKeyPacket(array(
'n' => $rsa->modulus->toBytes(),
'e' => $rsa->publicExponent->toBytes(),
'd' => $rsa->exponent->toBytes(),
'p' => $rsa->primes[1]->toBytes(),
'q' => $rsa->primes[2]->toBytes(),
'u' => $rsa->coefficients[2]->toBytes()
));
$uid = new OpenPGP_UserIDPacket('Test <test@example.com>');
$wkey = new OpenPGP_Crypt_RSA($nkey);
$m = $wkey->sign_key_userid(array($nkey, $uid));
print $m->to_bytes();

22
examples/sign.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
/* Parse secret key from STDIN, the key must not be password protected */
$wkey = OpenPGP_Message::parse(file_get_contents('php://stdin'));
$wkey = $wkey[0];
/* Create a new literal data packet */
$data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
/* Create a signer from the key */
$sign = new OpenPGP_Crypt_RSA($wkey);
/* The message is the signed data packet */
$m = $sign->sign($data);
/* Output the raw message bytes to STDOUT */
echo $m->to_bytes();
?>

18
examples/verify.php Normal file
View File

@@ -0,0 +1,18 @@
<?php
require_once dirname(__FILE__).'/../lib/openpgp.php';
require_once dirname(__FILE__).'/../lib/openpgp_crypt_rsa.php';
/* Parse public key from STDIN */
$wkey = OpenPGP_Message::parse(file_get_contents('php://stdin'));
/* Parse signed message from file named "t" */
$m = OpenPGP_Message::parse(file_get_contents('t'));
/* Create a verifier for the key */
$verify = new OpenPGP_Crypt_RSA($wkey);
/* Dump verification information to STDOUT */
var_dump($verify->verify($m));
?>

File diff suppressed because it is too large Load Diff

261
lib/openpgp_crypt_rsa.php Normal file
View File

@@ -0,0 +1,261 @@
<?php
// This is free and unencumbered software released into the public domain.
/**
* OpenPGP_Crypt_RSA.php is a wrapper for using the classes from OpenPGP.php with Crypt_RSA
*
* @package OpenPGP
*/
// From http://phpseclib.sourceforge.net/
require_once 'Crypt/RSA.php';
require_once dirname(__FILE__).'/openpgp.php';
@include_once dirname(__FILE__).'/openpgp_crypt_symmetric.php'; /* For encrypt/decrypt */
class OpenPGP_Crypt_RSA {
protected $key, $message;
// Construct a wrapper object from a key or a message packet
function __construct($packet) {
if(!is_object($packet)) $packet = OpenPGP_Message::parse($packet);
if($packet instanceof OpenPGP_PublicKeyPacket || $packet[0] instanceof OpenPGP_PublicKeyPacket) { // If it's a key (other keys are subclasses of this one)
$this->key = $packet;
} else {
$this->message = $packet;
}
}
function key($keyid=NULL) {
if(!$this->key) return NULL; // No key
if($this->key instanceof OpenPGP_Message) {
foreach($this->key as $p) {
if($p instanceof OpenPGP_PublicKeyPacket) {
if(!$keyid || strtoupper(substr($p->fingerprint, strlen($keyid)*-1)) == strtoupper($keyid)) return $p;
}
}
}
return $this->key;
}
// Get Crypt_RSA for the public key
function public_key($keyid=NULL) {
return self::convert_public_key($this->key($keyid));
}
// Get Crypt_RSA for the private key
function private_key($keyid=NULL) {
return self::convert_private_key($this->key($keyid));
}
// Pass a message to verify with this key, or a key (OpenPGP or Crypt_RSA) to check this message with
// Second optional parameter to specify which signature to verify (if there is more than one)
function verify($packet) {
$self = $this; // For old PHP
if(!is_object($packet)) $packet = OpenPGP_Message::parse($packet);
if(!$this->message) {
$m = $packet;
$verifier = function($m, $s) use($self) {
$key = $self->public_key($s->issuer());
if(!$key) return false;
$key->setHash(strtolower($s->hash_algorithm_name()));
return $key->verify($m, reset($s->data));
};
} else {
if(!($packet instanceof Crypt_RSA)) {
$packet = new self($packet);
}
$m = $this->message;
$verifier = function($m, $s) use($self, $packet) {
if(!($packet instanceof Crypt_RSA)) {
$key = $packet->public_key($s->issuer());
}
if(!$key) return false;
$key->setHash(strtolower($s->hash_algorithm_name()));
return $key->verify($m, reset($s->data));
};
}
return $m->verified_signatures(array('RSA' => array(
'MD5' => $verifier,
'SHA1' => $verifier,
'SHA224' => $verifier,
'SHA256' => $verifier,
'SHA384' => $verifier,
'SHA512' => $verifier
)));
}
// Pass a message to sign with this key, or a secret key to sign this message with
// Second parameter is hash algorithm to use (default SHA256)
// Third parameter is the 16-digit key ID to use... defaults to the key id in the key packet
function sign($packet, $hash='SHA256', $keyid=NULL) {
if(!is_object($packet)) {
if($this->key) {
$packet = new OpenPGP_LiteralDataPacket($packet);
} else {
$packet = OpenPGP_Message::parse($packet);
}
}
if($packet instanceof OpenPGP_SecretKeyPacket || $packet instanceof Crypt_RSA
|| ($packet instanceof ArrayAccess && $packet[0] instanceof OpenPGP_SecretKeyPacket)) {
$key = $packet;
$message = $this->message;
} else {
$key = $this->key;
$message = $packet;
}
if(!$key || !$message) return NULL; // Missing some data
if($message instanceof OpenPGP_Message) {
$sign = $message->signatures();
$message = $sign[0][0];
}
if(!($key instanceof Crypt_RSA)) {
$key = new self($key);
if(!$keyid) $keyid = substr($key->key()->fingerprint, -16, 16);
$key = $key->private_key($keyid);
}
$key->setHash(strtolower($hash));
$sig = new OpenPGP_SignaturePacket($message, 'RSA', strtoupper($hash));
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket($keyid);
$sig->sign_data(array('RSA' => array($hash => function($data) use($key) {return array($key->sign($data));})));
return new OpenPGP_Message(array($sig, $message));
}
/** Pass a message with a key and userid packet to sign */
// TODO: merge this with the normal sign function
function sign_key_userid($packet, $hash='SHA256', $keyid=NULL) {
if(is_array($packet)) {
$packet = new OpenPGP_Message($packet);
} else if(!is_object($packet)) {
$packet = OpenPGP_Message::parse($packet);
}
$key = $this->private_key($keyid);
if(!$key || !$packet) return NULL; // Missing some data
if(!$keyid) $keyid = substr($this->key->fingerprint, -16);
$key->setHash(strtolower($hash));
$sig = NULL;
foreach($packet as $p) {
if($p instanceof OpenPGP_SignaturePacket) $sig = $p;
}
if(!$sig) {
$sig = new OpenPGP_SignaturePacket($packet, 'RSA', strtoupper($hash));
$sig->signature_type = 0x13;
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_KeyFlagsPacket(array(0x01, 0x02));
$sig->hashed_subpackets[] = new OpenPGP_SignaturePacket_IssuerPacket($keyid);
$packet[] = $sig;
}
$sig->sign_data(array('RSA' => array($hash => function($data) use($key) {return array($key->sign($data));})));
return $packet;
}
function decrypt($packet) {
if(!is_object($packet)) $packet = OpenPGP_Message::parse($packet);
if($packet instanceof OpenPGP_SecretKeyPacket || $packet instanceof Crypt_RSA
|| ($packet instanceof ArrayAccess && $packet[0] instanceof OpenPGP_SecretKeyPacket)) {
$keys = $packet;
$message = $this->message;
} else {
$keys = $this->key;
$message = $packet;
}
if(!$keys || !$message) return NULL; // Missing some data
if(!($keys instanceof Crypt_RSA)) {
$keys = new self($keys);
}
foreach($message as $p) {
if($p instanceof OpenPGP_AsymmetricSessionKeyPacket) {
if($keys instanceof Crypt_RSA) {
$sk = self::try_decrypt_session($keys, substr($p->encrypted_data, 2));
} else if(strlen(str_replace('0', '', $p->keyid)) < 1) {
foreach($keys->key as $k) {
$sk = self::try_decrypt_session(self::convert_private_key($k), substr($p->encrypted_data, 2));
if($sk) break;
}
} else {
$key = $keys->private_key($p->keyid);
$sk = self::try_decrypt_session($key, substr($p->encrypted_data, 2));
}
if(!$sk) continue;
$r = OpenPGP_Crypt_Symmetric::decryptPacket(OpenPGP_Crypt_Symmetric::getEncryptedData($message), $sk[0], $sk[1]);
if($r) return $r;
}
}
return NULL; /* Failed */
}
static function try_decrypt_session($key, $edata) {
$key->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$data = $key->decrypt($edata);
$sk = substr($data, 1, strlen($data)-3);
$chk = unpack('n', substr($data, -2));
$chk = reset($chk);
$sk_chk = 0;
for($i = 0; $i < strlen($sk); $i++) {
$sk_chk = ($sk_chk + ord($sk{$i})) % 65536;
}
if($sk_chk != $chk) return NULL;
return array(ord($data{0}), $sk);
}
static function crypt_rsa_key($mod, $exp, $hash='SHA256') {
$rsa = new Crypt_RSA();
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$rsa->setHash(strtolower($hash));
$rsa->modulus = new Math_BigInteger($mod, 256);
$rsa->k = strlen($rsa->modulus->toBytes());
$rsa->exponent = new Math_BigInteger($exp, 256);
$rsa->setPublicKey();
return $rsa;
}
static function convert_key($packet, $private=false) {
if(!is_object($packet)) $packet = OpenPGP_Message::parse($packet);
if($packet instanceof OpenPGP_Message) $packet = $packet[0];
$mod = $packet->key['n'];
$exp = $packet->key['e'];
if($private) $exp = $packet->key['d'];
if(!$exp) return NULL; // Packet doesn't have needed data
$rsa = self::crypt_rsa_key($mod, $exp);
if($private) {
if($packet->key['p'] && $packet->key['q']) $rsa->primes = array($packet->key['p'], $packet->key['q']);
if($packet->key['u']) $rsa->coefficients = array($packet->key['u']);
}
return $rsa;
}
static function convert_public_key($packet) {
return self::convert_key($packet, false);
}
static function convert_private_key($packet) {
return self::convert_key($packet, true);
}
}
?>

View File

@@ -0,0 +1,196 @@
<?php
require_once dirname(__FILE__).'/openpgp.php';
@include_once dirname(__FILE__).'/openpgp_crypt_rsa.php';
@include_once dirname(__FILE__).'/openpgp_mcrypt_wrapper.php';
@include_once 'Crypt/AES.php';
@include_once 'Crypt/TripleDES.php';
require_once 'Crypt/Random.php'; // part of phpseclib is absolutely required
class OpenPGP_Crypt_Symmetric {
public static function encrypt($passphrases_and_keys, $message, $symmetric_algorithm=9) {
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($symmetric_algorithm);
if(!$cipher) throw new Exception("Unsupported cipher");
$prefix = crypt_random_string($key_block_bytes);
$prefix .= substr($prefix, -2);
$key = crypt_random_string($key_bytes);
$cipher->setKey($key);
$to_encrypt = $prefix . $message->to_bytes();
$mdc = new OpenPGP_ModificationDetectionCodePacket(hash('sha1', $to_encrypt . "\xD3\x14", true));
$to_encrypt .= $mdc->to_bytes();
$encrypted = array(new OpenPGP_IntegrityProtectedDataPacket($cipher->encrypt($to_encrypt)));
if(!is_array($passphrases_and_keys) && !($passphrases_and_keys instanceof IteratorAggregate)) {
$passphrases_and_keys = (array)$passphrases_and_keys;
}
foreach($passphrases_and_keys as $pass) {
if($pass instanceof OpenPGP_PublicKeyPacket) {
if(!in_array($pass->algorithm, array(1,2,3))) throw new Exception("Only RSA keys are supported.");
$crypt_rsa = new OpenPGP_Crypt_RSA($pass);
$rsa = $crypt_rsa->public_key();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$esk = $rsa->encrypt(chr($symmetric_algorithm) . $key . pack('n', self::checksum($key)));
$esk = pack('n', OpenPGP::bitlength($esk)) . $esk;
array_unshift($encrypted, new OpenPGP_AsymmetricSessionKeyPacket($pass->algorithm, $pass->fingerprint(), $esk));
} else if(is_string($pass)) {
$s2k = new OpenPGP_S2K(crypt_random_string(10));
$cipher->setKey($s2k->make_key($pass, $key_bytes));
$esk = $cipher->encrypt(chr($symmetric_algorithm) . $key);
array_unshift($encrypted, new OpenPGP_SymmetricSessionKeyPacket($s2k, $esk, $symmetric_algorithm));
}
}
return new OpenPGP_Message($encrypted);
}
public static function decryptSymmetric($pass, $m) {
$epacket = self::getEncryptedData($m);
foreach($m as $p) {
if($p instanceof OpenPGP_SymmetricSessionKeyPacket) {
if(strlen($p->encrypted_data) > 0) {
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($p->symmetric_algorithm);
if(!$cipher) continue;
$cipher->setKey($p->s2k->make_key($pass, $key_bytes));
$padAmount = $key_block_bytes - (strlen($p->encrypted_data) % $key_block_bytes);
$data = substr($cipher->decrypt($p->encrypted_data . str_repeat("\0", $padAmount)), 0, strlen($p->encrypted_data));
$decrypted = self::decryptPacket($epacket, ord($data{0}), substr($data, 1));
} else {
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($p->symmetric_algorithm);
$decrypted = self::decryptPacket($epacket, $p->symmetric_algorithm, $p->s2k->make_key($pass, $key_bytes));
}
if($decrypted) return $decrypted;
}
}
return NULL; /* If we get here, we failed */
}
public static function decryptSecretKey($pass, $packet) {
$packet = clone $packet; // Do not mutate orinigal
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($packet->symmetric_algorithm);
if(!$cipher) throw new Exception("Unsupported cipher");
$cipher->setKey($packet->s2k->make_key($pass, $key_bytes));
$cipher->setIV(substr($packet->encrypted_data, 0, $key_block_bytes));
$material = $cipher->decrypt(substr($packet->encrypted_data, $key_block_bytes));
if($packet->s2k_useage == 254) {
$chk = substr($material, -20);
$material = substr($material, 0, -20);
if($chk != hash('sha1', $material, true)) return NULL;
} else {
$chk = unpack('n', substr($material, -2));
$chk = reset($chk);
$material = substr($material, 0, -2);
$mkChk = self::checksum($material);
if($chk != $mkChk) return NULL;
}
$packet->s2k_useage = 0;
$packet->symmetric_algorithm = 0;
$packet->encrypted_data = NULL;
$packet->input = $material;
$packet->key_from_input();
unset($packet->input);
return $packet;
}
public static function decryptPacket($epacket, $symmetric_algorithm, $key) {
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($symmetric_algorithm);
if(!$cipher) return NULL;
$cipher->setKey($key);
if($epacket instanceof OpenPGP_IntegrityProtectedDataPacket) {
$padAmount = $key_block_bytes - (strlen($epacket->data) % $key_block_bytes);
$data = substr($cipher->decrypt($epacket->data . str_repeat("\0", $padAmount)), 0, strlen($epacket->data));
$prefix = substr($data, 0, $key_block_bytes + 2);
$mdc = substr(substr($data, -22, 22), 2);
$data = substr($data, $key_block_bytes + 2, -22);
$mkMDC = hash("sha1", $prefix . $data . "\xD3\x14", true);
if($mkMDC !== $mdc) return false;
try {
$msg = OpenPGP_Message::parse($data);
} catch (Exception $ex) { $msg = NULL; }
if($msg) return $msg; /* Otherwise keep trying */
} else {
// No MDC mean decrypt with resync
$iv = substr($epacket->data, 2, $key_block_bytes);
$edata = substr($epacket->data, $key_block_bytes + 2);
$padAmount = $key_block_bytes - (strlen($edata) % $key_block_bytes);
$cipher->setIV($iv);
$data = substr($cipher->decrypt($edata . str_repeat("\0", $padAmount)), 0, strlen($edata));
try {
$msg = OpenPGP_Message::parse($data);
} catch (Exception $ex) { $msg = NULL; }
if($msg) return $msg; /* Otherwise keep trying */
}
return NULL; /* Failed */
}
public static function getCipher($algo) {
$cipher = NULL;
switch($algo) {
case 2:
if(class_exists('Crypt_TripleDES')) {
$cipher = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
$key_bytes = 24;
$key_block_bytes = 8;
}
break;
case 3:
if(defined('MCRYPT_CAST_128')) {
$cipher = new MCryptWrapper(MCRYPT_CAST_128);
}
break;
case 7:
if(class_exists('Crypt_AES')) {
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
$cipher->setKeyLength(128);
}
break;
case 8:
if(class_exists('Crypt_AES')) {
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
$cipher->setKeyLength(192);
}
break;
case 9:
if(class_exists('Crypt_AES')) {
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
$cipher->setKeyLength(256);
}
break;
}
if(!$cipher) return array(NULL, NULL, NULL); // Unsupported cipher
if(!isset($key_bytes)) $key_bytes = $cipher->key_size;
if(!isset($key_block_bytes)) $key_block_bytes = $cipher->block_size;
return array($cipher, $key_bytes, $key_block_bytes);
}
public static function getEncryptedData($m) {
foreach($m as $p) {
if($p instanceof OpenPGP_EncryptedDataPacket) return $p;
}
throw new Exception("Can only decrypt EncryptedDataPacket");
}
public static function checksum($s) {
$mkChk = 0;
for($i = 0; $i < strlen($s); $i++) {
$mkChk = ($mkChk + ord($s{$i})) % 65536;
}
return $mkChk;
}
}

View File

@@ -0,0 +1,31 @@
<?php
if(function_exists('mcrypt_encrypt') && defined('MCRYPT_MODE_CFB')) {
class MCryptWrapper {
public $cipher, $key, $iv, $key_size, $block_size;
function __construct($cipher) {
$this->cipher = $cipher;
$this->key_size = mcrypt_module_get_algo_key_size($cipher);
$this->block_size = mcrypt_module_get_algo_block_size($cipher);
$this->iv = str_repeat("\0", mcrypt_get_iv_size($cipher, 'ncfb'));
}
function setKey($key) {
$this->key = $key;
}
function setIV($iv) {
$this->iv = $iv;
}
function encrypt($data) {
return mcrypt_encrypt($this->cipher, $this->key, $data, 'ncfb', $this->iv);
}
function decrypt($data) {
return mcrypt_decrypt($this->cipher, $this->key, $data, 'ncfb', $this->iv);
}
}
}

27
phpunit.xml Normal file
View File

@@ -0,0 +1,27 @@
<phpunit bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite name="Serialization">
<file>tests/suite.php</file>
</testsuite>
<testsuite name="Fingerprint">
<file>tests/suite.php</file>
</testsuite>
<testsuite name="MessageVerification">
<file>tests/phpseclib_suite.php</file>
</testsuite>
<testsuite name="KeyVerification">
<file>tests/phpseclib_suite.php</file>
</testsuite>
<testsuite name="Decryption">
<file>tests/phpseclib_suite.php</file>
</testsuite>
<testsuite name="Encryption">
<file>tests/phpseclib_suite.php</file>
</testsuite>
</testsuites>
</phpunit>

2
tests/bootstrap.php Normal file
View File

@@ -0,0 +1,2 @@
<?php
@include_once dirname(__FILE__) . '/../vendor/autoload.php';

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>$Test Key (RSA) <testkey@example.org>

BIN
tests/data/000003-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000005-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000007-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000009-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000011-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000014-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000017-002.sig Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>$Test Key (DSA) <testkey@example.com>

BIN
tests/data/000020-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000022-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000025-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000028-002.sig Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>+Test Key (DSA sign-only) <test@example.net>

BIN
tests/data/000031-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000033-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>.Test Key (RSA sign-only) <testkey@example.net>

BIN
tests/data/000037-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/000039-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000042-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000045-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>$Test Key (RSA) <testkey@example.org>

BIN
tests/data/000049-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000052-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000055-002.sig Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>$Test Key (DSA) <testkey@example.com>

BIN
tests/data/000058-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000061-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000064-002.sig Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>+Test Key (DSA sign-only) <test@example.net>

BIN
tests/data/000067-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>.Test Key (RSA sign-only) <testkey@example.net>

BIN
tests/data/000071-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000074-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/000077-002.sig Normal file

Binary file not shown.

Binary file not shown.

BIN
tests/data/002182-002.sig Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More