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