1<?php
2
3if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) {
4 return;
5}
6
7/**
8 * @internal This should only be used by sodium_compat
9 */
10class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray
11{
12 /**
13 * @var array<int, int>
14 */
15 protected $values = array();
16
17 /**
18 * @var int
19 */
20 protected $size;
21
22 /**
23 * @param int $size
24 */
25 public function __construct($size = 8)
26 {
27 parent::__construct($size);
28 $this->size = $size;
29 $this->values = array_fill(0, $size, 0);
30 }
31
32 /**
33 * @return self
34 */
35 public static function init()
36 {
37 return new self(8);
38 }
39
40 /**
41 * @internal You should not use this directly from another application
42 *
43 * @param array<int, int> $array
44 * @param bool $save_indexes
45 * @return self
46 *
47 * @psalm-suppress MethodSignatureMismatch
48 */
49 #[ReturnTypeWillChange]
50 public static function fromArray($array, $save_indexes = null)
51 {
52 $count = count($array);
53 if ($save_indexes) {
54 $keys = array_keys($array);
55 } else {
56 $keys = range(0, $count - 1);
57 }
58 $array = array_values($array);
59 /** @var array<int, int> $keys */
60
61 $obj = new ParagonIE_Sodium_Core_AES_Block();
62 if ($save_indexes) {
63 for ($i = 0; $i < $count; ++$i) {
64 $obj->offsetSet($keys[$i], $array[$i]);
65 }
66 } else {
67 for ($i = 0; $i < $count; ++$i) {
68 $obj->offsetSet($i, $array[$i]);
69 }
70 }
71 return $obj;
72 }
73
74
75 /**
76 * @internal You should not use this directly from another application
77 *
78 * @param int|null $offset
79 * @param int $value
80 * @return void
81 *
82 * @psalm-suppress MethodSignatureMismatch
83 * @psalm-suppress MixedArrayOffset
84 */
85 #[ReturnTypeWillChange]
86 public function offsetSet($offset, $value)
87 {
88 if (!is_int($value)) {
89 throw new InvalidArgumentException('Expected an integer');
90 }
91 if (is_null($offset)) {
92 $this->values[] = $value;
93 } else {
94 $this->values[$offset] = $value;
95 }
96 }
97
98 /**
99 * @internal You should not use this directly from another application
100 *
101 * @param int $offset
102 * @return bool
103 *
104 * @psalm-suppress MethodSignatureMismatch
105 * @psalm-suppress MixedArrayOffset
106 */
107 #[ReturnTypeWillChange]
108 public function offsetExists($offset)
109 {
110 return isset($this->values[$offset]);
111 }
112
113 /**
114 * @internal You should not use this directly from another application
115 *
116 * @param int $offset
117 * @return void
118 *
119 * @psalm-suppress MethodSignatureMismatch
120 * @psalm-suppress MixedArrayOffset
121 */
122 #[ReturnTypeWillChange]
123 public function offsetUnset($offset)
124 {
125 unset($this->values[$offset]);
126 }
127
128 /**
129 * @internal You should not use this directly from another application
130 *
131 * @param int $offset
132 * @return int
133 *
134 * @psalm-suppress MethodSignatureMismatch
135 * @psalm-suppress MixedArrayOffset
136 */
137 #[ReturnTypeWillChange]
138 public function offsetGet($offset)
139 {
140 if (!isset($this->values[$offset])) {
141 $this->values[$offset] = 0;
142 }
143 return (int) ($this->values[$offset]);
144 }
145
146 /**
147 * @internal You should not use this directly from another application
148 *
149 * @return array
150 */
151 public function __debugInfo()
152 {
153 $out = array();
154 foreach ($this->values as $v) {
155 $out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT);
156 }
157 return array(implode(', ', $out));
158 /*
159 return array(implode(', ', $this->values));
160 */
161 }
162
163 /**
164 * @param int $cl low bit mask
165 * @param int $ch high bit mask
166 * @param int $s shift
167 * @param int $x index 1
168 * @param int $y index 2
169 * @return self
170 */
171 public function swapN($cl, $ch, $s, $x, $y)
172 {
173 static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX;
174 $a = $this->values[$x] & $u32mask;
175 $b = $this->values[$y] & $u32mask;
176 // (x) = (a & cl) | ((b & cl) << (s));
177 $this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask);
178 // (y) = ((a & ch) >> (s)) | (b & ch);
179 $this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch);
180 return $this;
181 }
182
183 /**
184 * @param int $x index 1
185 * @param int $y index 2
186 * @return self
187 */
188 public function swap2($x, $y)
189 {
190 return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y);
191 }
192
193 /**
194 * @param int $x index 1
195 * @param int $y index 2
196 * @return self
197 */
198 public function swap4($x, $y)
199 {
200 return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y);
201 }
202
203 /**
204 * @param int $x index 1
205 * @param int $y index 2
206 * @return self
207 */
208 public function swap8($x, $y)
209 {
210 return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y);
211 }
212
213 /**
214 * @return self
215 */
216 public function orthogonalize()
217 {
218 return $this
219 ->swap2(0, 1)
220 ->swap2(2, 3)
221 ->swap2(4, 5)
222 ->swap2(6, 7)
223
224 ->swap4(0, 2)
225 ->swap4(1, 3)
226 ->swap4(4, 6)
227 ->swap4(5, 7)
228
229 ->swap8(0, 4)
230 ->swap8(1, 5)
231 ->swap8(2, 6)
232 ->swap8(3, 7);
233 }
234
235 /**
236 * @return self
237 */
238 public function shiftRows()
239 {
240 for ($i = 0; $i < 8; ++$i) {
241 $x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX;
242 $this->values[$i] = (
243 ($x & 0x000000FF)
244 | (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6)
245 | (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4)
246 | (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2)
247 ) & ParagonIE_Sodium_Core_Util::U32_MAX;
248 }
249 return $this;
250 }
251
252 /**
253 * @param int $x
254 * @return int
255 */
256 public static function rotr16($x)
257 {
258 return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16);
259 }
260
261 /**
262 * @return self
263 */
264 public function mixColumns()
265 {
266 $q0 = $this->values[0];
267 $q1 = $this->values[1];
268 $q2 = $this->values[2];
269 $q3 = $this->values[3];
270 $q4 = $this->values[4];
271 $q5 = $this->values[5];
272 $q6 = $this->values[6];
273 $q7 = $this->values[7];
274 $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
275 $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
276 $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
277 $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
278 $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
279 $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
280 $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
281 $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
282
283 $this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
284 $this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
285 $this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
286 $this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
287 $this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
288 $this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
289 $this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
290 $this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
291 return $this;
292 }
293
294 /**
295 * @return self
296 */
297 public function inverseMixColumns()
298 {
299 $q0 = $this->values[0];
300 $q1 = $this->values[1];
301 $q2 = $this->values[2];
302 $q3 = $this->values[3];
303 $q4 = $this->values[4];
304 $q5 = $this->values[5];
305 $q6 = $this->values[6];
306 $q7 = $this->values[7];
307 $r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
308 $r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
309 $r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
310 $r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
311 $r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
312 $r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
313 $r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
314 $r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
315
316 $this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
317 $this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
318 $this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
319 $this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
320 $this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
321 $this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
322 $this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
323 $this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
324 return $this;
325 }
326
327 /**
328 * @return self
329 */
330 public function inverseShiftRows()
331 {
332 for ($i = 0; $i < 8; ++$i) {
333 $x = $this->values[$i];
334 $this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & (
335 ($x & 0x000000FF)
336 | (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6)
337 | (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4)
338 | (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2)
339 );
340 }
341 return $this;
342 }
343}
344