PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/Filter/Encrypt/Openssl.php

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