From a756125436884dd622fdeff67084f3a62fc71b98 Mon Sep 17 00:00:00 2001 From: Derek Jones Date: Sun, 21 Jul 2013 14:21:41 -0700 Subject: Updating Calendar lib docs --- system/libraries/Calendar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/libraries') diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index 23d8ffb42..9c68c94c1 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -329,7 +329,7 @@ class CI_Calendar { * Get Day Names * * Returns an array of day names (Sunday, Monday, etc.) based - * on the type. Options: long, short, abrev + * on the type. Options: long, short, abr * * @param string * @return array -- cgit v1.2.3-24-g4f1b From 818aedb6ca46ee8498624d49403e5ff1404bc692 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 3 Feb 2014 11:30:25 +0200 Subject: Introducing CI_Encryption (a CI_Encrypt replacement) --- system/libraries/Encryption.php | 718 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 718 insertions(+) create mode 100644 system/libraries/Encryption.php (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php new file mode 100644 index 000000000..76569f281 --- /dev/null +++ b/system/libraries/Encryption.php @@ -0,0 +1,718 @@ +_drivers = array( + 'mcrypt' => extension_loaded('mcrypt'), + // While OpenSSL is available for PHP 5.3.0, an IV parameter + // for the encrypt/decrypt functions is only available since 5.3.3 + 'openssl' => (is_php('5.3.3') && extension_loaded('openssl')) + ); + + if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl']) + { + return show_error('Encryption: Unable to find an available encryption driver.'); + } + + $this->initialize($params); + + if (empty($this->_driver)) + { + $this->_driver = ($this->_drivers['mcrypt'] === TRUE) + ? 'mcrypt' + : 'openssl'; + + log_message('debug', "Encryption: Auto-configured driver '".$params['driver']."'."); + } + + isset($this->_key) OR $this->_key = config_item('encryption_key'); + if (empty($this->_key)) + { + return show_error('Encryption: You are required to set an encryption key in your configuration.'); + } + + log_message('debug', 'Encryption Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initialize + * + * @param array $params Configuration parameters + * @return CI_Encryption + */ + public function initialize(array $params) + { + if ( ! empty($params['driver'])) + { + if (isset($this->_drivers[$params['driver']])) + { + if ($this->_driver[$params['driver']]) + { + $this->_driver = $params['driver']; + } + else + { + log_message('error', "Encryption: Driver '".$params['driver']."' is not available."); + } + } + else + { + log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured."); + } + } + + empty($params['key']) OR $this->_key = $params['key']; + $this->{'_'.$this->_driver.'_initialize'}($params); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Initialize MCrypt + * + * @param array $params Configuration parameters + * @return void + */ + protected function _mcrypt_initialize($params) + { + if ( ! empty($params['cipher'])) + { + $params['cipher'] = strtolower($params['cipher']); + $this->_cipher_alias($params['cipher']); + + if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE)) + { + log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.'); + } + else + { + $this->_cipher = $params['cipher']; + } + } + + if ( ! empty($params['mode'])) + { + if ( ! defined('MCRYPT_MODE_'.$params['mode'])) + { + log_message('error', 'Encryption: MCrypt mode '.strtotupper($params['mode']).' is not available.'); + } + else + { + $this->_mode = constant('MCRYPT_MODE_'.$params['mode']); + } + } + + if (isset($this->_cipher, $this->_mode)) + { + if (is_resource($this->_handle) + && (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher + OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode) + ) + { + mcrypt_module_close($this->_handle); + } + + if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, '')) + { + log_message('debug', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.'); + } + else + { + log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.'); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Initialize OpenSSL + * + * @param array $params Configuration parameters + * @return void + */ + protected function _openssl_initialize($params) + { + if ( ! empty($params['cipher'])) + { + $params['cipher'] = strtolower($params['cipher']); + $this->_cipher_alias($params['cipher']); + $this->_cipher = $params['cipher']; + } + + if ( ! empty($params['mode'])) + { + $this->_mode = strtolower($params['mode']); + } + + if (isset($this->_cipher, $this->_mode)) + { + // OpenSSL methods aren't suffixed with '-stream' for this mode + $handle = ($this->_mode === 'stream') + ? $this->_cipher + : $this->_cipher.'-'.$this->_mode; + + if ( ! in_array($handle, openssl_get_cipher_methods, TRUE)) + { + $this->_handle = NULL; + log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.'); + } + else + { + $this->_handle = $handle; + log_message('debug', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.'); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Encrypt + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + public function encrypt($data, array $params = NULL) + { + if (($params = $this->{'_'.$this->_driver.'_get_params'}($params)) === FALSE) + { + 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) + { + return FALSE; + } + + return ($params['base64']) + ? base64_encode($data) + : $data; + } + + // -------------------------------------------------------------------- + + /** + * Encrypt via MCrypt + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + protected function _mcrypt_encrypt($data, $params) + { + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + { + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return FALSE; + } + + // Use PKCS#7 padding in order to ensure compatibility with OpenSSL + // and other implementations outside of PHP + $block_size = mcrypt_enc_get_block_size($params['handle']); + $pad = $block_size - (strlen($data) % $block_size); + $data .= str_repeat(chr($pad), $pad); + + $data = $params['iv'].mcrypt_generic($params['handle'], $data); + + mcrypt_generic_deinit($params['handle']); + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($handle); + } + + return $data; + } + + // -------------------------------------------------------------------- + + /** + * Encrypt via OpenSSL + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + protected function _openssl_encrypt($data, $params) + { + $data = openssl_encrypt( + $data, + $params['handle'], + $params['key'], + 1, // DO NOT TOUCH! + $params['iv'] + ); + + if ($data === FALSE) + { + return FALSE; + } + + return $params['iv'].$data; + } + + // -------------------------------------------------------------------- + + /** + * Decrypt + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + public function decrypt($data, array $params = NULL) + { + if (($params = $this->{'_'.$this->_driver.'_get_params'}($params)) === FALSE) + { + return FALSE; + } + elseif ($params['base64']) + { + $data = base64_decode($data); + } + + if ( ! isset($params['iv'])) + { + if ($iv_size) + { + $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) + { + $data = substr($data, $iv_size); + } + + return $this->{'_'.$this->_driver.'_decrypt'}($data, $params); + } + + // -------------------------------------------------------------------- + + /** + * Decrypt via MCrypt + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + protected function _mcrypt_decrypt($data, $params) + { + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + { + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return FALSE; + } + + $data = mdecrypt_generic($params['handle'], $data); + + mcrypt_generic_deinit($params['handle']); + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($handle); + } + + // Remove PKCS#7 padding + return substr($data, 0, -ord($data[strlen($data)-1])); + } + + // -------------------------------------------------------------------- + + /** + * Decrypt via OpenSSL + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + protected function _openssl_decrypt($data, $params) + { + return openssl_decrypt( + $data, + $params['handle'], + $params['key'], + 1, // DO NOT TOUCH! + $params['iv'] + ); + } + + // -------------------------------------------------------------------- + + /** + * 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 + * + * @param int $size + * @return int + */ + protected function _mcrypt_get_iv($size) + { + // If /dev/urandom is available - use it, otherwise there's + // also /dev/random, but it is highly unlikely that it would + // be available while /dev/urandom is not and it is known to be + // blocking anyway. + if (defined(MCRYPT_DEV_URANDOM)) + { + $source = MCRYPT_DEV_URANDOM; + } + else + { + $source = MCRYPT_RAND; + is_php('5.3') OR srand(microtime(TRUE)); + } + + return mcrypt_create_iv($size, $source); + } + + // -------------------------------------------------------------------- + + /** + * Get IV via OpenSSL + * + * @param int $size IV size + * @return int + */ + protected function _openssl_get_iv($size) + { + return openssl_random_pseudo_bytes($size); + } + + // -------------------------------------------------------------------- + + /** + * Get MCrypt parameters + * + * @param array $params Input parameters + * @return array + */ + protected function _mcrypt_get_params($params) + { + if (empty($params)) + { + if ( ! isset($this->_cipher, $this->_mode, $params->_key, $this->_handle) OR ! is_resource($this->_handle)) + { + return FALSE; + } + + return array( + 'handle' => $this->_handle, + 'cipher' => $this->_cipher, + 'mode' => $this->_mode, + 'key' => $this->_key, + 'base64' => TRUE + ); + } + + $params = array( + 'handle' => NULL, + 'cipher' => isset($params['cipher']) ? $params['cipher'] : $this->_cipher, + 'mode' => isset($params['mode']) ? $params['mode'] : $this->_mode, + 'key' => isset($params['key']) ? $params['key'] : $this->_key, + 'iv' => isset($params['iv']) ? $params['iv'] : NULL, + 'base64' => isset($params['base64']) ? $params['base64'] : TRUE + ); + + if ( ! isset($params['cipher'], $params['mode'], $params['key'])) + { + return FALSE; + } + + $this->_cipher_alias($params['cipher']); + + if ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) + { + if (($params['handle'] = mcrypt_module_open($params['cipher'], '', $params['mode'], '')) === FALSE) + { + return FALSE; + } + } + else + { + if ( ! is_resource($this->_handle)) + { + return FALSE; + } + + $params['handle'] = $this->_handle; + } + + return $params; + } + + // -------------------------------------------------------------------- + + /** + * Get OpenSSL parameters + * + * @param array $params Input parameters + * @return array + */ + protected function _openssl_get_params($params) + { + if (empty($params)) + { + if ( ! isset($this->_cipher, $this->_mode, $params->_key, $this->_handle)) + { + return FALSE; + } + + return array( + 'handle' => $this->_handle, + 'cipher' => $this->_cipher, + 'mode' => $this->_mode, + 'key' => $this->_key, + 'base64' => TRUE + ); + } + + $params = array( + 'handle' => NULL, + 'cipher' => isset($params['cipher']) ? $params['cipher'] : $this->_cipher, + 'mode' => isset($params['mode']) ? $params['mode'] : $this->_mode, + 'key' => isset($params['key']) ? $params['key'] : $this->_key, + 'iv' => isset($params['iv']) ? $params['iv'] : NULL, + 'base64' => isset($params['base64']) ? $params['base64'] : TRUE + ); + + if ( ! isset($params['cipher'], $params['mode'], $params['key'])) + { + return FALSE; + } + + $this->_cipher_alias($params['cipher']); + + if ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) + { + // OpenSSL methods aren't suffixed with '-stream' for this mode + $params['handle'] = ($params['mode'] === 'stream') + ? $params['cipher'] + : $params['cipher'].'-'.$params['mode']; + $params['handle'] = $params['cipher'].'-'.$params['mode']; + } + else + { + if (empty($this->_handle)) + { + return FALSE; + } + + $params['handle'] = $this->_handle; + } + + return $params; + } + + // -------------------------------------------------------------------- + + /** + * Cipher alias + * + * Tries to translate cipher names between MCrypt and OpenSSL's "dialects". + * + * @param string $cipher Cipher name + * @return void + */ + protected function _cipher_alias(&$cipher) + { + static $dictionary; + + if (empty($dictionary)) + { + $dictionary = array( + 'mcrypt' => array( + 'rijndael-128', + 'tripledes', + 'arcfour' + ), + 'openssl' => array( + 'aes-128', + 'des-ede3', + 'rc4-40' + ) + ); + + // Notes regarding other seemingly matching ciphers between + // MCrypt and OpenSSL: + // + // - DES is compatible, but doesn't need an alias + // - Blowfish is NOT compatible + // mcrypt: 'blowfish', 'blowfish-compat' + // openssl: 'bf' + // - CAST-128/CAST5 is NOT compatible + // mcrypt: 'cast-128' + // openssl: 'cast5' + // - RC2 is NOT compatible + // mcrypt: 'rc2' + // openssl: 'rc2', 'rc2-40', 'rc2-64' + // + // To avoid any other confusion due to a popular (but incorrect) + // belief, it should also be noted that Rijndael-192/256 are NOT + // the same ciphers as AES-192/256 like Rijndael-128 and AES-256 is. + // + // All compatibility tests were done in CBC mode. + } + + $dialect = ($this->_driver === 'mcrypt') + ? 'openssl' + : 'mcrypt'; + if (($index = array_search($cipher, $dictionary[$dialect], TRUE)) !== FALSE) + { + $cipher = $dictionary[$this->_driver][$index]; + } + } + + // -------------------------------------------------------------------- + + /** + * __get() magic + * + * @param string $key Property name + * @return mixed + */ + public function __get($key) + { + return in_array($key, array('cipher', 'mode', 'driver', 'drivers'), TRUE) + ? $this->{'_'.$key} + : NULL; + } + +} + +/* End of file Encryption.php */ +/* Location: ./system/libraries/Encryption.php */ \ No newline at end of file -- cgit v1.2.3-24-g4f1b From 29cade43cc0a86c4a1a531c2649c4830d29ac2fc Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 4 Feb 2014 14:05:58 +0200 Subject: CI_Encryption improvements - HMAC authentication by default. - HKDF support. - Reduce code repetition. --- system/libraries/Encryption.php | 298 +++++++++++++++++++++++++++------------- 1 file changed, 199 insertions(+), 99 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 76569f281..6e71d6ee1 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -81,6 +81,20 @@ class CI_Encryption { */ protected $_drivers = array(); + /** + * List of supported HMAC algorightms + * + * name => digest size pairs + * + * @var array + */ + protected $_digests = array( + 'sha224' => 28, + 'sha256' => 32, + 'sha384' => 48, + 'sha512' => 64 + ); + // -------------------------------------------------------------------- /** @@ -102,6 +116,12 @@ class CI_Encryption { { return show_error('Encryption: Unable to find an available encryption driver.'); } + // Our configuration validates against the existence of MCRYPT_MODE_* constants, + // but MCrypt supports CTR mode without actually having a constant for it, so ... + elseif ($this->_drivers['mcrypt'] && ! defined('MCRYPT_MODE_CTR')) + { + define('MCRYPT_MODE_CTR', 'ctr'); + } $this->initialize($params); @@ -268,7 +288,7 @@ class CI_Encryption { */ public function encrypt($data, array $params = NULL) { - if (($params = $this->{'_'.$this->_driver.'_get_params'}($params)) === FALSE) + if (($params = $this->_get_params($params)) === FALSE) { return FALSE; } @@ -284,9 +304,28 @@ class CI_Encryption { return FALSE; } - return ($params['base64']) - ? base64_encode($data) - : $data; + if ($params['base64']) + { + $data = base64_encode($data); + } + + if ($params['hmac'] !== FALSE) + { + if ( ! isset($params['hmac']['key'])) + { + $params['hmac']['key'] = $this->hkdf( + $params['key'], + $params['hmac']['digest'], + NULL, + NULL, + 'authentication' + ); + } + + return hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], $params['base64']).$data; + } + + return $data; } // -------------------------------------------------------------------- @@ -300,7 +339,11 @@ class CI_Encryption { */ protected function _mcrypt_encrypt($data, $params) { - if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + if ( ! is_resource($params['handle'])) + { + return FALSE; + } + elseif (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { if ($params['handle'] !== $this->_handle) { @@ -338,6 +381,11 @@ class CI_Encryption { */ protected function _openssl_encrypt($data, $params) { + if (empty($params['handle'])) + { + return FALSE; + } + $data = openssl_encrypt( $data, $params['handle'], @@ -365,11 +413,39 @@ class CI_Encryption { */ public function decrypt($data, array $params = NULL) { - if (($params = $this->{'_'.$this->_driver.'_get_params'}($params)) === FALSE) + if (($params = $this->_get_params($params)) === FALSE) { return FALSE; } - elseif ($params['base64']) + + if ($params['hmac'] !== FALSE) + { + if ( ! isset($params['hmac']['key'])) + { + $params['hmac']['key'] = $this->hkdf( + $params['key'], + $params['hmac']['digest'], + NULL, + NULL, + 'authentication' + ); + } + + // This might look illogical, but it is done during encryption as well ... + // The 'base64' value is effectively a "raw data" parameter + $digest_size = ($params['base64']) + ? $this->_digests[$params['hmac']['digest']] * 2 + : $this->_digests[$params['hmac']['digest']]; + $hmac = substr($data, 0, $digest_size); + $data = substr($data, $digest_size); + + if ($hmac !== hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], $params['base64'])) + { + return FALSE; + } + } + + if ($params['base64']) { $data = base64_decode($data); } @@ -405,7 +481,11 @@ class CI_Encryption { */ protected function _mcrypt_decrypt($data, $params) { - if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + if ( ! is_resource($params['handle'])) + { + return FALSE; + } + elseif (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { if ($params['handle'] !== $this->_handle) { @@ -438,13 +518,15 @@ class CI_Encryption { */ protected function _openssl_decrypt($data, $params) { - return openssl_decrypt( - $data, - $params['handle'], - $params['key'], - 1, // DO NOT TOUCH! - $params['iv'] - ); + return empty($params['handle']) + ? FALSE + : openssl_decrypt( + $data, + $params['handle'], + $params['key'], + 1, // DO NOT TOUCH! + $params['iv'] + ); } // -------------------------------------------------------------------- @@ -516,88 +598,52 @@ class CI_Encryption { // -------------------------------------------------------------------- /** - * Get MCrypt parameters + * Get params * * @param array $params Input parameters * @return array */ - protected function _mcrypt_get_params($params) + protected function _get_params($params) { if (empty($params)) { - if ( ! isset($this->_cipher, $this->_mode, $params->_key, $this->_handle) OR ! is_resource($this->_handle)) - { - return FALSE; - } - - return array( - 'handle' => $this->_handle, - 'cipher' => $this->_cipher, - 'mode' => $this->_mode, - 'key' => $this->_key, - 'base64' => TRUE - ); + return isset($this->_cipher, $this->_mode, $params->_key, $this->_handle) + ? array( + 'handle' => $this->_handle, + 'cipher' => $this->_cipher, + 'mode' => $this->_mode, + 'key' => $this->_key, + 'base64' => TRUE, + 'hmac' => $this->_mode === 'gcm' ? FALSE : array('digest' => 'sha512', 'key' => NULL) + ) + : FALSE; } - - $params = array( - 'handle' => NULL, - 'cipher' => isset($params['cipher']) ? $params['cipher'] : $this->_cipher, - 'mode' => isset($params['mode']) ? $params['mode'] : $this->_mode, - 'key' => isset($params['key']) ? $params['key'] : $this->_key, - 'iv' => isset($params['iv']) ? $params['iv'] : NULL, - 'base64' => isset($params['base64']) ? $params['base64'] : TRUE - ); - - if ( ! isset($params['cipher'], $params['mode'], $params['key'])) + elseif ( ! isset($params['cipher'], $params['mode'], $params['key'])) { return FALSE; } - $this->_cipher_alias($params['cipher']); - - if ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) + if ($params['mode'] === 'gcm') { - if (($params['handle'] = mcrypt_module_open($params['cipher'], '', $params['mode'], '')) === FALSE) - { - return FALSE; - } + $params['hmac'] = FALSE; } - else + elseif ( ! isset($params['hmac']) OR ( ! is_array($params['hmac']) && $params['hmac'] !== FALSE)) { - if ( ! is_resource($this->_handle)) - { - return FALSE; - } - - $params['handle'] = $this->_handle; + $params['hmac'] = array( + 'digest' => 'sha512', + 'key' => NULL + ); } - - return $params; - } - - // -------------------------------------------------------------------- - - /** - * Get OpenSSL parameters - * - * @param array $params Input parameters - * @return array - */ - protected function _openssl_get_params($params) - { - if (empty($params)) + elseif (is_array($params['hmac'])) { - if ( ! isset($this->_cipher, $this->_mode, $params->_key, $this->_handle)) + if (isset($params['hmac']['digest']) && ! isset($this->_digests[$params['hmac']['digest']])) { return FALSE; } - return array( - 'handle' => $this->_handle, - 'cipher' => $this->_cipher, - 'mode' => $this->_mode, - 'key' => $this->_key, - 'base64' => TRUE + $params['hmac'] = array( + 'digest' => isset($params['hmac']['digest']) ? $params['hmac']['digest'] : 'sha512', + 'key' => isset($params['hmac']['key']) ? $params['hmac']['key'] : NULL ); } @@ -607,35 +653,47 @@ class CI_Encryption { 'mode' => isset($params['mode']) ? $params['mode'] : $this->_mode, 'key' => isset($params['key']) ? $params['key'] : $this->_key, 'iv' => isset($params['iv']) ? $params['iv'] : NULL, - 'base64' => isset($params['base64']) ? $params['base64'] : TRUE + 'base64' => isset($params['base64']) ? $params['base64'] : TRUE, + 'hmac' => $params['hmac'] ); - if ( ! isset($params['cipher'], $params['mode'], $params['key'])) - { - return FALSE; - } - $this->_cipher_alias($params['cipher']); + $params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) + ? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode']) + : $this->_handle; - if ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) - { - // OpenSSL methods aren't suffixed with '-stream' for this mode - $params['handle'] = ($params['mode'] === 'stream') - ? $params['cipher'] - : $params['cipher'].'-'.$params['mode']; - $params['handle'] = $params['cipher'].'-'.$params['mode']; - } - else - { - if (empty($this->_handle)) - { - return FALSE; - } + return $params; + } - $params['handle'] = $this->_handle; - } + // -------------------------------------------------------------------- - return $params; + /** + * Get MCrypt handle + * + * @param string $cipher Cipher name + * @param string $mode Encryption mode + * @return resource + */ + protected function _mcrypt_get_handle($cipher, $mode) + { + return mcrypt_module_open($cipher, '', $mode, ''); + } + + // -------------------------------------------------------------------- + + /** + * Get OpenSSL handle + * + * @param string $cipher Cipher name + * @param string $mode Encryption mode + * @return string + */ + protected function _openssl_get_handle($cipher, $mode) + { + // OpenSSL methods aren't suffixed with '-stream' for this mode + return ($mode === 'stream') + ? $cipher + : $cipher.'-'.$mode; } // -------------------------------------------------------------------- @@ -699,6 +757,48 @@ class CI_Encryption { // -------------------------------------------------------------------- + /** + * HKDF + * + * @link https://tools.ietf.org/rfc/rfc5869.txt + * @param $key Input key + * @param $digest A SHA-2 hashing algorithm + * @param $salt Optional salt + * @param $info Optional context/application-specific info + * @param $length Output length (defaults to the selected digest size) + * @return string A pseudo-random key + */ + public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '') + { + if ( ! isset($this->_digests[$digest])) + { + return FALSE; + } + + if (empty($length) OR ! is_int($length)) + { + $length = $this->_digests[$digest]; + } + elseif ($length > (255 * $this->_digests[$digest])) + { + return FALSE; + } + + isset($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]); + + $prk = hash_hmac($digest, $key, $salt, TRUE); + $key = ''; + for ($key_block = '', $block_index = 1; strlen($key) < $length; $block_index++) + { + $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE); + $key .= $key_block; + } + + return substr($key, 0, $length); + } + + // -------------------------------------------------------------------- + /** * __get() magic * -- cgit v1.2.3-24-g4f1b From 912831f589862c205d5b9837b710aa391460e08d Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 4 Feb 2014 17:21:37 +0200 Subject: CI_Encryption: Fix some errors and add unit tests for hkdf() --- system/libraries/Encryption.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 6e71d6ee1..4258aee53 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -125,15 +125,6 @@ class CI_Encryption { $this->initialize($params); - if (empty($this->_driver)) - { - $this->_driver = ($this->_drivers['mcrypt'] === TRUE) - ? 'mcrypt' - : 'openssl'; - - log_message('debug', "Encryption: Auto-configured driver '".$params['driver']."'."); - } - isset($this->_key) OR $this->_key = config_item('encryption_key'); if (empty($this->_key)) { @@ -172,6 +163,15 @@ class CI_Encryption { } } + if (empty($this->_driver)) + { + $this->_driver = ($this->_drivers['mcrypt'] === TRUE) + ? 'mcrypt' + : 'openssl'; + + log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'."); + } + empty($params['key']) OR $this->_key = $params['key']; $this->{'_'.$this->_driver.'_initialize'}($params); return $this; @@ -807,7 +807,7 @@ class CI_Encryption { */ public function __get($key) { - return in_array($key, array('cipher', 'mode', 'driver', 'drivers'), TRUE) + return in_array($key, array('cipher', 'mode', 'driver', 'drivers', 'digests'), TRUE) ? $this->{'_'.$key} : NULL; } -- cgit v1.2.3-24-g4f1b From 177144ff7d7c8afcfd4469efabf4733879a2e570 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 4 Feb 2014 18:07:34 +0200 Subject: Fix a logical error in CI_Encryption --- system/libraries/Encryption.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 4258aee53..3c1347523 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -322,7 +322,7 @@ class CI_Encryption { ); } - return hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], $params['base64']).$data; + return hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], ! $params['base64']).$data; } return $data; @@ -432,14 +432,14 @@ class CI_Encryption { } // This might look illogical, but it is done during encryption as well ... - // The 'base64' value is effectively a "raw data" parameter + // The 'base64' value is effectively an inverted "raw data" parameter $digest_size = ($params['base64']) ? $this->_digests[$params['hmac']['digest']] * 2 : $this->_digests[$params['hmac']['digest']]; $hmac = substr($data, 0, $digest_size); $data = substr($data, $digest_size); - if ($hmac !== hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], $params['base64'])) + if ($hmac !== hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], ! $params['base64'])) { return FALSE; } -- cgit v1.2.3-24-g4f1b From 50ccc38a8c07b412aad0c26afb0775a0d9be18ee Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 4 Feb 2014 23:30:06 +0200 Subject: CI_Encryption: Fix more errors and add a 'portability' test case --- system/libraries/Encryption.php | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 3c1347523..2d3f82dc8 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -148,7 +148,7 @@ class CI_Encryption { { if (isset($this->_drivers[$params['driver']])) { - if ($this->_driver[$params['driver']]) + if ($this->_drivers[$params['driver']]) { $this->_driver = $params['driver']; } @@ -264,7 +264,7 @@ class CI_Encryption { ? $this->_cipher : $this->_cipher.'-'.$this->_mode; - if ( ! in_array($handle, openssl_get_cipher_methods, TRUE)) + if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE)) { $this->_handle = NULL; log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.'); @@ -364,7 +364,7 @@ class CI_Encryption { mcrypt_generic_deinit($params['handle']); if ($params['handle'] !== $this->_handle) { - mcrypt_module_close($handle); + mcrypt_module_close($params['handle']); } return $data; @@ -452,7 +452,8 @@ class CI_Encryption { if ( ! isset($params['iv'])) { - if ($iv_size) + $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); @@ -500,7 +501,7 @@ class CI_Encryption { mcrypt_generic_deinit($params['handle']); if ($params['handle'] !== $this->_handle) { - mcrypt_module_close($handle); + mcrypt_module_close($params['handle']); } // Remove PKCS#7 padding @@ -607,7 +608,7 @@ class CI_Encryption { { if (empty($params)) { - return isset($this->_cipher, $this->_mode, $params->_key, $this->_handle) + return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle) ? array( 'handle' => $this->_handle, 'cipher' => $this->_cipher, @@ -714,14 +715,16 @@ class CI_Encryption { { $dictionary = array( 'mcrypt' => array( - 'rijndael-128', - 'tripledes', - 'arcfour' + 'aes-128' => 'rijndael-128', + 'aes-192' => 'rijndael-128', + 'aes-256' => 'rijndael-128', + 'des3-ede3' => 'tripledes', + 'rc4-40' => 'arcfour' ), 'openssl' => array( - 'aes-128', - 'des-ede3', - 'rc4-40' + 'rijndael-128' => 'aes-128', + 'tripledes' => 'des-ede3', + 'arcfour' => 'rc4-40' ) ); @@ -746,12 +749,9 @@ class CI_Encryption { // All compatibility tests were done in CBC mode. } - $dialect = ($this->_driver === 'mcrypt') - ? 'openssl' - : 'mcrypt'; - if (($index = array_search($cipher, $dictionary[$dialect], TRUE)) !== FALSE) + if (isset($dictionary[$this->_driver][$cipher])) { - $cipher = $dictionary[$this->_driver][$index]; + $cipher = $dictionary[$this->_driver][$cipher]; } } -- cgit v1.2.3-24-g4f1b From 9108dd4e33cf139337e83ff969b2d38fee5ae2f8 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Tue, 4 Feb 2014 23:33:41 +0200 Subject: CI_Encryption: Remove ARCFour from aliased ciphers due ... Seems like there are some issues with it --- system/libraries/Encryption.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 2d3f82dc8..503fb64e3 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -718,13 +718,11 @@ class CI_Encryption { 'aes-128' => 'rijndael-128', 'aes-192' => 'rijndael-128', 'aes-256' => 'rijndael-128', - 'des3-ede3' => 'tripledes', - 'rc4-40' => 'arcfour' + 'des3-ede3' => 'tripledes' ), 'openssl' => array( 'rijndael-128' => 'aes-128', - 'tripledes' => 'des-ede3', - 'arcfour' => 'rc4-40' + 'tripledes' => 'des-ede3' ) ); -- cgit v1.2.3-24-g4f1b From 4a2918a33c756ac7cc9defc2e6acd371e4412af6 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 01:03:46 +0200 Subject: Integrate CI_Encryption into the framework TODO: Add documentation in user_guide_src/source/libraries/encryption.rst --- .../libraries/Session/drivers/Session_cookie.php | 55 ++++++++++++---------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index 971dfeabe..5d338fc04 100644 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -240,7 +240,7 @@ class CI_Session_cookie extends CI_Session_driver { // Do we need encryption? If so, load the encryption class if ($this->sess_encrypt_cookie === TRUE) { - $this->CI->load->library('encrypt'); + $this->CI->load->library('encryption'); } // Check for database @@ -383,30 +383,33 @@ class CI_Session_cookie extends CI_Session_driver { return FALSE; } - $len = strlen($session) - 40; - - if ($len < 0) + if ($this->sess_encrypt_cookie === TRUE) { - log_message('debug', 'The session cookie was not signed.'); - return FALSE; + $session = $this->CI->encryption->decrypt($session); + if ($session === FALSE) + { + log_message('error', 'Session: Unable to decrypt the session cookie, possibly due to a HMAC mismatch.'); + return FALSE; + } } - - // Check cookie authentication - $hmac = substr($session, $len); - $session = substr($session, 0, $len); - - if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key)) + else { - log_message('error', 'The session cookie data did not match what was expected.'); - $this->sess_destroy(); - return FALSE; - } + if (($len = strlen($session) - 40) <= 0) + { + log_message('error', 'Session: The session cookie was not signed.'); + return FALSE; + } - // Check for encryption - if ($this->sess_encrypt_cookie === TRUE) - { - // Decrypt the cookie data - $session = $this->CI->encrypt->decode($session); + // Check cookie authentication + $hmac = substr($session, $len); + $session = substr($session, 0, $len); + + if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key)) + { + log_message('error', 'Session: HMAC mismatch. The session cookie data did not match what was expected.'); + $this->sess_destroy(); + return FALSE; + } } // Unserialize the session array @@ -723,11 +726,13 @@ class CI_Session_cookie extends CI_Session_driver { if ($this->sess_encrypt_cookie === TRUE) { - $cookie_data = $this->CI->encrypt->encode($cookie_data); + $cookie_data = $this->CI->encryption->encrypt($cookie_data); + } + else + { + // Require message authentication + $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); } - - // Require message authentication - $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); -- cgit v1.2.3-24-g4f1b 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 From d9a48da095e2b76c65b1b9ebd26b6f06c94cb0e5 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 14:10:28 +0200 Subject: CI_Encryption: Add Blowfish to compatibility list --- system/libraries/Encryption.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 2228ca3a6..d1aed7399 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -734,21 +734,25 @@ class CI_Encryption { 'aes-128' => 'rijndael-128', 'aes-192' => 'rijndael-128', 'aes-256' => 'rijndael-128', - 'des3-ede3' => 'tripledes' + 'des3-ede3' => 'tripledes', + 'bf' => 'blowfish', ), 'openssl' => array( 'rijndael-128' => 'aes-128', - 'tripledes' => 'des-ede3' + 'tripledes' => 'des-ede3', + 'blowfish' => 'bf' ) ); - // Notes regarding other seemingly matching ciphers between - // MCrypt and OpenSSL: + // Notes: + // + // - Blowfish is said to be supporting key sizes between + // 4 and 56 bytes, but it appears that between MCrypt and + // OpenSSL, only those of 16 and more bytes are compatible. + // + // Other seemingly matching ciphers between MCrypt, OpenSSL: // // - DES is compatible, but doesn't need an alias - // - Blowfish is NOT compatible - // mcrypt: 'blowfish', 'blowfish-compat' - // openssl: 'bf' // - CAST-128/CAST5 is NOT compatible // mcrypt: 'cast-128' // openssl: 'cast5' -- cgit v1.2.3-24-g4f1b From f401767c04a24677e11a3b6c4e3590e8b2e06e88 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 18:51:15 +0200 Subject: CI_Encryption: More MCrypt/OpenSSL compatibility and get rid of the MCRYPT_MODE_* constants --- system/libraries/Encryption.php | 86 +++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 17 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index d1aed7399..51e390c91 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -81,6 +81,35 @@ class CI_Encryption { */ protected $_drivers = array(); + /** + * List of available modes + * + * @var array + */ + protected $_modes = array( + 'mcrypt' => array( + 'cbc' => 'cbc', + 'ecb' => 'ecb', + 'ofb' => 'nofb', + 'ofb8' => 'ofb', + 'cfb' => 'ncfb', + 'cfb8' => 'cfb', + 'ctr' => 'ctr', + 'stream' => 'stream' + ), + 'openssl' => array( + 'cbc' => 'cbc', + 'ecb' => 'ecb', + 'ofb' => 'ofb', + 'cfb' => 'cfb', + 'cfb8' => 'cfb8', + 'ctr' => 'ctr', + 'stream' => '', + 'gcm' => 'gcm', + 'xts' => 'xts' + ) + ); + /** * List of supported HMAC algorightms * @@ -116,12 +145,6 @@ class CI_Encryption { { return show_error('Encryption: Unable to find an available encryption driver.'); } - // Our configuration validates against the existence of MCRYPT_MODE_* constants, - // but MCrypt supports CTR mode without actually having a constant for it, so ... - elseif ($this->_drivers['mcrypt'] && ! defined('MCRYPT_MODE_CTR')) - { - define('MCRYPT_MODE_CTR', 'ctr'); - } $this->initialize($params); @@ -204,13 +227,14 @@ class CI_Encryption { if ( ! empty($params['mode'])) { - if ( ! defined('MCRYPT_MODE_'.$params['mode'])) + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes['mcrypt'][$params['mode']])) { log_message('error', 'Encryption: MCrypt mode '.strtotupper($params['mode']).' is not available.'); } else { - $this->_mode = constant('MCRYPT_MODE_'.$params['mode']); + $this->_mode = $this->_modes['mcrypt'][$params['mode']]; } } @@ -254,13 +278,21 @@ class CI_Encryption { if ( ! empty($params['mode'])) { - $this->_mode = strtolower($params['mode']); + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes['openssl'][$params['mode']])) + { + log_message('error', 'Encryption: OpenSSL mode '.strtotupper($params['mode']).' is not available.'); + } + else + { + $this->_mode = $this->_modes['openssl'][$params['mode']]; + } } if (isset($this->_cipher, $this->_mode)) { - // OpenSSL methods aren't suffixed with '-stream' for this mode - $handle = ($this->_mode === 'stream') + // This is mostly for the stream mode, which doesn't get suffixed in OpenSSL + $handle = empty($this->_mode) ? $this->_cipher : $this->_cipher.'-'.$this->_mode; @@ -356,10 +388,13 @@ class CI_Encryption { } // Use PKCS#7 padding in order to ensure compatibility with OpenSSL - // and other implementations outside of PHP - $block_size = mcrypt_enc_get_block_size($params['handle']); - $pad = $block_size - (strlen($data) % $block_size); - $data .= str_repeat(chr($pad), $pad); + // and other implementations outside of PHP. + if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) + { + $block_size = mcrypt_enc_get_block_size($params['handle']); + $pad = $block_size - (strlen($data) % $block_size); + $data .= str_repeat(chr($pad), $pad); + } // Work-around for yet another strange behavior in MCrypt. // @@ -526,6 +561,11 @@ class CI_Encryption { } $data = mdecrypt_generic($params['handle'], $data); + // Remove PKCS#7 padding, if necessary + if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) + { + $data = substr($data, 0, -ord($data[strlen($data)-1])); + } mcrypt_generic_deinit($params['handle']); if ($params['handle'] !== $this->_handle) @@ -533,8 +573,7 @@ class CI_Encryption { mcrypt_module_close($params['handle']); } - // Remove PKCS#7 padding - return substr($data, 0, -ord($data[strlen($data)-1])); + return $data; } // -------------------------------------------------------------------- @@ -664,6 +703,19 @@ class CI_Encryption { ); } + if (isset($params['mode'])) + { + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes[$this->_driver][$params['mode']])) + { + return FALSE; + } + else + { + $params['mode'] = $this->_modes[$this->_driver][$params['mode']]; + } + } + $params = array( 'handle' => NULL, 'cipher' => isset($params['cipher']) ? $params['cipher'] : $this->_cipher, -- cgit v1.2.3-24-g4f1b From 8e20216f25624524d7d6e0322e85e6ccb47e3778 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 18:59:55 +0200 Subject: More CI_Encryption improvements - Make OpenSSL the default driver if available (because MCrypt is stupid). - Require MCRYPT_DEV_URANDOM for the MCrypt availability check (because security; also, incidentally - it's faster that way ;)). --- system/libraries/Encryption.php | 52 +++++------------------------------------ 1 file changed, 6 insertions(+), 46 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 51e390c91..fe177fce3 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -135,7 +135,7 @@ class CI_Encryption { public function __construct(array $params = array()) { $this->_drivers = array( - 'mcrypt' => extension_loaded('mcrypt'), + 'mcrypt' => defined('MCRYPT_DEV_URANDOM'), // While OpenSSL is available for PHP 5.3.0, an IV parameter // for the encrypt/decrypt functions is only available since 5.3.3 'openssl' => (is_php('5.3.3') && extension_loaded('openssl')) @@ -188,9 +188,9 @@ class CI_Encryption { if (empty($this->_driver)) { - $this->_driver = ($this->_drivers['mcrypt'] === TRUE) - ? 'mcrypt' - : 'openssl'; + $this->_driver = ($this->_drivers['openssl'] === TRUE) + ? 'openssl' + : 'mcrypt'; log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'."); } @@ -372,7 +372,7 @@ class CI_Encryption { elseif ( ! isset($params['iv'])) { $params['iv'] = ($iv_size = mcrypt_enc_get_iv_size($params['handle'])) - ? $this->_mcrypt_get_iv($iv_size) + ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM) : NULL; } @@ -438,7 +438,7 @@ class CI_Encryption { elseif ( ! isset($params['iv'])) { $params['iv'] = ($iv_size = openssl_cipher_iv_length($params['handle'])) - ? $this->_openssl_get_iv($iv_size) + ? openssl_random_pseudo_bytes($iv_size) : NULL; } @@ -613,46 +613,6 @@ class CI_Encryption { // -------------------------------------------------------------------- - /** - * Get IV via MCrypt - * - * @param int $size - * @return int - */ - protected function _mcrypt_get_iv($size) - { - // If /dev/urandom is available - use it, otherwise there's - // also /dev/random, but it is highly unlikely that it would - // be available while /dev/urandom is not and it is known to be - // blocking anyway. - if (defined(MCRYPT_DEV_URANDOM)) - { - $source = MCRYPT_DEV_URANDOM; - } - else - { - $source = MCRYPT_RAND; - is_php('5.3') OR srand(microtime(TRUE)); - } - - return mcrypt_create_iv($size, $source); - } - - // -------------------------------------------------------------------- - - /** - * Get IV via OpenSSL - * - * @param int $size IV size - * @return int - */ - protected function _openssl_get_iv($size) - { - return openssl_random_pseudo_bytes($size); - } - - // -------------------------------------------------------------------- - /** * Get params * -- cgit v1.2.3-24-g4f1b From 8d33a9a4a8ac924678ae5bba6387ca7fce206f4b Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Wed, 5 Feb 2014 23:11:23 +0200 Subject: CI_Encryption: HMAC to not be derived from the encryption key --- system/libraries/Encryption.php | 114 ++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 58 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index fe177fce3..36975e585 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -324,31 +324,27 @@ class CI_Encryption { { return FALSE; } + elseif ( ! isset($params['key'])) + { + if ( ! isset($this->_key)) + { + return show_error('Encryption: You are required to set an encryption key in your configuration.'); + } + + $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + } if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE) { return FALSE; } - if ($params['base64']) - { - $data = base64_encode($data); - } + $params['base64'] && $data = base64_encode($data); - if ($params['hmac'] !== FALSE) + if (isset($params['hmac_digest'])) { - if ( ! isset($params['hmac']['key'])) - { - $params['hmac']['key'] = $this->hkdf( - $params['key'], - $params['hmac']['digest'], - NULL, - NULL, - 'authentication' - ); - } - - return hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], ! $params['base64']).$data; + isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); + return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data; } return $data; @@ -473,29 +469,29 @@ class CI_Encryption { { return FALSE; } - - if ($params['hmac'] !== FALSE) + elseif ( ! isset($params['key'])) { - if ( ! isset($params['hmac']['key'])) + if ( ! isset($this->_key)) { - $params['hmac']['key'] = $this->hkdf( - $params['key'], - $params['hmac']['digest'], - NULL, - NULL, - 'authentication' - ); + return show_error('Encryption: You are required to set an encryption key in your configuration.'); } + $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + } + + if (isset($params['hmac_digest'])) + { + isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); + // This might look illogical, but it is done during encryption as well ... // The 'base64' value is effectively an inverted "raw data" parameter $digest_size = ($params['base64']) - ? $this->_digests[$params['hmac']['digest']] * 2 - : $this->_digests[$params['hmac']['digest']]; + ? $this->_digests[$params['hmac_digest']] * 2 + : $this->_digests[$params['hmac_digest']]; $hmac = substr($data, 0, $digest_size); $data = substr($data, $digest_size); - if ($hmac !== hash_hmac($params['hmac']['digest'], $data, $params['hmac']['key'], ! $params['base64'])) + if ($hmac !== hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64'])) { return FALSE; } @@ -628,9 +624,10 @@ class CI_Encryption { 'handle' => $this->_handle, 'cipher' => $this->_cipher, 'mode' => $this->_mode, - 'key' => $this->_key, + 'key' => NULL, 'base64' => TRUE, - 'hmac' => $this->_mode === 'gcm' ? FALSE : array('digest' => 'sha512', 'key' => NULL) + 'hmac_digest' => ($this->_mode !== 'gcm' ? 'sha512' : NULL), + 'hmac_key' => NULL ) : FALSE; } @@ -639,51 +636,52 @@ class CI_Encryption { return FALSE; } - if ($params['mode'] === 'gcm') - { - $params['hmac'] = FALSE; - } - elseif ( ! isset($params['hmac']) OR ( ! is_array($params['hmac']) && $params['hmac'] !== FALSE)) - { - $params['hmac'] = array( - 'digest' => 'sha512', - 'key' => NULL - ); - } - elseif (is_array($params['hmac'])) + if (isset($params['mode'])) { - if (isset($params['hmac']['digest']) && ! isset($this->_digests[$params['hmac']['digest']])) + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes[$this->_driver][$params['mode']])) { return FALSE; } - - $params['hmac'] = array( - 'digest' => isset($params['hmac']['digest']) ? $params['hmac']['digest'] : 'sha512', - 'key' => isset($params['hmac']['key']) ? $params['hmac']['key'] : NULL - ); + else + { + $params['mode'] = $this->_modes[$this->_driver][$params['mode']]; + } } - if (isset($params['mode'])) + if ($params['mode'] === 'gcm' OR isset($params['hmac']) && $params['hmac'] === FALSE) { - $params['mode'] = strtolower($params['mode']); - if ( ! isset($this->_modes[$this->_driver][$params['mode']])) + $params['hmac_digest'] = $params['hmac_key'] = NULL; + } + else + { + if ( ! isset($params['hmac_key'])) { return FALSE; } + elseif (isset($params['hmac_digest'])) + { + $params['hmac_digest'] = strtolower($params['hmac_digest']); + if ( ! isset($this->_digests[$params['hmac_digest']])) + { + return FALSE; + } + } else { - $params['mode'] = $this->_modes[$this->_driver][$params['mode']]; + $params['hmac_digest'] = 'sha512'; } } $params = array( 'handle' => NULL, - 'cipher' => isset($params['cipher']) ? $params['cipher'] : $this->_cipher, - 'mode' => isset($params['mode']) ? $params['mode'] : $this->_mode, - 'key' => isset($params['key']) ? $params['key'] : $this->_key, + 'cipher' => $params['cipher'], + 'mode' => $params['mode'], + 'key' => $params['key'], 'iv' => isset($params['iv']) ? $params['iv'] : NULL, 'base64' => isset($params['base64']) ? $params['base64'] : TRUE, - 'hmac' => $params['hmac'] + 'hmac_digest' => $params['hmac_digest'], + 'hmac_key' => $params['hmac_key'] ); $this->_cipher_alias($params['cipher']); -- cgit v1.2.3-24-g4f1b From 7c5544817de29222aa2d79ac7445122d57ad62c6 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 6 Feb 2014 02:38:27 +0200 Subject: CI_Encryption: Time-attack-safe HMAC verification --- system/libraries/Encryption.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 36975e585..f5950ee46 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -481,17 +481,31 @@ class CI_Encryption { if (isset($params['hmac_digest'])) { - isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); - // This might look illogical, but it is done during encryption as well ... // The 'base64' value is effectively an inverted "raw data" parameter $digest_size = ($params['base64']) ? $this->_digests[$params['hmac_digest']] * 2 : $this->_digests[$params['hmac_digest']]; - $hmac = substr($data, 0, $digest_size); + + if (strlen($data) <= $digest_size) + { + return FALSE; + } + + $hmac_input = substr($data, 0, $digest_size); $data = substr($data, $digest_size); - if ($hmac !== hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64'])) + isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); + $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']); + + // Time-attack-safe comparison + $diff = 0; + for ($i = 0; $i < $digest_size; $i++) + { + $diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]); + } + + if ($diff !== 0) { return FALSE; } -- cgit v1.2.3-24-g4f1b From e8088d693d6bd8b08c1cdc397bbdebd7067844a5 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Thu, 6 Feb 2014 05:01:48 +0200 Subject: CI_Encryption: CAST-128/CAST5 and RC4/ARCFour compatibility --- system/libraries/Encryption.php | 65 +++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 15 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index f5950ee46..583ddac3b 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -367,11 +367,21 @@ class CI_Encryption { } elseif ( ! isset($params['iv'])) { - $params['iv'] = ($iv_size = mcrypt_enc_get_iv_size($params['handle'])) + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + $params['iv'] = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM) : NULL; } + // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt) + // + // RFC2144 says that keys shorter than 16 bytes are to be padded with + // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that. + if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16) + { + $params['key'] .= str_repeat("\x0", 16 - $kl); + } if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { @@ -541,7 +551,9 @@ class CI_Encryption { } elseif ( ! isset($params['iv'])) { - if ($iv_size = mcrypt_enc_get_iv_size($params['handle'])) + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) { if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') { @@ -560,6 +572,15 @@ class CI_Encryption { } } + // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt) + // + // RFC2144 says that keys shorter than 16 bytes are to be padded with + // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that. + if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16) + { + $params['key'] .= str_repeat("\x0", 16 - $kl); + } + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) { if ($params['handle'] !== $this->_handle) @@ -760,35 +781,49 @@ class CI_Encryption { 'aes-256' => 'rijndael-128', 'des3-ede3' => 'tripledes', 'bf' => 'blowfish', + 'cast5' => 'cast-128', + 'rc4' => 'arcfour', + 'rc4-40' => 'arcfour' ), 'openssl' => array( 'rijndael-128' => 'aes-128', 'tripledes' => 'des-ede3', - 'blowfish' => 'bf' + 'blowfish' => 'bf', + 'cast-128' => 'cast5', + 'arcfour' => 'rc4-40', + 'rc4' => 'rc4-40' ) ); // Notes: // + // - Rijndael-128 is, at the same time all three of AES-128, + // AES-192 and AES-256. The only difference between them is + // the key size. Rijndael-192, Rijndael-256 on the other hand + // also have different block sizes and are NOT AES-compatible. + // // - Blowfish is said to be supporting key sizes between // 4 and 56 bytes, but it appears that between MCrypt and // OpenSSL, only those of 16 and more bytes are compatible. + // Also, don't know what MCrypt's 'blowfish-compat' is. // - // Other seemingly matching ciphers between MCrypt, OpenSSL: + // - CAST-128/CAST5 produces a longer cipher when encrypted via + // OpenSSL, but (strangely enough) can be decrypted by either + // extension anyway. + // Also, RFC2144 says that the cipher supports key sizes + // between 5 and 16 bytes by the implementation actually + // zero-padding them to 16 bytes, but MCrypt doesn't do that. // - // - DES is compatible, but doesn't need an alias - // - CAST-128/CAST5 is NOT compatible - // mcrypt: 'cast-128' - // openssl: 'cast5' - // - RC2 is NOT compatible - // mcrypt: 'rc2' - // openssl: 'rc2', 'rc2-40', 'rc2-64' + // - RC4 (ARCFour) has a strange implementation under OpenSSL. + // Its 'rc4-40' cipher method seems to work flawlessly, yet + // there's another one, 'rc4' that only works with a 16-byte key. // - // To avoid any other confusion due to a popular (but incorrect) - // belief, it should also be noted that Rijndael-192/256 are NOT - // the same ciphers as AES-192/256 like Rijndael-128 and AES-256 is. + // - DES is compatible, but doesn't need an alias. + // + // Other seemingly matching ciphers between MCrypt, OpenSSL: // - // All compatibility tests were done in CBC mode. + // - RC2 is NOT compatible and only an obscure forum post + // confirms that it is MCrypt's fault. } if (isset($dictionary[$this->_driver][$cipher])) -- cgit v1.2.3-24-g4f1b From 81e10644861c86437cf197b54af096894b41cd63 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Fri, 7 Feb 2014 01:43:36 +0200 Subject: CI_Encryption: Optimizations and test cases --- system/libraries/Encryption.php | 44 +++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 26 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index 583ddac3b..e03e278fa 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -44,7 +44,7 @@ class CI_Encryption { * * @var string */ - protected $_cipher = 'rijndael-128'; + protected $_cipher = 'aes-128'; /** * Cipher mode @@ -147,11 +147,9 @@ class CI_Encryption { } $this->initialize($params); - - isset($this->_key) OR $this->_key = config_item('encryption_key'); - if (empty($this->_key)) + if ( ! isset($this->_key) && strlen($key = config_item('encryption_key')) > 0) { - return show_error('Encryption: You are required to set an encryption key in your configuration.'); + $this->_key = $key; } log_message('debug', 'Encryption Class Initialized'); @@ -324,15 +322,8 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['key'])) - { - if ( ! isset($this->_key)) - { - return show_error('Encryption: You are required to set an encryption key in your configuration.'); - } - $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); - } + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE) { @@ -479,15 +470,6 @@ class CI_Encryption { { return FALSE; } - elseif ( ! isset($params['key'])) - { - if ( ! isset($this->_key)) - { - return show_error('Encryption: You are required to set an encryption key in your configuration.'); - } - - $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); - } if (isset($params['hmac_digest'])) { @@ -531,6 +513,8 @@ class CI_Encryption { $data = substr($data, $iv_size); } + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + return $this->{'_'.$this->_driver.'_decrypt'}($data, $params); } @@ -684,7 +668,7 @@ class CI_Encryption { } } - if ($params['mode'] === 'gcm' OR isset($params['hmac']) && $params['hmac'] === FALSE) + if ($params['mode'] === 'gcm' OR (isset($params['hmac']) && $params['hmac'] === FALSE)) { $params['hmac_digest'] = $params['hmac_key'] = NULL; } @@ -884,9 +868,17 @@ class CI_Encryption { */ public function __get($key) { - return in_array($key, array('cipher', 'mode', 'driver', 'drivers', 'digests'), TRUE) - ? $this->{'_'.$key} - : NULL; + // Because aliases + if ($key === 'mode') + { + return array_search($this->_mode, $this->_modes[$this->_driver], TRUE); + } + elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE)) + { + return $this->{'_'.$key}; + } + + return NULL; } } -- cgit v1.2.3-24-g4f1b From 505b3d6b42d608b8555b62b78134f697a1f6d09f Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Sat, 8 Feb 2014 18:24:00 +0200 Subject: Make CI_Email::set_alt_message() parameter mandatory (optional doesn't make sense) --- system/libraries/Email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'system/libraries') diff --git a/system/libraries/Email.php b/system/libraries/Email.php index f4efff882..88925e03f 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -822,7 +822,7 @@ class CI_Email { * @param string * @return CI_Email */ - public function set_alt_message($str = '') + public function set_alt_message($str) { $this->alt_message = (string) $str; return $this; -- cgit v1.2.3-24-g4f1b From a89c1dabd11e8628106b1629f76ec9fc65c20085 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Sat, 8 Feb 2014 19:03:35 +0200 Subject: Method chaining support for FV set_data(), reset_validation() --- system/libraries/Form_validation.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 58485916c..7c441409f 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -252,7 +252,7 @@ class CI_Form_validation { * each array due to the limitations of CI's singleton * * @param array $data - * @return void + * @return CI_Form_validation */ public function set_data(array $data) { @@ -260,6 +260,8 @@ class CI_Form_validation { { $this->validation_data = $data; } + + return $this; } // -------------------------------------------------------------------- @@ -1536,7 +1538,7 @@ class CI_Form_validation { * Prevents subsequent validation routines from being affected by the * results of any previous validation routine due to the CI singleton. * - * @return void + * @return CI_Form_validation */ public function reset_validation() { @@ -1545,6 +1547,7 @@ class CI_Form_validation { $this->_error_array = array(); $this->_error_messages = array(); $this->error_string = ''; + return $this; } } -- cgit v1.2.3-24-g4f1b From 6f6102c805198101fad36024b82692ebce20f2c8 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Sat, 8 Feb 2014 19:11:40 +0200 Subject: Add method chaining support to Calendar & Pagination libs --- system/libraries/Calendar.php | 10 +++++++--- system/libraries/Pagination.php | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index fc6599931..610b427cf 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -139,7 +139,7 @@ class CI_Calendar { * Accepts an associative array as input, containing display preferences * * @param array config preferences - * @return void + * @return CI_Calendar */ public function initialize($config = array()) { @@ -156,6 +156,8 @@ class CI_Calendar { { $this->next_prev_url = $this->CI->config->site_url($this->CI->router->class.'/'.$this->CI->router->method); } + + return $this; } // -------------------------------------------------------------------- @@ -513,7 +515,7 @@ class CI_Calendar { * Harvests the data within the template {pseudo-variables} * used to display the calendar * - * @return void + * @return CI_Calendar */ public function parse_template() { @@ -521,7 +523,7 @@ class CI_Calendar { if ($this->template === '') { - return; + return $this; } $today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today'); @@ -537,6 +539,8 @@ class CI_Calendar { $this->temp[$val] = $this->temp[substr($val, 0, -6)]; } } + + return $this; } } diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index c6ffd03d4..f67cb47f8 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -314,7 +314,7 @@ class CI_Pagination { * Initialize Preferences * * @param array $params Initialization parameters - * @return void + * @return CI_Pagination */ public function initialize($params = array()) { @@ -342,6 +342,8 @@ class CI_Pagination { } } } + + return $this; } // -------------------------------------------------------------------- -- cgit v1.2.3-24-g4f1b From 1f5909527f5a4984d4fa0a1f3bd51aa5bd850406 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Sat, 8 Feb 2014 19:50:26 +0200 Subject: Add method chaining support to CI_Table --- system/libraries/Table.php | 72 ++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Table.php b/system/libraries/Table.php index b77fcf19d..1d4320855 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -117,7 +117,7 @@ class CI_Table { /** * Set the template * - * @param array + * @param array $template * @return bool */ public function set_template($template) @@ -139,12 +139,13 @@ class CI_Table { * Can be passed as an array or discreet params * * @param mixed - * @return void + * @return CI_Table */ public function set_heading($args = array()) { $args = func_get_args(); $this->heading = $this->_prep_args($args); + return $this; } // -------------------------------------------------------------------- @@ -155,9 +156,9 @@ class CI_Table { * columns. This allows a single array with many elements to be * displayed in a table that has a fixed column count. * - * @param array - * @param int - * @return void + * @param array $array + * @param int $col_limit + * @return array */ public function make_columns($array = array(), $col_limit = 0) { @@ -202,12 +203,13 @@ class CI_Table { * * Can be passed as an array or discreet params * - * @param mixed - * @return void + * @param mixed $value + * @return CI_Table */ public function set_empty($value) { $this->empty_cells = $value; + return $this; } // -------------------------------------------------------------------- @@ -218,12 +220,13 @@ class CI_Table { * Can be passed as an array or discreet params * * @param mixed - * @return void + * @return CI_Table */ public function add_row($args = array()) { $args = func_get_args(); $this->rows[] = $this->_prep_args($args); + return $this; } // -------------------------------------------------------------------- @@ -271,8 +274,8 @@ class CI_Table { /** * Add a table caption * - * @param string - * @return void + * @param string $caption + * @return CI_Table */ public function set_caption($caption) { @@ -284,7 +287,7 @@ class CI_Table { /** * Generate the table * - * @param mixed + * @param mixed $table_data * @return string */ public function generate($table_data = NULL) @@ -417,13 +420,14 @@ class CI_Table { /** * Clears the table arrays. Useful if multiple tables are being generated * - * @return void + * @return CI_Table */ public function clear() { - $this->rows = array(); - $this->heading = array(); - $this->auto_heading = TRUE; + $this->rows = array(); + $this->heading = array(); + $this->auto_heading = TRUE; + return $this; } // -------------------------------------------------------------------- @@ -528,31 +532,31 @@ class CI_Table { protected function _default_template() { return array( - 'table_open' => '', + 'table_open' => '
', - 'thead_open' => '', - 'thead_close' => '', + 'thead_open' => '', + 'thead_close' => '', - 'heading_row_start' => '', - 'heading_row_end' => '', - 'heading_cell_start' => '', + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', - 'tbody_open' => '', - 'tbody_close' => '', + 'tbody_open' => '', + 'tbody_close' => '', - 'row_start' => '', - 'row_end' => '', - 'cell_start' => '', + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', - 'row_alt_start' => '', - 'row_alt_end' => '', - 'cell_alt_start' => '', + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', - 'table_close' => '
', - 'heading_cell_end' => '
', + 'heading_cell_end' => '
', - 'cell_end' => '
', + 'cell_end' => '
', - 'cell_alt_end' => '
', + 'cell_alt_end' => '
' - ); + 'table_close' => '' + ); } } -- cgit v1.2.3-24-g4f1b From d8a561a9cd12317342dd2f28aea8d76e93efce0d Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Sat, 8 Feb 2014 20:14:52 +0200 Subject: [ci skip] Deprecate the Javascript library --- system/libraries/Javascript.php | 1 + 1 file changed, 1 insertion(+) (limited to 'system/libraries') diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php index 26a16850c..34a216c22 100644 --- a/system/libraries/Javascript.php +++ b/system/libraries/Javascript.php @@ -34,6 +34,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @category Javascript * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/javascript.html + * @deprecated 3.0.0 This was never a good idea in the first place. */ class CI_Javascript { -- cgit v1.2.3-24-g4f1b From 4b450651ed3b9413be0245401da706c218850f53 Mon Sep 17 00:00:00 2001 From: Andrey Andreev Date: Mon, 10 Feb 2014 06:59:54 +0200 Subject: CI_Encryption: Rename 'base64' parameter to 'raw_data' and add docs --- system/libraries/Encryption.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'system/libraries') diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php index e03e278fa..3a5409839 100644 --- a/system/libraries/Encryption.php +++ b/system/libraries/Encryption.php @@ -698,7 +698,7 @@ class CI_Encryption { 'mode' => $params['mode'], 'key' => $params['key'], 'iv' => isset($params['iv']) ? $params['iv'] : NULL, - 'base64' => isset($params['base64']) ? $params['base64'] : TRUE, + 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE, 'hmac_digest' => $params['hmac_digest'], 'hmac_key' => $params['hmac_key'] ); @@ -825,8 +825,8 @@ class CI_Encryption { * @param $key Input key * @param $digest A SHA-2 hashing algorithm * @param $salt Optional salt - * @param $info Optional context/application-specific info * @param $length Output length (defaults to the selected digest size) + * @param $info Optional context/application-specific info * @return string A pseudo-random key */ public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '') -- cgit v1.2.3-24-g4f1b