encryption key string * 'algorithm' => algorithm to use * 'algorithm_directory' => directory where to find the algorithm * 'mode' => encryption mode to use * 'modedirectory' => directory where to find the mode * ) */ protected $_encryption = array( 'key' => 'ZendFramework', 'algorithm' => 'blowfish', 'algorithm_directory' => '', 'mode' => 'cbc', 'mode_directory' => '', 'vector' => null, 'salt' => false ); /** * Internal compression * * @var array */ protected $_compression; protected static $_srandCalled = false; /** * Class constructor * * @param string|array|Zend_Config $options Cryption Options */ public function __construct($options) { if (!extension_loaded('mcrypt')) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('This filter needs the mcrypt extension'); } if ($options instanceof Zend_Config) { $options = $options->toArray(); } elseif (is_string($options)) { $options = array('key' => $options); } elseif (!is_array($options)) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('Invalid options argument provided to filter'); } if (array_key_exists('compression', $options)) { $this->setCompression($options['compression']); unset($options['compress']); } $this->setEncryption($options); } /** * Returns the set encryption options * * @return array */ public function getEncryption() { return $this->_encryption; } /** * Sets new encryption options * * @param string|array $options Encryption options * @return Zend_Filter_File_Encryption */ public function setEncryption($options) { if (is_string($options)) { $options = array('key' => $options); } if (!is_array($options)) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('Invalid options argument provided to filter'); } $options = $options + $this->getEncryption(); $algorithms = mcrypt_list_algorithms($options['algorithm_directory']); if (!in_array($options['algorithm'], $algorithms)) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception("The algorithm '{$options['algorithm']}' is not supported"); } $modes = mcrypt_list_modes($options['mode_directory']); if (!in_array($options['mode'], $modes)) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception("The mode '{$options['mode']}' is not supported"); } if (!mcrypt_module_self_test($options['algorithm'], $options['algorithm_directory'])) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('The given algorithm can not be used due an internal mcrypt problem'); } if (!isset($options['vector'])) { $options['vector'] = null; } $this->_encryption = $options; $this->setVector($options['vector']); return $this; } /** * Returns the set vector * * @return string */ public function getVector() { return $this->_encryption['vector']; } /** * Sets the initialization vector * * @param string $vector (Optional) Vector to set * @return Zend_Filter_Encrypt_Mcrypt */ public function setVector($vector = null) { $cipher = $this->_openCipher(); $size = mcrypt_enc_get_iv_size($cipher); if (empty($vector)) { $this->_srand(); if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) { $method = MCRYPT_RAND; } else { if (file_exists('/dev/urandom') || (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) { $method = MCRYPT_DEV_URANDOM; } elseif (file_exists('/dev/random')) { $method = MCRYPT_DEV_RANDOM; } else { $method = MCRYPT_RAND; } } $vector = mcrypt_create_iv($size, $method); } else if (strlen($vector) != $size) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('The given vector has a wrong size for the set algorithm'); } $this->_encryption['vector'] = $vector; $this->_closeCipher($cipher); return $this; } /** * Returns the compression * * @return array */ public function getCompression() { return $this->_compression; } /** * Sets a internal compression for values to encrypt * * @param string|array $compression * @return Zend_Filter_Encrypt_Mcrypt */ public function setCompression($compression) { if (is_string($this->_compression)) { $compression = array('adapter' => $compression); } $this->_compression = $compression; return $this; } /** * Defined by Zend_Filter_Interface * * Encrypts $value with the defined settings * * @param string $value The content to encrypt * @return string The encrypted content */ public function encrypt($value) { // compress prior to encryption if (!empty($this->_compression)) { require_once 'Zend/Filter/Compress.php'; $compress = new Zend_Filter_Compress($this->_compression); $value = $compress->filter($value); } $cipher = $this->_openCipher(); $this->_initCipher($cipher); $encrypted = mcrypt_generic($cipher, $value); mcrypt_generic_deinit($cipher); $this->_closeCipher($cipher); return $encrypted; } /** * Defined by Zend_Filter_Interface * * Decrypts $value with the defined settings * * @param string $value Content to decrypt * @return string The decrypted content */ public function decrypt($value) { $cipher = $this->_openCipher(); $this->_initCipher($cipher); $decrypted = mdecrypt_generic($cipher, $value); mcrypt_generic_deinit($cipher); $this->_closeCipher($cipher); // decompress after decryption if (!empty($this->_compression)) { require_once 'Zend/Filter/Decompress.php'; $decompress = new Zend_Filter_Decompress($this->_compression); $decrypted = $decompress->filter($decrypted); } return $decrypted; } /** * Returns the adapter name * * @return string */ public function toString() { return 'Mcrypt'; } /** * Open a cipher * * @throws Zend_Filter_Exception When the cipher can not be opened * @return resource Returns the opened cipher */ protected function _openCipher() { $cipher = mcrypt_module_open( $this->_encryption['algorithm'], $this->_encryption['algorithm_directory'], $this->_encryption['mode'], $this->_encryption['mode_directory']); if ($cipher === false) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('Mcrypt can not be opened with your settings'); } return $cipher; } /** * Close a cipher * * @param resource $cipher Cipher to close * @return Zend_Filter_Encrypt_Mcrypt */ protected function _closeCipher($cipher) { mcrypt_module_close($cipher); return $this; } /** * Initialises the cipher with the set key * * @param resource $cipher * @throws * @return resource */ protected function _initCipher($cipher) { $key = $this->_encryption['key']; $keysizes = mcrypt_enc_get_supported_key_sizes($cipher); if (empty($keysizes) || ($this->_encryption['salt'] == true)) { $this->_srand(); $keysize = mcrypt_enc_get_key_size($cipher); $key = substr(md5($key), 0, $keysize); } else if (!in_array(strlen($key), $keysizes)) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('The given key has a wrong size for the set algorithm'); } $result = mcrypt_generic_init($cipher, $key, $this->_encryption['vector']); if ($result < 0) { require_once 'Zend/Filter/Exception.php'; throw new Zend_Filter_Exception('Mcrypt could not be initialize with the given setting'); } return $this; } /** * _srand() interception * * @see ZF-8742 */ protected function _srand() { if (version_compare(PHP_VERSION, '5.3.0', '>=')) { return; } if (!self::$_srandCalled) { srand((double) microtime() * 1000000); self::$_srandCalled = true; } } }