diff options
-rw-r--r-- | system/libraries/Encryption.php | 86 | ||||
-rw-r--r-- | tests/codeigniter/libraries/Encryption_test.php | 59 |
2 files changed, 115 insertions, 30 deletions
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 @@ -82,6 +82,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 * * name => digest size pairs @@ -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, diff --git a/tests/codeigniter/libraries/Encryption_test.php b/tests/codeigniter/libraries/Encryption_test.php index b13cb3140..ca1a4cd60 100644 --- a/tests/codeigniter/libraries/Encryption_test.php +++ b/tests/codeigniter/libraries/Encryption_test.php @@ -21,17 +21,51 @@ class Encryption_test extends CI_TestCase { $message = 'This is a message encrypted via MCrypt and decrypted via OpenSSL, or vice-versa.'; - // Format is: <MCrypt cipher name>, <OpenSSL cipher name>, <key size> + // Format is: <Cipher name>, <Cipher mode>, <Key size> $portable = array( - array('rijndael-128', 'aes-128', 16), - array('rijndael-128', 'aes-192', 24), - array('rijndael-128', 'aes-256', 32), - array('des', 'des', 7), - array('tripledes', 'des-ede3', 7), - array('tripledes', 'des-ede3', 14), - array('tripledes', 'des-ede3', 21), - array('blowfish', 'bf', 16), - array('blowfish', 'bf', 56) + array('aes-128', 'cbc', 16), + array('aes-128', 'cfb', 16), + array('aes-128', 'cfb8', 16), + array('aes-128', 'ofb', 16), + array('aes-128', 'ecb', 16), + array('aes-128', 'ctr', 16), + array('aes-192', 'cbc', 24), + array('aes-192', 'cfb', 24), + array('aes-192', 'cfb8', 24), + array('aes-192', 'ofb', 24), + array('aes-192', 'ecb', 24), + array('aes-192', 'ctr', 24), + array('aes-256', 'cbc', 32), + array('aes-256', 'cfb', 32), + array('aes-256', 'cfb8', 32), + array('aes-256', 'ofb', 32), + array('aes-256', 'ecb', 32), + array('aes-256', 'ctr', 32), + array('des', 'cbc', 7), + array('des', 'cfb', 7), + array('des', 'cfb8', 7), + array('des', 'ofb', 7), + array('des', 'ecb', 7), + array('tripledes', 'cbc', 7), + array('tripledes', 'cfb', 7), + array('tripledes', 'cfb8', 7), + array('tripledes', 'ofb', 7), + array('tripledes', 'cbc', 14), + array('tripledes', 'cfb', 14), + array('tripledes', 'cfb8', 14), + array('tripledes', 'ofb', 14), + array('tripledes', 'cbc', 21), + array('tripledes', 'cfb', 21), + array('tripledes', 'cfb8', 21), + array('tripledes', 'ofb', 21), + array('blowfish', 'cbc', 16), + array('blowfish', 'cfb', 16), + array('blowfish', 'ofb', 16), + array('blowfish', 'ecb', 16), + array('blowfish', 'cbc', 56), + array('blowfish', 'cfb', 56), + array('blowfish', 'ofb', 56), + array('blowfish', 'ecb', 56), ); $driver_index = array('mcrypt', 'openssl'); @@ -40,8 +74,8 @@ class Encryption_test extends CI_TestCase { // Add some randomness to the selected driver $driver = mt_rand(0,1); $params = array( - 'cipher' => $test[$driver], - 'mode' => 'cbc', + 'cipher' => $test[0], + 'mode' => $test[1], 'key' => openssl_random_pseudo_bytes($test[2]) ); @@ -49,7 +83,6 @@ class Encryption_test extends CI_TestCase { $ciphertext = $this->encryption->encrypt($message, $params); $driver = (int) ! $driver; - $params['cipher'] = $test[$driver]; $this->encryption->initialize(array('driver' => $driver_index[$driver])); $this->assertEquals($message, $this->encryption->decrypt($ciphertext, $params)); |