Asymmetric decryption
This commit is contained in:
parent
641c07835b
commit
cd15aec6f9
@ -568,7 +568,37 @@ class OpenPGP_Packet {
|
|||||||
* @see http://tools.ietf.org/html/rfc4880#section-5.1
|
* @see http://tools.ietf.org/html/rfc4880#section-5.1
|
||||||
*/
|
*/
|
||||||
class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
|
class OpenPGP_AsymmetricSessionKeyPacket extends OpenPGP_Packet {
|
||||||
// TODO
|
public $version, $keyid, $key_algorithm, $encrypted_data;
|
||||||
|
|
||||||
|
function read() {
|
||||||
|
switch($this->version = ord($this->read_byte())) {
|
||||||
|
case 3:
|
||||||
|
$rawkeyid = $this->read_bytes(8);
|
||||||
|
$this->keyid = '';
|
||||||
|
for($i = 0; $i < strlen($rawkeyid); $i++) { // Store KeyID in Hex
|
||||||
|
$this->keyid .= sprintf('%02X',ord($rawkeyid{$i}));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->key_algorithm = ord($this->read_byte());
|
||||||
|
|
||||||
|
$this->encrypted_data = $this->input;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unsupported AsymmetricSessionKeyPacket version: " . $this->version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function body() {
|
||||||
|
$bytes = ord($this->version);
|
||||||
|
|
||||||
|
for($i = 0; $i < strlen($this->keyid); $i += 2) {
|
||||||
|
$bytes .= chr(hexdec($this->keyid{$i}.$this->keyid{$i+1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytes .= chr($this->key_algorithm);
|
||||||
|
$bytes .= $this->encrypted_data;
|
||||||
|
return $bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,21 +6,35 @@ require_once 'Crypt/TripleDES.php';
|
|||||||
|
|
||||||
class OpenPGP_Crypt_AES_TripleDES {
|
class OpenPGP_Crypt_AES_TripleDES {
|
||||||
public static function decryptSymmetric($pass, $m) {
|
public static function decryptSymmetric($pass, $m) {
|
||||||
|
$epacket = self::getEncryptedData($m);
|
||||||
|
|
||||||
foreach($m as $p) {
|
foreach($m as $p) {
|
||||||
if($p instanceof OpenPGP_SymmetricSessionKeyPacket) {
|
if($p instanceof OpenPGP_SymmetricSessionKeyPacket) {
|
||||||
|
if(strlen($p->encrypted_data) > 0) {
|
||||||
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($p->symmetric_algorithm);
|
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher($p->symmetric_algorithm);
|
||||||
if(!$cipher) continue;
|
if(!$cipher) continue;
|
||||||
$cipher->setKey($p->s2k->make_key($pass, $key_bytes));
|
$cipher->setKey($p->s2k->make_key($pass, $key_bytes));
|
||||||
|
|
||||||
if(strlen($p->encrypted_data) > 0) {
|
|
||||||
$padAmount = $key_block_bytes - (strlen($p->encrypted_data) % $key_block_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));
|
$data = substr($cipher->decrypt($p->encrypted_data . str_repeat("\0", $padAmount)), 0, strlen($p->encrypted_data));
|
||||||
list($cipher, $key_bytes, $key_block_bytes) = self::getCipher(ord($data{0}));
|
$decrypted = self::decryptPacket($epacket, ord($data{0}), substr($data, 1));
|
||||||
if(!$cipher) continue;
|
} else {
|
||||||
$cipher->setKey(substr($data, 1));
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
$epacket = self::getEncryptedData($m);
|
if($decrypted) return $decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL; /* If we get here, we failed */
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
$padAmount = $key_block_bytes - (strlen($epacket->data) % $key_block_bytes);
|
$padAmount = $key_block_bytes - (strlen($epacket->data) % $key_block_bytes);
|
||||||
|
|
||||||
if($epacket instanceof OpenPGP_IntegrityProtectedDataPacket) {
|
if($epacket instanceof OpenPGP_IntegrityProtectedDataPacket) {
|
||||||
@ -49,10 +63,8 @@ class OpenPGP_Crypt_AES_TripleDES {
|
|||||||
} catch (Exception $ex) { $msg = NULL; }
|
} catch (Exception $ex) { $msg = NULL; }
|
||||||
if($msg) return $msg; /* Otherwise keep trying */
|
if($msg) return $msg; /* Otherwise keep trying */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL; /* If we get here, we failed */
|
return NULL; /* Failed */
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getCipher($algo) {
|
public static function getCipher($algo) {
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
// From http://phpseclib.sourceforge.net/
|
// From http://phpseclib.sourceforge.net/
|
||||||
require 'Crypt/RSA.php';
|
require 'Crypt/RSA.php';
|
||||||
|
|
||||||
|
require_once dirname(__FILE__).'/openpgp.php';
|
||||||
|
@include_once dirname(__FILE__).'/openpgp_cryph_aes_tripledes.php'; /* For encrypt/decrypt */
|
||||||
|
|
||||||
class OpenPGP_Crypt_RSA {
|
class OpenPGP_Crypt_RSA {
|
||||||
protected $key, $message;
|
protected $key, $message;
|
||||||
|
|
||||||
@ -157,6 +160,64 @@ class OpenPGP_Crypt_RSA {
|
|||||||
return $packet;
|
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, $p->encyrpted_data);
|
||||||
|
} else if(strlen(str_replace('0', '', $p->keyid)) < 1) {
|
||||||
|
foreach($keys->key as $k) {
|
||||||
|
$sk = self::try_decrypt_session(self::convert_private_key($k), $p->encyrpted_data);
|
||||||
|
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_AES_TripleDES::decryptPacket(OpenPGP_Crypt_AES_TripleDES::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') {
|
static function crypt_rsa_key($mod, $exp, $hash='SHA256') {
|
||||||
$rsa = new Crypt_RSA();
|
$rsa = new Crypt_RSA();
|
||||||
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
||||||
|
BIN
tests/data/hello.gpg
Normal file
BIN
tests/data/hello.gpg
Normal file
Binary file not shown.
@ -91,4 +91,16 @@ class Decryption extends PHPUnit_Framework_TestCase {
|
|||||||
public function testDecryptNoMDC() {
|
public function testDecryptNoMDC() {
|
||||||
$this->oneSymmetric("hello", "PGP\n", "symmetric-no-mdc.gpg");
|
$this->oneSymmetric("hello", "PGP\n", "symmetric-no-mdc.gpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDecryptAsymmetric() {
|
||||||
|
$m = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/hello.gpg'));
|
||||||
|
$key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/helloKey.gpg'));
|
||||||
|
$m2 = (new OpenPGP_Crypt_RSA($key))->decrypt($m);
|
||||||
|
while($m2[0] instanceof OpenPGP_CompressedDataPacket) $m2 = $m2[0]->data;
|
||||||
|
foreach($m2 as $p) {
|
||||||
|
if($p instanceof OpenPGP_LiteralDataPacket) {
|
||||||
|
$this->assertEquals($p->data, "hello\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user