PageRenderTime 37ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php

https://gitlab.com/techniconline/kmc
PHP | 302 lines | 113 code | 45 blank | 144 comment | 9 complexity | 5ecfc66e696abc63a606ebc88a9f0e06 MD5 | raw file
  1. <?php namespace Illuminate\Encryption;
  2. use Exception;
  3. use Illuminate\Contracts\Encryption\DecryptException;
  4. use Symfony\Component\Security\Core\Util\StringUtils;
  5. use Symfony\Component\Security\Core\Util\SecureRandom;
  6. use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;
  7. class Encrypter implements EncrypterContract
  8. {
  9. /**
  10. * The encryption key.
  11. *
  12. * @var string
  13. */
  14. protected $key;
  15. /**
  16. * The algorithm used for encryption.
  17. *
  18. * @var string
  19. */
  20. protected $cipher = MCRYPT_RIJNDAEL_128;
  21. /**
  22. * The mode used for encryption.
  23. *
  24. * @var string
  25. */
  26. protected $mode = MCRYPT_MODE_CBC;
  27. /**
  28. * The block size of the cipher.
  29. *
  30. * @var int
  31. */
  32. protected $block = 16;
  33. /**
  34. * Create a new encrypter instance.
  35. *
  36. * @param string $key
  37. * @return void
  38. */
  39. public function __construct($key)
  40. {
  41. $this->key = (string)$key;
  42. }
  43. /**
  44. * Encrypt the given value.
  45. *
  46. * @param string $value
  47. * @return string
  48. */
  49. public function encrypt($value)
  50. {
  51. $iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
  52. $value = base64_encode($this->padAndMcrypt($value, $iv));
  53. // Once we have the encrypted value we will go ahead base64_encode the input
  54. // vector and create the MAC for the encrypted value so we can verify its
  55. // authenticity. Then, we'll JSON encode the data in a "payload" array.
  56. $mac = $this->hash($iv = base64_encode($iv), $value);
  57. return base64_encode(json_encode(compact('iv', 'value', 'mac')));
  58. }
  59. /**
  60. * Pad and use mcrypt on the given value and input vector.
  61. *
  62. * @param string $value
  63. * @param string $iv
  64. * @return string
  65. */
  66. protected function padAndMcrypt($value, $iv)
  67. {
  68. $value = $this->addPadding(serialize($value));
  69. return mcrypt_encrypt($this->cipher, $this->key, $value, $this->mode, $iv);
  70. }
  71. /**
  72. * Decrypt the given value.
  73. *
  74. * @param string $payload
  75. * @return string
  76. */
  77. public function decrypt($payload)
  78. {
  79. $payload = $this->getJsonPayload($payload);
  80. // We'll go ahead and remove the PKCS7 padding from the encrypted value before
  81. // we decrypt it. Once we have the de-padded value, we will grab the vector
  82. // and decrypt the data, passing back the unserialized from of the value.
  83. $value = base64_decode($payload['value']);
  84. $iv = base64_decode($payload['iv']);
  85. return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
  86. }
  87. /**
  88. * Run the mcrypt decryption routine for the value.
  89. *
  90. * @param string $value
  91. * @param string $iv
  92. * @return string
  93. *
  94. * @throws \Exception
  95. */
  96. protected function mcryptDecrypt($value, $iv)
  97. {
  98. try {
  99. return mcrypt_decrypt($this->cipher, $this->key, $value, $this->mode, $iv);
  100. } catch (Exception $e) {
  101. throw new DecryptException($e->getMessage());
  102. }
  103. }
  104. /**
  105. * Get the JSON array from the given payload.
  106. *
  107. * @param string $payload
  108. * @return array
  109. *
  110. * @throws \Illuminate\Contracts\Encryption\DecryptException
  111. */
  112. protected function getJsonPayload($payload)
  113. {
  114. $payload = json_decode(base64_decode($payload), true);
  115. // If the payload is not valid JSON or does not have the proper keys set we will
  116. // assume it is invalid and bail out of the routine since we will not be able
  117. // to decrypt the given value. We'll also check the MAC for this encryption.
  118. if (!$payload || $this->invalidPayload($payload)) {
  119. throw new DecryptException('Invalid data.');
  120. }
  121. if (!$this->validMac($payload)) {
  122. throw new DecryptException('MAC is invalid.');
  123. }
  124. return $payload;
  125. }
  126. /**
  127. * Determine if the MAC for the given payload is valid.
  128. *
  129. * @param array $payload
  130. * @return bool
  131. *
  132. * @throws \RuntimeException
  133. */
  134. protected function validMac(array $payload)
  135. {
  136. $bytes = (new SecureRandom)->nextBytes(16);
  137. $calcMac = hash_hmac('sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true);
  138. return StringUtils::equals(hash_hmac('sha256', $payload['mac'], $bytes, true), $calcMac);
  139. }
  140. /**
  141. * Create a MAC for the given value.
  142. *
  143. * @param string $iv
  144. * @param string $value
  145. * @return string
  146. */
  147. protected function hash($iv, $value)
  148. {
  149. return hash_hmac('sha256', $iv . $value, $this->key);
  150. }
  151. /**
  152. * Add PKCS7 padding to a given value.
  153. *
  154. * @param string $value
  155. * @return string
  156. */
  157. protected function addPadding($value)
  158. {
  159. $pad = $this->block - (strlen($value) % $this->block);
  160. return $value . str_repeat(chr($pad), $pad);
  161. }
  162. /**
  163. * Remove the padding from the given value.
  164. *
  165. * @param string $value
  166. * @return string
  167. */
  168. protected function stripPadding($value)
  169. {
  170. $pad = ord($value[($len = strlen($value)) - 1]);
  171. return $this->paddingIsValid($pad, $value) ? substr($value, 0, $len - $pad) : $value;
  172. }
  173. /**
  174. * Determine if the given padding for a value is valid.
  175. *
  176. * @param string $pad
  177. * @param string $value
  178. * @return bool
  179. */
  180. protected function paddingIsValid($pad, $value)
  181. {
  182. $beforePad = strlen($value) - $pad;
  183. return substr($value, $beforePad) == str_repeat(substr($value, -1), $pad);
  184. }
  185. /**
  186. * Verify that the encryption payload is valid.
  187. *
  188. * @param array|mixed $data
  189. * @return bool
  190. */
  191. protected function invalidPayload($data)
  192. {
  193. return !is_array($data) || !isset($data['iv']) || !isset($data['value']) || !isset($data['mac']);
  194. }
  195. /**
  196. * Get the IV size for the cipher.
  197. *
  198. * @return int
  199. */
  200. protected function getIvSize()
  201. {
  202. return mcrypt_get_iv_size($this->cipher, $this->mode);
  203. }
  204. /**
  205. * Get the random data source available for the OS.
  206. *
  207. * @return int
  208. */
  209. protected function getRandomizer()
  210. {
  211. if (defined('MCRYPT_DEV_URANDOM')) return MCRYPT_DEV_URANDOM;
  212. if (defined('MCRYPT_DEV_RANDOM')) return MCRYPT_DEV_RANDOM;
  213. mt_srand();
  214. return MCRYPT_RAND;
  215. }
  216. /**
  217. * Set the encryption key.
  218. *
  219. * @param string $key
  220. * @return void
  221. */
  222. public function setKey($key)
  223. {
  224. $this->key = (string)$key;
  225. }
  226. /**
  227. * Set the encryption cipher.
  228. *
  229. * @param string $cipher
  230. * @return void
  231. */
  232. public function setCipher($cipher)
  233. {
  234. $this->cipher = $cipher;
  235. $this->updateBlockSize();
  236. }
  237. /**
  238. * Set the encryption mode.
  239. *
  240. * @param string $mode
  241. * @return void
  242. */
  243. public function setMode($mode)
  244. {
  245. $this->mode = $mode;
  246. $this->updateBlockSize();
  247. }
  248. /**
  249. * Update the block size for the current cipher and mode.
  250. *
  251. * @return void
  252. */
  253. protected function updateBlockSize()
  254. {
  255. $this->block = mcrypt_get_iv_size($this->cipher, $this->mode);
  256. }
  257. }