From e7516b09402580c4fe0bf0ff537f367c1ba0efd2 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 13:45:31 +0200 Subject: CI_Encryption: Work around MCrypt's dumb behavior in ECB mode --- system/libraries/Encryption.php | 114 +++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 49 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 503fb64e3..2228ca3a6 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -292,12 +292,6 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['iv'])) - { - $params['iv'] = ($iv_size = $this->{'_'.$this->_driver.'_get_iv_size'}($params['handle'])) - ? $this->{'_'.$this->_driver.'_get_iv'}($iv_size) - : NULL; - } if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE) { @@ -343,7 +337,15 @@ class CI_Encryption { { return FALSE; } - elseif (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + elseif ( ! isset($params['iv'])) + { + $params['iv'] = ($iv_size = mcrypt_enc_get_iv_size($params['handle'])) + ? $this->_mcrypt_get_iv($iv_size) + : NULL; + } + + + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { if ($params['handle'] !== $this->_handle) { @@ -359,7 +361,20 @@ class CI_Encryption { $pad = $block_size - (strlen($data) % $block_size); $data .= str_repeat(chr($pad), $pad); - $data = $params['iv'].mcrypt_generic($params['handle'], $data); + // Work-around for yet another strange behavior in MCrypt. + // + // When encrypting in ECB mode, the IV is ignored. Yet + // mcrypt_enc_get_iv_size() returns a value larger than 0 + // even if ECB is used AND mcrypt_generic_init() complains + // if you don't pass an IV with length equal to the said + // return value. + // + // This probably would've been fine (even though still wasteful), + // but OpenSSL isn't that dumb and we need to make the process + // portable, so ... + $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') + ? $params['iv'].mcrypt_generic($params['handle'], $data) + : mcrypt_generic($params['handle'], $data); mcrypt_generic_deinit($params['handle']); if ($params['handle'] !== $this->_handle) @@ -385,6 +400,12 @@ class CI_Encryption { { return FALSE; } + elseif ( ! isset($params['iv'])) + { + $params['iv'] = ($iv_size = openssl_cipher_iv_length($params['handle'])) + ? $this->_openssl_get_iv($iv_size) + : NULL; + } $data = openssl_encrypt( $data, @@ -450,20 +471,7 @@ class CI_Encryption { $data = base64_decode($data); } - if ( ! isset($params['iv'])) - { - $iv_size = $this->{'_'.$this->_driver.'_get_iv_size'}($params['handle']); - if ($iv_size = $this->{'_'.$this->_driver.'_get_iv_size'}($params['handle'])) - { - $params['iv'] = substr($data, 0, $iv_size); - $data = substr($data, $iv_size); - } - else - { - $params['iv'] = NULL; - } - } - elseif (strncmp($params['iv'], $data, $iv_size = strlen($params['iv'])) === 0) + if (isset($params['iv']) && strncmp($params['iv'], $data, $iv_size = strlen($params['iv'])) === 0) { $data = substr($data, $iv_size); } @@ -486,7 +494,28 @@ class CI_Encryption { { return FALSE; } - elseif (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + elseif ( ! isset($params['iv'])) + { + if ($iv_size = mcrypt_enc_get_iv_size($params['handle'])) + { + if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') + { + $params['iv'] = substr($data, 0, $iv_size); + $data = substr($data, $iv_size); + } + else + { + // MCrypt is dumb and this is ignored, only size matters + $params['iv'] = str_repeat("\x0", $iv_size); + } + } + else + { + $params['iv'] = NULL; + } + } + + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { if ($params['handle'] !== $this->_handle) { @@ -519,6 +548,19 @@ class CI_Encryption { */ protected function _openssl_decrypt($data, $params) { + if ( ! isset($params['iv'])) + { + if ($iv_size = openssl_cipher_iv_length($params['handle'])) + { + $params['iv'] = substr($data, 0, $iv_size); + $data = substr($data, $iv_size); + } + else + { + $params['iv'] = NULL; + } + } + return empty($params['handle']) ? FALSE : openssl_decrypt( @@ -532,32 +574,6 @@ class CI_Encryption { // -------------------------------------------------------------------- - /** - * Get IV size via MCrypt - * - * @param resource $handle MCrypt module resource - * @return int - */ - protected function _mcrypt_get_iv_size($handle) - { - return mcrypt_enc_get_iv_size($handle); - } - - // -------------------------------------------------------------------- - - /** - * Get IV size via OpenSSL - * - * @param string $handle OpenSSL cipher method - * @return int - */ - protected function _openssl_get_iv_size($handle) - { - return openssl_cipher_iv_length($handle); - } - - // -------------------------------------------------------------------- - /** * Get IV via MCrypt * -- cgit v1.2.3-24-g4f1b