diff --git a/CHANGELOG b/CHANGELOG
index 6a14ab87e..f97f1fdf0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
+- Improved encrypt/decrypt methods with option to choose the cipher_method (#1489719)
- Make optional adding of standard signature separator - sig_separator (#1487768)
- Optimize folder_size() on Cyrus IMAP by using special folder annotation (#1490514)
- Make optional hidding of folders with name starting with a dot - imap_skip_hidden_folders (#1490468)
diff --git a/config/defaults.inc.php b/config/defaults.inc.php
index a3b7b5380..45d2c7ba3 100644
--- a/config/defaults.inc.php
+++ b/config/defaults.inc.php
@@ -446,11 +446,16 @@ $config['referer_check'] = false;
// Possible values: sameorigin|deny. Set to false in order to disable sending them
$config['x_frame_options'] = 'sameorigin';
-// this key is used to encrypt the users imap password which is stored
-// in the session record (and the client cookie if remember password is enabled).
-// please provide a string of exactly 24 chars.
+// This key is used for encrypting purposes, like storing of imap password
+// in the session. For historical reasons it's called DES_key, but it's used
+// with any configured cipher_method (see below).
$config['des_key'] = 'rcmail-!24ByteDESkey*Str';
+// Encryption algorithm. You can use any method supported by openssl.
+// Default is set for backward compatibility to DES-EDE3-CBC,
+// but you can choose e.g. AES-256-CBC which we consider a better choice.
+$config['cipher_method'] = 'DES-EDE3-CBC';
+
// Automatically add this domain to user names for login
// Only for IMAP servers that require full e-mail addresses for login
// Specify an array with 'host' => 'domain' values to support multiple hosts
diff --git a/installer/config.php b/installer/config.php
index 4882c1d93..588e14d1f 100644
--- a/installer/config.php
+++ b/installer/config.php
@@ -128,8 +128,7 @@ echo $input_deskey->show($RCI->getprop('des_key'));
?>
This key is used to encrypt the users imap password before storing in the session record
-It's a random generated string to ensure that every installation has its own key.
-If you enter it manually please provide a string of exactly 24 chars.
+It's a random generated string to ensure that every installation has its own key.
ip_check
diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index 4d80dc0a0..37b5a3af0 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -810,26 +810,22 @@ class rcube
}
/**
- * Encrypt using 3DES
+ * Encrypt a string
*
* @param string $clear Clear text input
* @param string $key Encryption key to retrieve from the configuration, defaults to 'des_key'
* @param boolean $base64 Whether or not to base64_encode() the result before returning
*
- * @return string encrypted text
+ * @return string Encrypted text
*/
public function encrypt($clear, $key = 'des_key', $base64 = true)
{
- if (!$clear) {
+ if (!is_string($clear) || !strlen($clear)) {
return '';
}
- // Add a single canary byte to the end of the clear text, which
- // will help find out how much of padding will need to be removed
- // upon decryption; see http://php.net/mcrypt_generic#68082.
- $clear = pack("a*H2", $clear, "80");
$ckey = $this->config->get_crypto_key($key);
- $method = 'DES-EDE3-CBC';
+ $method = $this->config->get_crypto_method();
$opts = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
$iv = rcube_utils::random_bytes(openssl_cipher_iv_length($method), true);
$cipher = $iv . openssl_encrypt($clear, $method, $ckey, $opts, $iv);
@@ -838,13 +834,13 @@ class rcube
}
/**
- * Decrypt 3DES-encrypted string
+ * Decrypt a string
*
* @param string $cipher Encrypted text
* @param string $key Encryption key to retrieve from the configuration, defaults to 'des_key'
* @param boolean $base64 Whether or not input is base64-encoded
*
- * @return string decrypted text
+ * @return string Decrypted text
*/
public function decrypt($cipher, $key = 'des_key', $base64 = true)
{
@@ -852,10 +848,9 @@ class rcube
return '';
}
- $cipher = $base64 ? base64_decode($cipher) : $cipher;
- $ckey = $this->config->get_crypto_key($key);
-
- $method = 'DES-EDE3-CBC';
+ $cipher = $base64 ? base64_decode($cipher) : $cipher;
+ $ckey = $this->config->get_crypto_key($key);
+ $method = $this->config->get_crypto_method();
$opts = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
$iv_size = openssl_cipher_iv_length($method);
$iv = substr($cipher, 0, $iv_size);
@@ -868,10 +863,6 @@ class rcube
$cipher = substr($cipher, $iv_size);
$clear = openssl_decrypt($cipher, $method, $ckey, $opts, $iv);
- // Trim PHP's padding and the canary byte; see note in
- // rcube::encrypt() and http://php.net/mcrypt_generic#68082
- $clear = substr(rtrim($clear, "\0"), 0, -1);
-
return $clear;
}
diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php
index 3dd54e307..799552fdf 100644
--- a/program/lib/Roundcube/rcube_config.php
+++ b/program/lib/Roundcube/rcube_config.php
@@ -505,7 +505,7 @@ class rcube_config
public function get_crypto_key($key)
{
// Bomb out if the requested key does not exist
- if (!array_key_exists($key, $this->prop)) {
+ if (!array_key_exists($key, $this->prop) || empty($this->prop[$key])) {
rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
@@ -513,18 +513,23 @@ class rcube_config
), true, true);
}
- $key = $this->prop[$key];
+ return $this->prop[$key];
+ }
- // Bomb out if the configured key is not exactly 24 bytes long
- if (strlen($key) != 24) {
- rcube::raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Configured crypto key '$key' is not exactly 24 bytes long"
- ), true, true);
+ /**
+ * Return configured crypto method.
+ *
+ * @return string Crypto method
+ */
+ public function get_crypto_method()
+ {
+ $method = $this->get('cipher_method');
+
+ if (empty($method)) {
+ $method = 'DES-EDE3-CBC';
}
- return $key;
+ return $method;
}
/**