PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

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