File indexing completed on 2024-12-22 05:36:41

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Filter
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 /**
0023  * @see Zend_Filter_Encrypt_Interface
0024  */
0025 // require_once 'Zend/Filter/Encrypt/Interface.php';
0026 
0027 /** @see Zend_Crypt_Math */
0028 // require_once 'Zend/Crypt/Math.php';
0029 
0030 /**
0031  * Encryption adapter for mcrypt
0032  *
0033  * @category   Zend
0034  * @package    Zend_Filter
0035  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0036  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0037  */
0038 class Zend_Filter_Encrypt_Mcrypt implements Zend_Filter_Encrypt_Interface
0039 {
0040     /**
0041      * Definitions for encryption
0042      * array(
0043      *     'key' => encryption key string
0044      *     'algorithm' => algorithm to use
0045      *     'algorithm_directory' => directory where to find the algorithm
0046      *     'mode' => encryption mode to use
0047      *     'modedirectory' => directory where to find the mode
0048      * )
0049      */
0050     protected $_encryption = array(
0051         'key'                 => 'ZendFramework',
0052         'algorithm'           => 'blowfish',
0053         'algorithm_directory' => '',
0054         'mode'                => 'cbc',
0055         'mode_directory'      => '',
0056         'vector'              => null,
0057         'salt'                => false
0058     );
0059 
0060     /**
0061      * Internal compression
0062      *
0063      * @var array
0064      */
0065     protected $_compression;
0066 
0067     protected static $_srandCalled = false;
0068 
0069     /**
0070      * Class constructor
0071      *
0072      * @param string|array|Zend_Config $options Cryption Options
0073      */
0074     public function __construct($options)
0075     {
0076         if (!extension_loaded('mcrypt')) {
0077             // require_once 'Zend/Filter/Exception.php';
0078             throw new Zend_Filter_Exception('This filter needs the mcrypt extension');
0079         }
0080 
0081         if ($options instanceof Zend_Config) {
0082             $options = $options->toArray();
0083         } elseif (is_string($options)) {
0084             $options = array('key' => $options);
0085         } elseif (!is_array($options)) {
0086             // require_once 'Zend/Filter/Exception.php';
0087             throw new Zend_Filter_Exception('Invalid options argument provided to filter');
0088         }
0089 
0090         if (array_key_exists('compression', $options)) {
0091             $this->setCompression($options['compression']);
0092             unset($options['compress']);
0093         }
0094 
0095         $this->setEncryption($options);
0096     }
0097 
0098     /**
0099      * Returns the set encryption options
0100      *
0101      * @return array
0102      */
0103     public function getEncryption()
0104     {
0105         return $this->_encryption;
0106     }
0107 
0108     /**
0109      * Sets new encryption options
0110      *
0111      * @param  string|array $options Encryption options
0112      * @return Zend_Filter_File_Encryption
0113      */
0114     public function setEncryption($options)
0115     {
0116         if (is_string($options)) {
0117             $options = array('key' => $options);
0118         }
0119 
0120         if (!is_array($options)) {
0121             // require_once 'Zend/Filter/Exception.php';
0122             throw new Zend_Filter_Exception('Invalid options argument provided to filter');
0123         }
0124 
0125         $options = $options + $this->getEncryption();
0126         $algorithms = mcrypt_list_algorithms($options['algorithm_directory']);
0127         if (!in_array($options['algorithm'], $algorithms)) {
0128             // require_once 'Zend/Filter/Exception.php';
0129             throw new Zend_Filter_Exception("The algorithm '{$options['algorithm']}' is not supported");
0130         }
0131 
0132         $modes = mcrypt_list_modes($options['mode_directory']);
0133         if (!in_array($options['mode'], $modes)) {
0134             // require_once 'Zend/Filter/Exception.php';
0135             throw new Zend_Filter_Exception("The mode '{$options['mode']}' is not supported");
0136         }
0137 
0138         if (!mcrypt_module_self_test($options['algorithm'], $options['algorithm_directory'])) {
0139             // require_once 'Zend/Filter/Exception.php';
0140             throw new Zend_Filter_Exception('The given algorithm can not be used due an internal mcrypt problem');
0141         }
0142 
0143         if (!isset($options['vector'])) {
0144             $options['vector'] = null;
0145         }
0146 
0147         $this->_encryption = $options;
0148         $this->setVector($options['vector']);
0149 
0150         return $this;
0151     }
0152 
0153     /**
0154      * Returns the set vector
0155      *
0156      * @return string
0157      */
0158     public function getVector()
0159     {
0160         return $this->_encryption['vector'];
0161     }
0162 
0163     /**
0164      * Sets the initialization vector
0165      *
0166      * @param string $vector (Optional) Vector to set
0167      * @return Zend_Filter_Encrypt_Mcrypt
0168      */
0169     public function setVector($vector = null)
0170     {
0171         $cipher = $this->_openCipher();
0172         $size   = mcrypt_enc_get_iv_size($cipher);
0173         if (empty($vector)) {
0174             $this->_srand();
0175             if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) {
0176                 $method = MCRYPT_RAND;
0177             } else {
0178                 if (file_exists('/dev/urandom') || (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')) {
0179                     $method = MCRYPT_DEV_URANDOM;
0180                 } elseif (file_exists('/dev/random')) {
0181                     $method = MCRYPT_DEV_RANDOM;
0182                 } else {
0183                     $method = MCRYPT_RAND;
0184                 }
0185             }
0186             $vector = mcrypt_create_iv($size, $method);
0187         } else if (strlen($vector) != $size) {
0188             // require_once 'Zend/Filter/Exception.php';
0189             throw new Zend_Filter_Exception('The given vector has a wrong size for the set algorithm');
0190         }
0191 
0192         $this->_encryption['vector'] = $vector;
0193         $this->_closeCipher($cipher);
0194 
0195         return $this;
0196     }
0197 
0198     /**
0199      * Returns the compression
0200      *
0201      * @return array
0202      */
0203     public function getCompression()
0204     {
0205         return $this->_compression;
0206     }
0207 
0208     /**
0209      * Sets a internal compression for values to encrypt
0210      *
0211      * @param string|array $compression
0212      * @return Zend_Filter_Encrypt_Mcrypt
0213      */
0214     public function setCompression($compression)
0215     {
0216         if (is_string($this->_compression)) {
0217             $compression = array('adapter' => $compression);
0218         }
0219 
0220         $this->_compression = $compression;
0221         return $this;
0222     }
0223 
0224     /**
0225      * Defined by Zend_Filter_Interface
0226      *
0227      * Encrypts $value with the defined settings
0228      *
0229      * @param  string $value The content to encrypt
0230      * @return string The encrypted content
0231      */
0232     public function encrypt($value)
0233     {
0234         // compress prior to encryption
0235         if (!empty($this->_compression)) {
0236             // require_once 'Zend/Filter/Compress.php';
0237             $compress = new Zend_Filter_Compress($this->_compression);
0238             $value    = $compress->filter($value);
0239         }
0240 
0241         $cipher  = $this->_openCipher();
0242         $this->_initCipher($cipher);
0243         $encrypted = mcrypt_generic($cipher, $value);
0244         mcrypt_generic_deinit($cipher);
0245         $this->_closeCipher($cipher);
0246 
0247         return $encrypted;
0248     }
0249 
0250     /**
0251      * Defined by Zend_Filter_Interface
0252      *
0253      * Decrypts $value with the defined settings
0254      *
0255      * @param  string $value Content to decrypt
0256      * @return string The decrypted content
0257      */
0258     public function decrypt($value)
0259     {
0260         $cipher = $this->_openCipher();
0261         $this->_initCipher($cipher);
0262         $decrypted = mdecrypt_generic($cipher, $value);
0263         mcrypt_generic_deinit($cipher);
0264         $this->_closeCipher($cipher);
0265 
0266         // decompress after decryption
0267         if (!empty($this->_compression)) {
0268             // require_once 'Zend/Filter/Decompress.php';
0269             $decompress = new Zend_Filter_Decompress($this->_compression);
0270             $decrypted  = $decompress->filter($decrypted);
0271         }
0272 
0273         return $decrypted;
0274     }
0275 
0276     /**
0277      * Returns the adapter name
0278      *
0279      * @return string
0280      */
0281     public function toString()
0282     {
0283         return 'Mcrypt';
0284     }
0285 
0286     /**
0287      * Open a cipher
0288      *
0289      * @throws Zend_Filter_Exception When the cipher can not be opened
0290      * @return resource Returns the opened cipher
0291      */
0292     protected function _openCipher()
0293     {
0294         $cipher = mcrypt_module_open(
0295             $this->_encryption['algorithm'],
0296             $this->_encryption['algorithm_directory'],
0297             $this->_encryption['mode'],
0298             $this->_encryption['mode_directory']);
0299 
0300         if ($cipher === false) {
0301             // require_once 'Zend/Filter/Exception.php';
0302             throw new Zend_Filter_Exception('Mcrypt can not be opened with your settings');
0303         }
0304 
0305         return $cipher;
0306     }
0307 
0308     /**
0309      * Close a cipher
0310      *
0311      * @param  resource $cipher Cipher to close
0312      * @return Zend_Filter_Encrypt_Mcrypt
0313      */
0314     protected function _closeCipher($cipher)
0315     {
0316         mcrypt_module_close($cipher);
0317 
0318         return $this;
0319     }
0320 
0321     /**
0322      * Initialises the cipher with the set key
0323      *
0324      * @param  resource $cipher
0325      * @throws
0326      * @return resource
0327      */
0328     protected function _initCipher($cipher)
0329     {
0330         $key = $this->_encryption['key'];
0331 
0332         $keysizes = mcrypt_enc_get_supported_key_sizes($cipher);
0333         if (empty($keysizes) || ($this->_encryption['salt'] == true)) {
0334             $this->_srand();
0335             $keysize = mcrypt_enc_get_key_size($cipher);
0336             $key     = substr(md5($key), 0, $keysize);
0337         } else if (!in_array(strlen($key), $keysizes)) {
0338             // require_once 'Zend/Filter/Exception.php';
0339             throw new Zend_Filter_Exception('The given key has a wrong size for the set algorithm');
0340         }
0341 
0342         $result = mcrypt_generic_init($cipher, $key, $this->_encryption['vector']);
0343         if ($result < 0) {
0344             // require_once 'Zend/Filter/Exception.php';
0345             throw new Zend_Filter_Exception('Mcrypt could not be initialize with the given setting');
0346         }
0347 
0348         return $this;
0349     }
0350 
0351     /**
0352      * _srand() interception
0353      *
0354      * @see ZF-8742
0355      */
0356     protected function _srand()
0357     {
0358         if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
0359             return;
0360         }
0361         if (!self::$_srandCalled) {
0362             srand(Zend_Crypt_Math::randInteger(0, PHP_INT_MAX));
0363             self::$_srandCalled = true;
0364         }
0365     }
0366 }