PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/www/libs/Zend/Filter/Encrypt/Openssl.php

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