PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Filter/Encrypt/Openssl.php

https://bitbucket.org/hjain/loudmusic
PHP | 492 lines | 269 code | 59 blank | 164 comment | 41 complexity | 60bd39db9b4a3668140ea7d179ea9593 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Filter
  17. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Openssl.php 24593 2012-01-05 20:35:02Z matthew $
  20. */
  21. /**
  22. * @see Zend_Filter_Encrypt_Interface
  23. */
  24. require_once 'Zend/Filter/Encrypt/Interface.php';
  25. /**
  26. * Encryption adapter for openssl
  27. *
  28. * @category Zend
  29. * @package Zend_Filter
  30. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  31. * @license http://framework.zend.com/license/new-bsd New BSD License
  32. */
  33. class Zend_Filter_Encrypt_Openssl implements Zend_Filter_Encrypt_Interface
  34. {
  35. /**
  36. * Definitions for encryption
  37. * array(
  38. * 'public' => public keys
  39. * 'private' => private keys
  40. * 'envelope' => resulting envelope keys
  41. * )
  42. */
  43. protected $_keys = array(
  44. 'public' => array(),
  45. 'private' => array(),
  46. 'envelope' => array()
  47. );
  48. /**
  49. * Internal passphrase
  50. *
  51. * @var string
  52. */
  53. protected $_passphrase;
  54. /**
  55. * Internal compression
  56. *
  57. * @var array
  58. */
  59. protected $_compression;
  60. /**
  61. * Internal create package
  62. *
  63. * @var boolean
  64. */
  65. protected $_package = false;
  66. /**
  67. * Class constructor
  68. * Available options
  69. * 'public' => public key
  70. * 'private' => private key
  71. * 'envelope' => envelope key
  72. * 'passphrase' => passphrase
  73. * 'compression' => compress value with this compression adapter
  74. * 'package' => pack envelope keys into encrypted string, simplifies decryption
  75. *
  76. * @param string|array $options Options for this adapter
  77. */
  78. public function __construct($options = array())
  79. {
  80. if (!extension_loaded('openssl')) {
  81. require_once 'Zend/Filter/Exception.php';
  82. throw new Zend_Filter_Exception('This filter needs the openssl extension');
  83. }
  84. if ($options instanceof Zend_Config) {
  85. $options = $options->toArray();
  86. }
  87. if (!is_array($options)) {
  88. $options = array('public' => $options);
  89. }
  90. if (array_key_exists('passphrase', $options)) {
  91. $this->setPassphrase($options['passphrase']);
  92. unset($options['passphrase']);
  93. }
  94. if (array_key_exists('compression', $options)) {
  95. $this->setCompression($options['compression']);
  96. unset($options['compress']);
  97. }
  98. if (array_key_exists('package', $options)) {
  99. $this->setPackage($options['package']);
  100. unset($options['package']);
  101. }
  102. $this->_setKeys($options);
  103. }
  104. /**
  105. * Sets the encryption keys
  106. *
  107. * @param string|array $keys Key with type association
  108. * @return Zend_Filter_Encrypt_Openssl
  109. */
  110. protected function _setKeys($keys)
  111. {
  112. if (!is_array($keys)) {
  113. require_once 'Zend/Filter/Exception.php';
  114. throw new Zend_Filter_Exception('Invalid options argument provided to filter');
  115. }
  116. foreach ($keys as $type => $key) {
  117. if (is_file($key) and is_readable($key)) {
  118. $file = fopen($key, 'r');
  119. $cert = fread($file, 8192);
  120. fclose($file);
  121. } else {
  122. $cert = $key;
  123. $key = count($this->_keys[$type]);
  124. }
  125. switch ($type) {
  126. case 'public':
  127. $test = openssl_pkey_get_public($cert);
  128. if ($test === false) {
  129. require_once 'Zend/Filter/Exception.php';
  130. throw new Zend_Filter_Exception("Public key '{$cert}' not valid");
  131. }
  132. openssl_free_key($test);
  133. $this->_keys['public'][$key] = $cert;
  134. break;
  135. case 'private':
  136. $test = openssl_pkey_get_private($cert, $this->_passphrase);
  137. if ($test === false) {
  138. require_once 'Zend/Filter/Exception.php';
  139. throw new Zend_Filter_Exception("Private key '{$cert}' not valid");
  140. }
  141. openssl_free_key($test);
  142. $this->_keys['private'][$key] = $cert;
  143. break;
  144. case 'envelope':
  145. $this->_keys['envelope'][$key] = $cert;
  146. break;
  147. default:
  148. break;
  149. }
  150. }
  151. return $this;
  152. }
  153. /**
  154. * Returns all public keys
  155. *
  156. * @return array
  157. */
  158. public function getPublicKey()
  159. {
  160. $key = $this->_keys['public'];
  161. return $key;
  162. }
  163. /**
  164. * Sets public keys
  165. *
  166. * @param string|array $key Public keys
  167. * @return Zend_Filter_Encrypt_Openssl
  168. */
  169. public function setPublicKey($key)
  170. {
  171. if (is_array($key)) {
  172. foreach($key as $type => $option) {
  173. if ($type !== 'public') {
  174. $key['public'] = $option;
  175. unset($key[$type]);
  176. }
  177. }
  178. } else {
  179. $key = array('public' => $key);
  180. }
  181. return $this->_setKeys($key);
  182. }
  183. /**
  184. * Returns all private keys
  185. *
  186. * @return array
  187. */
  188. public function getPrivateKey()
  189. {
  190. $key = $this->_keys['private'];
  191. return $key;
  192. }
  193. /**
  194. * Sets private keys
  195. *
  196. * @param string $key Private key
  197. * @param string $passphrase
  198. * @return Zend_Filter_Encrypt_Openssl
  199. */
  200. public function setPrivateKey($key, $passphrase = null)
  201. {
  202. if (is_array($key)) {
  203. foreach($key as $type => $option) {
  204. if ($type !== 'private') {
  205. $key['private'] = $option;
  206. unset($key[$type]);
  207. }
  208. }
  209. } else {
  210. $key = array('private' => $key);
  211. }
  212. if ($passphrase !== null) {
  213. $this->setPassphrase($passphrase);
  214. }
  215. return $this->_setKeys($key);
  216. }
  217. /**
  218. * Returns all envelope keys
  219. *
  220. * @return array
  221. */
  222. public function getEnvelopeKey()
  223. {
  224. $key = $this->_keys['envelope'];
  225. return $key;
  226. }
  227. /**
  228. * Sets envelope keys
  229. *
  230. * @param string|array $options Envelope keys
  231. * @return Zend_Filter_Encrypt_Openssl
  232. */
  233. public function setEnvelopeKey($key)
  234. {
  235. if (is_array($key)) {
  236. foreach($key as $type => $option) {
  237. if ($type !== 'envelope') {
  238. $key['envelope'] = $option;
  239. unset($key[$type]);
  240. }
  241. }
  242. } else {
  243. $key = array('envelope' => $key);
  244. }
  245. return $this->_setKeys($key);
  246. }
  247. /**
  248. * Returns the passphrase
  249. *
  250. * @return string
  251. */
  252. public function getPassphrase()
  253. {
  254. return $this->_passphrase;
  255. }
  256. /**
  257. * Sets a new passphrase
  258. *
  259. * @param string $passphrase
  260. * @return Zend_Filter_Encrypt_Openssl
  261. */
  262. public function setPassphrase($passphrase)
  263. {
  264. $this->_passphrase = $passphrase;
  265. return $this;
  266. }
  267. /**
  268. * Returns the compression
  269. *
  270. * @return array
  271. */
  272. public function getCompression()
  273. {
  274. return $this->_compression;
  275. }
  276. /**
  277. * Sets a internal compression for values to encrypt
  278. *
  279. * @param string|array $compression
  280. * @return Zend_Filter_Encrypt_Openssl
  281. */
  282. public function setCompression($compression)
  283. {
  284. if (is_string($this->_compression)) {
  285. $compression = array('adapter' => $compression);
  286. }
  287. $this->_compression = $compression;
  288. return $this;
  289. }
  290. /**
  291. * Returns if header should be packaged
  292. *
  293. * @return boolean
  294. */
  295. public function getPackage()
  296. {
  297. return $this->_package;
  298. }
  299. /**
  300. * Sets if the envelope keys should be included in the encrypted value
  301. *
  302. * @param boolean $package
  303. * @return Zend_Filter_Encrypt_Openssl
  304. */
  305. public function setPackage($package)
  306. {
  307. $this->_package = (boolean) $package;
  308. return $this;
  309. }
  310. /**
  311. * Encrypts $value with the defined settings
  312. * Note that you also need the "encrypted" keys to be able to decrypt
  313. *
  314. * @param string $value Content to encrypt
  315. * @return string The encrypted content
  316. * @throws Zend_Filter_Exception
  317. */
  318. public function encrypt($value)
  319. {
  320. $encrypted = array();
  321. $encryptedkeys = array();
  322. if (count($this->_keys['public']) == 0) {
  323. require_once 'Zend/Filter/Exception.php';
  324. throw new Zend_Filter_Exception('Openssl can not encrypt without public keys');
  325. }
  326. $keys = array();
  327. $fingerprints = array();
  328. $count = -1;
  329. foreach($this->_keys['public'] as $key => $cert) {
  330. $keys[$key] = openssl_pkey_get_public($cert);
  331. if ($this->_package) {
  332. $details = openssl_pkey_get_details($keys[$key]);
  333. if ($details === false) {
  334. $details = array('key' => 'ZendFramework');
  335. }
  336. ++$count;
  337. $fingerprints[$count] = md5($details['key']);
  338. }
  339. }
  340. // compress prior to encryption
  341. if (!empty($this->_compression)) {
  342. require_once 'Zend/Filter/Compress.php';
  343. $compress = new Zend_Filter_Compress($this->_compression);
  344. $value = $compress->filter($value);
  345. }
  346. $crypt = openssl_seal($value, $encrypted, $encryptedkeys, $keys);
  347. foreach ($keys as $key) {
  348. openssl_free_key($key);
  349. }
  350. if ($crypt === false) {
  351. require_once 'Zend/Filter/Exception.php';
  352. throw new Zend_Filter_Exception('Openssl was not able to encrypt your content with the given options');
  353. }
  354. $this->_keys['envelope'] = $encryptedkeys;
  355. // Pack data and envelope keys into single string
  356. if ($this->_package) {
  357. $header = pack('n', count($this->_keys['envelope']));
  358. foreach($this->_keys['envelope'] as $key => $envKey) {
  359. $header .= pack('H32n', $fingerprints[$key], strlen($envKey)) . $envKey;
  360. }
  361. $encrypted = $header . $encrypted;
  362. }
  363. return $encrypted;
  364. }
  365. /**
  366. * Defined by Zend_Filter_Interface
  367. *
  368. * Decrypts $value with the defined settings
  369. *
  370. * @param string $value Content to decrypt
  371. * @return string The decrypted content
  372. * @throws Zend_Filter_Exception
  373. */
  374. public function decrypt($value)
  375. {
  376. $decrypted = "";
  377. $envelope = current($this->getEnvelopeKey());
  378. if (count($this->_keys['private']) !== 1) {
  379. require_once 'Zend/Filter/Exception.php';
  380. throw new Zend_Filter_Exception('Please give a private key for decryption with Openssl');
  381. }
  382. if (!$this->_package && empty($envelope)) {
  383. require_once 'Zend/Filter/Exception.php';
  384. throw new Zend_Filter_Exception('Please give a envelope key for decryption with Openssl');
  385. }
  386. foreach($this->_keys['private'] as $key => $cert) {
  387. $keys = openssl_pkey_get_private($cert, $this->getPassphrase());
  388. }
  389. if ($this->_package) {
  390. $details = openssl_pkey_get_details($keys);
  391. if ($details !== false) {
  392. $fingerprint = md5($details['key']);
  393. } else {
  394. $fingerprint = md5("ZendFramework");
  395. }
  396. $count = unpack('ncount', $value);
  397. $count = $count['count'];
  398. $length = 2;
  399. for($i = $count; $i > 0; --$i) {
  400. $header = unpack('H32print/nsize', substr($value, $length, 18));
  401. $length += 18;
  402. if ($header['print'] == $fingerprint) {
  403. $envelope = substr($value, $length, $header['size']);
  404. }
  405. $length += $header['size'];
  406. }
  407. // remainder of string is the value to decrypt
  408. $value = substr($value, $length);
  409. }
  410. $crypt = openssl_open($value, $decrypted, $envelope, $keys);
  411. openssl_free_key($keys);
  412. if ($crypt === false) {
  413. require_once 'Zend/Filter/Exception.php';
  414. throw new Zend_Filter_Exception('Openssl was not able to decrypt you content with the given options');
  415. }
  416. // decompress after decryption
  417. if (!empty($this->_compression)) {
  418. require_once 'Zend/Filter/Decompress.php';
  419. $decompress = new Zend_Filter_Decompress($this->_compression);
  420. $decrypted = $decompress->filter($decrypted);
  421. }
  422. return $decrypted;
  423. }
  424. /**
  425. * Returns the adapter name
  426. *
  427. * @return string
  428. */
  429. public function toString()
  430. {
  431. return 'Openssl';
  432. }
  433. }