diff --git a/lib/openpgp.php b/lib/openpgp.php index 06e354f..3fdd9d9 100644 --- a/lib/openpgp.php +++ b/lib/openpgp.php @@ -1454,15 +1454,15 @@ class OpenPGP_PublicSubkeyPacket extends OpenPGP_PublicKeyPacket { * @see http://tools.ietf.org/html/rfc4880#section-12 */ class OpenPGP_SecretKeyPacket extends OpenPGP_PublicKeyPacket { - public $s2k_useage, $s2k, $symmetric_type, $private_hash, $encrypted_data; + public $s2k_useage, $s2k, $symmetric_algorithm, $private_hash, $encrypted_data; function read() { parent::read(); // All the fields from PublicKey $this->s2k_useage = ord($this->read_byte()); if($this->s2k_useage == 255 || $this->s2k_useage == 254) { - $this->symmetric_type = ord($this->read_byte()); + $this->symmetric_algorithm = ord($this->read_byte()); $this->s2k = OpenPGP_S2k::parse($this->input); } else if($this->s2k_useage > 0) { - $this->symmetric_type = $this->s2k_useage; + $this->symmetric_algorithm = $this->s2k_useage; } if($this->s2k_useage > 0) { // TODO: IV of the same length as cipher's block size @@ -1503,7 +1503,7 @@ class OpenPGP_SecretKeyPacket extends OpenPGP_PublicKeyPacket { $bytes = parent::body() . chr($this->s2k_useage); $secret_material = NULL; if($this->s2k_useage == 255 || $this->s2k_useage == 254) { - $bytes .= chr($this->symmetric_type); + $bytes .= chr($this->symmetric_algorithm); $bytes .= $this->s2k->to_bytes(); } if($this->s2k_useage > 0) { diff --git a/lib/openpgp_crypt_aes_tripledes.php b/lib/openpgp_crypt_aes_tripledes.php index d0cf24c..8309819 100644 --- a/lib/openpgp_crypt_aes_tripledes.php +++ b/lib/openpgp_crypt_aes_tripledes.php @@ -30,6 +30,44 @@ class OpenPGP_Crypt_AES_TripleDES { 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); + $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)) 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; + } + if($chk != $mkChk) return NULL; + } + + $packet->s2k_useage = 0; + $packet->symmetric_algorithm = 0; + $packet->encrypted_data = NULL; + + foreach($packet::$secret_key_fields[$packet->algorithm] as $f) { + $length = unpack('n', substr($material, 0, 2)); // in bits + $length = (int)floor((reset($length) + 7) / 8); // in bytes + $packet->key[$f] = substr($material, 2, $length); + $material = substr($material, 2 + $length); + } + + 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; diff --git a/tests/data/encryptedSecretKey.gpg b/tests/data/encryptedSecretKey.gpg new file mode 100644 index 0000000..af700e8 Binary files /dev/null and b/tests/data/encryptedSecretKey.gpg differ diff --git a/tests/phpseclib_suite.php b/tests/phpseclib_suite.php index 9b291c2..8044fbf 100644 --- a/tests/phpseclib_suite.php +++ b/tests/phpseclib_suite.php @@ -104,4 +104,10 @@ class Decryption extends PHPUnit_Framework_TestCase { } } } + + public function testDecryptSecretKey() { + $key = OpenPGP_Message::parse(file_get_contents(dirname(__FILE__) . '/data/encryptedSecretKey.gpg')); + $skey = OpenPGP_Crypt_AES_TripleDES::decryptSecretKey("hello", $key[0]); + $this->assertSame(!!$skey, true); + } }