diff --git a/lib/openpgp.php b/lib/openpgp.php
index 3fdd9d9..927126c 100644
--- a/lib/openpgp.php
+++ b/lib/openpgp.php
@@ -113,6 +113,13 @@ class OpenPGP {
class OpenPGP_S2K {
public $type, $hash_algorithm, $salt, $count;
+ function __construct($salt='BADSALT', $hash_algorithm=10, $count=65536, $type=3) {
+ $this->type = $type;
+ $this->hash_algorithm = $hash_algorithm;
+ $this->salt = $salt;
+ $this->count = $count;
+ }
+
static function parse(&$input) {
$s2k = new OpenPGP_S2k();
switch($s2k->type = ord($input{0})) {
@@ -570,6 +577,13 @@ class OpenPGP_Packet {
class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
public $version, $keyid, $key_algorithm, $encrypted_data;
+ function __construct($key_algorithm='', $keyid='', $encrypted_data='', $version=3) {
+ $this->version = $version;
+ $this->keyid = substr($keyid, -16);
+ $this->key_algorithm = $key_algorithm;
+ $this->encrypted_data = $encrypted_data;
+ }
+
function read() {
switch($this->version = ord($this->read_byte())) {
case 3:
@@ -1230,6 +1244,13 @@ class OpenPGP_SignaturePacket_EmbeddedSignaturePacket extends OpenPGP_SignatureP
class OpenPGP_SymmetricSessionKeyPacket extends OpenPGP_Packet {
public $version, $symmetric_algorithm, $s2k, $encrypted_data;
+ function __construct($s2k=NULL, $encrypted_data='', $symmetric_algorithm=9, $version=3) {
+ $this->version = $version;
+ $this->symmetric_algorithm = $symmetric_algorithm;
+ $this->s2k = $s2k;
+ $this->encrypted_data = $encrypted_data;
+ }
+
function read() {
$this->version = ord($this->read_byte());
$this->symmetric_algorithm = ord($this->read_byte());
@@ -1775,6 +1796,10 @@ class OpenPGP_UserAttributePacket extends OpenPGP_Packet {
class OpenPGP_IntegrityProtectedDataPacket extends OpenPGP_EncryptedDataPacket {
public $version;
+ function __construct($data='', $version=1) {
+ $this->data = $data;
+ }
+
function read() {
$this->version = ord($this->read_byte());
$this->data = $this->input;
@@ -1791,7 +1816,24 @@ class OpenPGP_IntegrityProtectedDataPacket extends OpenPGP_EncryptedDataPacket {
* @see http://tools.ietf.org/html/rfc4880#section-5.14
*/
class OpenPGP_ModificationDetectionCodePacket extends OpenPGP_Packet {
- // TODO
+ function __construct($sha1='') {
+ $this->data = $sha1;
+ }
+
+ function read() {
+ $this->data = $this->input;
+ if(strlen($this->input) != 20) throw new Exception("Bad ModificationDetectionCodePacket");
+ }
+
+ function header_and_body() {
+ $body = $this->body(); // Get body first, we will need it's length
+ if(strlen($body) != 20) throw new Exception("Bad ModificationDetectionCodePacket");
+ return array('header' => "\xD3\x14", 'body' => $body);
+ }
+
+ function body() {
+ return $this->data;
+ }
}
/**
diff --git a/lib/openpgp_crypt_aes_tripledes.php b/lib/openpgp_crypt_aes_tripledes.php
index 8309819..46d5985 100644
--- a/lib/openpgp_crypt_aes_tripledes.php
+++ b/lib/openpgp_crypt_aes_tripledes.php
@@ -1,10 +1,49 @@
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() . crypt_random() . crypt_random());
+ $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);
@@ -41,16 +80,13 @@ class OpenPGP_Crypt_AES_TripleDES {
if($packet->s2k_useage == 254) {
$chk = substr($material, -20);
$material = substr($material, 0, -20);
- if($chk != hash('sha1', $material)) return NULL;
+ if($chk != hash('sha1', $material, true)) return NULL;
} else {
$chk = unpack('n', substr($material, -2));
$chk = reset($chk);
$material = substr($material, 0, -2);
- $mkChk = 0;
- for($i = 0; $i < strlen($material); $i++) {
- $mkChk = ($mkChk + ord($material{$i})) % 65536;
- }
+ $mkChk = self::checksum($material);
if($chk != $mkChk) return NULL;
}
@@ -139,4 +175,21 @@ class OpenPGP_Crypt_AES_TripleDES {
}
throw new Exception("Can only decrypt EncryptedDataPacket");
}
+
+ public static function randomBytes($n) {
+ $key = '';
+ for($i = 0; $i < $n; $i++) {
+ $key .= crypt_random();
+ }
+ $s2k = new OpenPGP_S2K(crypt_random() . crypt_random() . crypt_random());
+ return $s2k->make_key($key, $n);
+ }
+
+ public static function checksum($s) {
+ $mkChk = 0;
+ for($i = 0; $i < strlen($s); $i++) {
+ $mkChk = ($mkChk + ord($s{$i})) % 65536;
+ }
+ return $mkChk;
+ }
}
diff --git a/phpunit.xml b/phpunit.xml
index 41b0d95..a071d34 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -15,5 +15,13 @@
tests/phpseclib_suite.php
+
+
+ tests/phpseclib_suite.php
+
+
+
+ tests/phpseclib_suite.php
+
diff --git a/tests/phpseclib_suite.php b/tests/phpseclib_suite.php
index 8044fbf..e5ed903 100644
--- a/tests/phpseclib_suite.php
+++ b/tests/phpseclib_suite.php
@@ -111,3 +111,21 @@ class Decryption extends PHPUnit_Framework_TestCase {
$this->assertSame(!!$skey, true);
}
}
+
+class Encryption extends PHPUnit_Framework_TestCase {
+ public function testEncryptSymmetric() {
+ $data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
+ $encrypted = OpenPGP_Crypt_AES_TripleDES::encrypt('secret', new OpenPGP_Message(array($data)));
+ $decrypted = OpenPGP_Crypt_AES_TripleDES::decryptSymmetric('secret', $encrypted);
+ $this->assertEquals($decrypted[0]->data, 'This is text.');
+ }
+
+ public function testEncryptAsymmetric() {
+ $key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
+ $data = new OpenPGP_LiteralDataPacket('This is text.', array('format' => 'u', 'filename' => 'stuff.txt'));
+ $encrypted = OpenPGP_Crypt_AES_TripleDES::encrypt($key, new OpenPGP_Message(array($data)));
+ $decryptor = new OpenPGP_Crypt_RSA($key);
+ $decrypted = $decryptor->decrypt($encrypted);
+ $this->assertEquals($decrypted[0]->data, 'This is text.');
+ }
+}