CookieCryptTrait.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.1.6
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Utility;
  16. use RuntimeException;
  17. /**
  18. * Cookie Crypt Trait.
  19. *
  20. * Provides the encrypt/decrypt logic for the CookieComponent.
  21. *
  22. * @link https://book.cakephp.org/3.0/en/controllers/components/cookie.html
  23. */
  24. trait CookieCryptTrait
  25. {
  26. /**
  27. * Valid cipher names for encrypted cookies.
  28. *
  29. * @var array
  30. */
  31. protected $_validCiphers = ['aes', 'rijndael'];
  32. /**
  33. * Returns the encryption key to be used.
  34. *
  35. * @return string
  36. */
  37. abstract protected function _getCookieEncryptionKey();
  38. /**
  39. * Encrypts $value using public $type method in Security class
  40. *
  41. * @param string $value Value to encrypt
  42. * @param string|bool $encrypt Encryption mode to use. False
  43. * disabled encryption.
  44. * @param string|null $key Used as the security salt if specified.
  45. * @return string Encoded values
  46. */
  47. protected function _encrypt($value, $encrypt, $key = null)
  48. {
  49. if (is_array($value)) {
  50. $value = $this->_implode($value);
  51. }
  52. if ($encrypt === false) {
  53. return $value;
  54. }
  55. $this->_checkCipher($encrypt);
  56. $prefix = 'Q2FrZQ==.';
  57. $cipher = null;
  58. if ($key === null) {
  59. $key = $this->_getCookieEncryptionKey();
  60. }
  61. if ($encrypt === 'rijndael') {
  62. $cipher = Security::rijndael($value, $key, 'encrypt');
  63. }
  64. if ($encrypt === 'aes') {
  65. $cipher = Security::encrypt($value, $key);
  66. }
  67. return $prefix . base64_encode($cipher);
  68. }
  69. /**
  70. * Helper method for validating encryption cipher names.
  71. *
  72. * @param string $encrypt The cipher name.
  73. * @return void
  74. * @throws \RuntimeException When an invalid cipher is provided.
  75. */
  76. protected function _checkCipher($encrypt)
  77. {
  78. if (!in_array($encrypt, $this->_validCiphers)) {
  79. $msg = sprintf(
  80. 'Invalid encryption cipher. Must be one of %s or false.',
  81. implode(', ', $this->_validCiphers)
  82. );
  83. throw new RuntimeException($msg);
  84. }
  85. }
  86. /**
  87. * Decrypts $value using public $type method in Security class
  88. *
  89. * @param array $values Values to decrypt
  90. * @param string|bool $mode Encryption mode
  91. * @param string|null $key Used as the security salt if specified.
  92. * @return string|array Decrypted values
  93. */
  94. protected function _decrypt($values, $mode, $key = null)
  95. {
  96. if (is_string($values)) {
  97. return $this->_decode($values, $mode, $key);
  98. }
  99. $decrypted = [];
  100. foreach ($values as $name => $value) {
  101. $decrypted[$name] = $this->_decode($value, $mode, $key);
  102. }
  103. return $decrypted;
  104. }
  105. /**
  106. * Decodes and decrypts a single value.
  107. *
  108. * @param string $value The value to decode & decrypt.
  109. * @param string|false $encrypt The encryption cipher to use.
  110. * @param string|null $key Used as the security salt if specified.
  111. * @return string|array Decoded values.
  112. */
  113. protected function _decode($value, $encrypt, $key)
  114. {
  115. if (!$encrypt) {
  116. return $this->_explode($value);
  117. }
  118. $this->_checkCipher($encrypt);
  119. $prefix = 'Q2FrZQ==.';
  120. $prefixLength = strlen($prefix);
  121. if (strncmp($value, $prefix, $prefixLength) !== 0) {
  122. return '';
  123. }
  124. $value = base64_decode(substr($value, $prefixLength), true);
  125. if ($value === false || $value === '') {
  126. return '';
  127. }
  128. if ($key === null) {
  129. $key = $this->_getCookieEncryptionKey();
  130. }
  131. if ($encrypt === 'rijndael') {
  132. $value = Security::rijndael($value, $key, 'decrypt');
  133. }
  134. if ($encrypt === 'aes') {
  135. $value = Security::decrypt($value, $key);
  136. }
  137. if ($value === false) {
  138. return '';
  139. }
  140. return $this->_explode($value);
  141. }
  142. /**
  143. * Implode method to keep keys are multidimensional arrays
  144. *
  145. * @param array $array Map of key and values
  146. * @return string A json encoded string.
  147. */
  148. protected function _implode(array $array)
  149. {
  150. return json_encode($array);
  151. }
  152. /**
  153. * Explode method to return array from string set in CookieComponent::_implode()
  154. * Maintains reading backwards compatibility with 1.x CookieComponent::_implode().
  155. *
  156. * @param string $string A string containing JSON encoded data, or a bare string.
  157. * @return string|array Map of key and values
  158. */
  159. protected function _explode($string)
  160. {
  161. $first = substr($string, 0, 1);
  162. if ($first === '{' || $first === '[') {
  163. $ret = json_decode($string, true);
  164. return ($ret !== null) ? $ret : $string;
  165. }
  166. $array = [];
  167. foreach (explode(',', $string) as $pair) {
  168. $key = explode('|', $pair);
  169. if (!isset($key[1])) {
  170. return $key[0];
  171. }
  172. $array[$key[0]] = $key[1];
  173. }
  174. return $array;
  175. }
  176. }