From ac1cd3719c460fd59339b48cf4c8d258c839ce46 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Sun, 12 Jun 2016 09:59:50 +0200 Subject: [PATCH] Enigma: Fix redundant list-secret-keys/list-public-keys calls on signing/encryption --- CHANGELOG | 1 + plugins/enigma/lib/enigma_driver.php | 20 ++++++------- plugins/enigma/lib/enigma_driver_gnupg.php | 27 ++++++++--------- plugins/enigma/lib/enigma_driver_phpssl.php | 4 +-- plugins/enigma/lib/enigma_engine.php | 32 ++++++++++++--------- plugins/enigma/lib/enigma_key.php | 2 ++ plugins/enigma/lib/enigma_subkey.php | 1 + 7 files changed, 48 insertions(+), 39 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f22d9f01a..13e4d20ad 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ CHANGELOG Roundcube Webmail =========================== - Update TinyMCE to version 4.3.13 (#5309) +- Enigma: Fix redundant list-secret-keys/list-public-keys calls on signing/encryption - Enigma: Implement PGP encryption and signing in one go (#5302) - Enigma: Display signature verification status for encrypted+signed messages (#5302) - Display different attachment icon on encrypted messages diff --git a/plugins/enigma/lib/enigma_driver.php b/plugins/enigma/lib/enigma_driver.php index f3b117bdb..d0d3918d5 100644 --- a/plugins/enigma/lib/enigma_driver.php +++ b/plugins/enigma/lib/enigma_driver.php @@ -34,20 +34,19 @@ abstract class enigma_driver /** * Encryption (and optional signing). * - * @param string Message body - * @param array List of key-password mapping - * @param string Optional signing Key ID - * @param string Optional signing Key password + * @param string Message body + * @param array List of keys (enigma_key objects) + * @param enigma_key Optional signing Key ID * * @return mixed Encrypted message or enigma_error on failure */ - abstract function encrypt($text, $keys, $sign_key = null, $sign_pass = null); + abstract function encrypt($text, $keys, $sign_key = null); /** * Decryption (and sig verification if sig exists). * * @param string Encrypted message - * @param array List of key-password mapping + * @param array List of key-password * @param enigma_signature Signature information (if available) * * @return mixed Decrypted message or enigma_error on failure @@ -57,14 +56,13 @@ abstract class enigma_driver /** * Signing. * - * @param string Message body - * @param string Key ID - * @param string Key password - * @param int Signing mode (enigma_engine::SIGN_*) + * @param string Message body + * @param enigma_key The signing key + * @param int Signing mode (enigma_engine::SIGN_*) * * @return mixed True on success or enigma_error on failure */ - abstract function sign($text, $key, $passwd, $mode = null); + abstract function sign($text, $key, $mode = null); /** * Signature verification. diff --git a/plugins/enigma/lib/enigma_driver_gnupg.php b/plugins/enigma/lib/enigma_driver_gnupg.php index 9cd894546..0b2f51a1c 100644 --- a/plugins/enigma/lib/enigma_driver_gnupg.php +++ b/plugins/enigma/lib/enigma_driver_gnupg.php @@ -97,22 +97,21 @@ class enigma_driver_gnupg extends enigma_driver /** * Encryption (and optional signing). * - * @param string Message body - * @param array List of key-password mapping - * @param string Optional signing Key ID - * @param string Optional signing Key password + * @param string Message body + * @param array List of keys (enigma_key objects) + * @param enigma_key Optional signing Key ID * * @return mixed Encrypted message or enigma_error on failure */ - function encrypt($text, $keys, $sign_key = null, $sign_pass = null) + function encrypt($text, $keys, $sign_key = null) { try { foreach ($keys as $key) { - $this->gpg->addEncryptKey($key); + $this->gpg->addEncryptKey($key->reference); } if ($sign_key) { - $this->gpg->addSignKey($sign_key, $sign_pass); + $this->gpg->addSignKey($sign_key->reference, $sign_key->password); return $this->gpg->encryptAndSign($text, true); } @@ -155,17 +154,16 @@ class enigma_driver_gnupg extends enigma_driver /** * Signing. * - * @param string Message body - * @param string Key ID - * @param string Key password - * @param int Signing mode (enigma_engine::SIGN_*) + * @param string Message body + * @param enigma_key The key + * @param int Signing mode (enigma_engine::SIGN_*) * * @return mixed True on success or enigma_error on failure */ - function sign($text, $key, $passwd, $mode = null) + function sign($text, $key, $mode = null) { try { - $this->gpg->addSignKey($key, $passwd); + $this->gpg->addSignKey($key->reference, $key->password); return $this->gpg->sign($text, $mode, CRYPT_GPG::ARMOR_ASCII, true); } catch (Exception $e) { @@ -450,6 +448,9 @@ class enigma_driver_gnupg extends enigma_driver $ekey->name = trim($ekey->users[0]->name . ' <' . $ekey->users[0]->email . '>'); + // keep reference to Crypt_GPG's key for performance reasons + $ekey->reference = $key; + foreach ($key->getSubKeys() as $idx => $subkey) { $skey = new enigma_subkey(); $skey->id = $subkey->getId(); diff --git a/plugins/enigma/lib/enigma_driver_phpssl.php b/plugins/enigma/lib/enigma_driver_phpssl.php index 26be2cfaf..638cd3d7c 100644 --- a/plugins/enigma/lib/enigma_driver_phpssl.php +++ b/plugins/enigma/lib/enigma_driver_phpssl.php @@ -67,7 +67,7 @@ class enigma_driver_phpssl extends enigma_driver } - function encrypt($text, $keys, $sign_key = null, $sign_pass = null) + function encrypt($text, $keys, $sign_key = null) { } @@ -75,7 +75,7 @@ class enigma_driver_phpssl extends enigma_driver { } - function sign($text, $key, $passwd, $mode = null) + function sign($text, $key, $mode = null) { } diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index 47d1d1df9..d14d91fe7 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -208,7 +208,7 @@ class enigma_engine } // sign the body - $result = $this->pgp_sign($body, $key->id, $pass, $pgp_mode); + $result = $this->pgp_sign($body, $key, $pgp_mode); if ($result !== true) { if ($result->getCode() == enigma_error::BADPASS) { @@ -264,6 +264,8 @@ class enigma_engine $error = array('missing' => array($sign_key->id => $sign_key->name)); return new enigma_error(enigma_error::BADPASS, '', $error); } + + $sign_key->password = $sign_pass; } $recipients = array($from); @@ -281,7 +283,12 @@ class enigma_engine // find recipient public keys foreach ((array) $recipients as $email) { - $key = $this->find_key($email); + if ($email == $from && $sign_key) { + $key = $sign_key; + } + else { + $key = $this->find_key($email); + } if (empty($key)) { return new enigma_error(enigma_error::KEYNOTFOUND, '', array( @@ -289,7 +296,7 @@ class enigma_engine )); } - $keys[] = $key->id; + $keys[] = $key; } // select mode @@ -315,7 +322,7 @@ class enigma_engine } // sign the body - $result = $this->pgp_encrypt($body, $keys, $sign_key ? $sign_key->id : null, $sign_pass); + $result = $this->pgp_encrypt($body, $keys, $sign_key); if ($result !== true) { if ($result->getCode() == enigma_error::BADPASS) { @@ -854,7 +861,7 @@ class enigma_engine * * @return mixed enigma_signature or enigma_error */ - private function pgp_verify(&$msg_body, $sig_body=null) + private function pgp_verify(&$msg_body, $sig_body = null) { // @TODO: Handle big bodies using (temp) files $sig = $this->pgp_driver->verify($msg_body, $sig_body); @@ -902,17 +909,16 @@ class enigma_engine /** * PGP message signing * - * @param mixed Message body - * @param string Key ID - * @param string Key passphrase - * @param int Signing mode + * @param mixed Message body + * @param enigma_key The key (with passphrase) + * @param int Signing mode * * @return mixed True or enigma_error */ - private function pgp_sign(&$msg_body, $keyid, $password, $mode = null) + private function pgp_sign(&$msg_body, $key, $mode = null) { // @TODO: Handle big bodies using (temp) files - $result = $this->pgp_driver->sign($msg_body, $keyid, $password, $mode); + $result = $this->pgp_driver->sign($msg_body, $key, $mode); if ($result instanceof enigma_error) { $err_code = $result->getCode(); @@ -934,7 +940,7 @@ class enigma_engine * PGP message encrypting * * @param mixed Message body - * @param array Keys + * @param array Keys (array of enigma_key objects) * @param string Optional signing Key ID * @param string Optional signing Key password * @@ -1012,7 +1018,7 @@ class enigma_engine // check key validity and type foreach ($result as $key) { - if ($keyid = $key->find_subkey($email, $mode)) { + if ($subkey = $key->find_subkey($email, $mode)) { return $key; } } diff --git a/plugins/enigma/lib/enigma_key.php b/plugins/enigma/lib/enigma_key.php index 976cb457d..3498f4f2c 100644 --- a/plugins/enigma/lib/enigma_key.php +++ b/plugins/enigma/lib/enigma_key.php @@ -21,6 +21,8 @@ class enigma_key public $name; public $users = array(); public $subkeys = array(); + public $reference; + public $password; const TYPE_UNKNOWN = 0; const TYPE_KEYPAIR = 1; diff --git a/plugins/enigma/lib/enigma_subkey.php b/plugins/enigma/lib/enigma_subkey.php index dfcfebf65..3fb5cc676 100644 --- a/plugins/enigma/lib/enigma_subkey.php +++ b/plugins/enigma/lib/enigma_subkey.php @@ -27,6 +27,7 @@ class enigma_subkey public $length; public $usage; + /** * Converts internal ID to short ID * Crypt_GPG uses internal, but e.g. Thunderbird's Enigmail displays short ID