1<?php
2
3if (class_exists('ParagonIE_Sodium_Core32_ChaCha20', false)) {
4 return;
5}
6
7/**
8 * Class ParagonIE_Sodium_Core32_ChaCha20
9 */
10class ParagonIE_Sodium_Core32_ChaCha20 extends ParagonIE_Sodium_Core32_Util
11{
12 /**
13 * The ChaCha20 quarter round function. Works on four 32-bit integers.
14 *
15 * @internal You should not use this directly from another application
16 *
17 * @param ParagonIE_Sodium_Core32_Int32 $a
18 * @param ParagonIE_Sodium_Core32_Int32 $b
19 * @param ParagonIE_Sodium_Core32_Int32 $c
20 * @param ParagonIE_Sodium_Core32_Int32 $d
21 * @return array<int, ParagonIE_Sodium_Core32_Int32>
22 * @throws SodiumException
23 * @throws TypeError
24 */
25 protected static function quarterRound(
26 ParagonIE_Sodium_Core32_Int32 $a,
27 ParagonIE_Sodium_Core32_Int32 $b,
28 ParagonIE_Sodium_Core32_Int32 $c,
29 ParagonIE_Sodium_Core32_Int32 $d
30 ) {
31 /** @var ParagonIE_Sodium_Core32_Int32 $a */
32 /** @var ParagonIE_Sodium_Core32_Int32 $b */
33 /** @var ParagonIE_Sodium_Core32_Int32 $c */
34 /** @var ParagonIE_Sodium_Core32_Int32 $d */
35
36 # a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
37 $a = $a->addInt32($b);
38 $d = $d->xorInt32($a)->rotateLeft(16);
39
40 # c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
41 $c = $c->addInt32($d);
42 $b = $b->xorInt32($c)->rotateLeft(12);
43
44 # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
45 $a = $a->addInt32($b);
46 $d = $d->xorInt32($a)->rotateLeft(8);
47
48 # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
49 $c = $c->addInt32($d);
50 $b = $b->xorInt32($c)->rotateLeft(7);
51
52 return array($a, $b, $c, $d);
53 }
54
55 /**
56 * @internal You should not use this directly from another application
57 *
58 * @param ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx
59 * @param string $message
60 *
61 * @return string
62 * @throws SodiumException
63 * @throws TypeError
64 */
65 public static function encryptBytes(
66 ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx,
67 $message = ''
68 ) {
69 $bytes = self::strlen($message);
70
71 /** @var ParagonIE_Sodium_Core32_Int32 $x0 */
72 /** @var ParagonIE_Sodium_Core32_Int32 $x1 */
73 /** @var ParagonIE_Sodium_Core32_Int32 $x2 */
74 /** @var ParagonIE_Sodium_Core32_Int32 $x3 */
75 /** @var ParagonIE_Sodium_Core32_Int32 $x4 */
76 /** @var ParagonIE_Sodium_Core32_Int32 $x5 */
77 /** @var ParagonIE_Sodium_Core32_Int32 $x6 */
78 /** @var ParagonIE_Sodium_Core32_Int32 $x7 */
79 /** @var ParagonIE_Sodium_Core32_Int32 $x8 */
80 /** @var ParagonIE_Sodium_Core32_Int32 $x9 */
81 /** @var ParagonIE_Sodium_Core32_Int32 $x10 */
82 /** @var ParagonIE_Sodium_Core32_Int32 $x11 */
83 /** @var ParagonIE_Sodium_Core32_Int32 $x12 */
84 /** @var ParagonIE_Sodium_Core32_Int32 $x13 */
85 /** @var ParagonIE_Sodium_Core32_Int32 $x14 */
86 /** @var ParagonIE_Sodium_Core32_Int32 $x15 */
87
88 /*
89 j0 = ctx->input[0];
90 j1 = ctx->input[1];
91 j2 = ctx->input[2];
92 j3 = ctx->input[3];
93 j4 = ctx->input[4];
94 j5 = ctx->input[5];
95 j6 = ctx->input[6];
96 j7 = ctx->input[7];
97 j8 = ctx->input[8];
98 j9 = ctx->input[9];
99 j10 = ctx->input[10];
100 j11 = ctx->input[11];
101 j12 = ctx->input[12];
102 j13 = ctx->input[13];
103 j14 = ctx->input[14];
104 j15 = ctx->input[15];
105 */
106 /** @var ParagonIE_Sodium_Core32_Int32 $j0 */
107 $j0 = $ctx[0];
108 /** @var ParagonIE_Sodium_Core32_Int32 $j1 */
109 $j1 = $ctx[1];
110 /** @var ParagonIE_Sodium_Core32_Int32 $j2 */
111 $j2 = $ctx[2];
112 /** @var ParagonIE_Sodium_Core32_Int32 $j3 */
113 $j3 = $ctx[3];
114 /** @var ParagonIE_Sodium_Core32_Int32 $j4 */
115 $j4 = $ctx[4];
116 /** @var ParagonIE_Sodium_Core32_Int32 $j5 */
117 $j5 = $ctx[5];
118 /** @var ParagonIE_Sodium_Core32_Int32 $j6 */
119 $j6 = $ctx[6];
120 /** @var ParagonIE_Sodium_Core32_Int32 $j7 */
121 $j7 = $ctx[7];
122 /** @var ParagonIE_Sodium_Core32_Int32 $j8 */
123 $j8 = $ctx[8];
124 /** @var ParagonIE_Sodium_Core32_Int32 $j9 */
125 $j9 = $ctx[9];
126 /** @var ParagonIE_Sodium_Core32_Int32 $j10 */
127 $j10 = $ctx[10];
128 /** @var ParagonIE_Sodium_Core32_Int32 $j11 */
129 $j11 = $ctx[11];
130 /** @var ParagonIE_Sodium_Core32_Int32 $j12 */
131 $j12 = $ctx[12];
132 /** @var ParagonIE_Sodium_Core32_Int32 $j13 */
133 $j13 = $ctx[13];
134 /** @var ParagonIE_Sodium_Core32_Int32 $j14 */
135 $j14 = $ctx[14];
136 /** @var ParagonIE_Sodium_Core32_Int32 $j15 */
137 $j15 = $ctx[15];
138
139 $c = '';
140 for (;;) {
141 if ($bytes < 64) {
142 $message .= str_repeat("\x00", 64 - $bytes);
143 }
144
145 $x0 = clone $j0;
146 $x1 = clone $j1;
147 $x2 = clone $j2;
148 $x3 = clone $j3;
149 $x4 = clone $j4;
150 $x5 = clone $j5;
151 $x6 = clone $j6;
152 $x7 = clone $j7;
153 $x8 = clone $j8;
154 $x9 = clone $j9;
155 $x10 = clone $j10;
156 $x11 = clone $j11;
157 $x12 = clone $j12;
158 $x13 = clone $j13;
159 $x14 = clone $j14;
160 $x15 = clone $j15;
161
162 # for (i = 20; i > 0; i -= 2) {
163 for ($i = 20; $i > 0; $i -= 2) {
164 # QUARTERROUND( x0, x4, x8, x12)
165 list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
166
167 # QUARTERROUND( x1, x5, x9, x13)
168 list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
169
170 # QUARTERROUND( x2, x6, x10, x14)
171 list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
172
173 # QUARTERROUND( x3, x7, x11, x15)
174 list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
175
176 # QUARTERROUND( x0, x5, x10, x15)
177 list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
178
179 # QUARTERROUND( x1, x6, x11, x12)
180 list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
181
182 # QUARTERROUND( x2, x7, x8, x13)
183 list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
184
185 # QUARTERROUND( x3, x4, x9, x14)
186 list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
187 }
188 /*
189 x0 = PLUS(x0, j0);
190 x1 = PLUS(x1, j1);
191 x2 = PLUS(x2, j2);
192 x3 = PLUS(x3, j3);
193 x4 = PLUS(x4, j4);
194 x5 = PLUS(x5, j5);
195 x6 = PLUS(x6, j6);
196 x7 = PLUS(x7, j7);
197 x8 = PLUS(x8, j8);
198 x9 = PLUS(x9, j9);
199 x10 = PLUS(x10, j10);
200 x11 = PLUS(x11, j11);
201 x12 = PLUS(x12, j12);
202 x13 = PLUS(x13, j13);
203 x14 = PLUS(x14, j14);
204 x15 = PLUS(x15, j15);
205 */
206 $x0 = $x0->addInt32($j0);
207 $x1 = $x1->addInt32($j1);
208 $x2 = $x2->addInt32($j2);
209 $x3 = $x3->addInt32($j3);
210 $x4 = $x4->addInt32($j4);
211 $x5 = $x5->addInt32($j5);
212 $x6 = $x6->addInt32($j6);
213 $x7 = $x7->addInt32($j7);
214 $x8 = $x8->addInt32($j8);
215 $x9 = $x9->addInt32($j9);
216 $x10 = $x10->addInt32($j10);
217 $x11 = $x11->addInt32($j11);
218 $x12 = $x12->addInt32($j12);
219 $x13 = $x13->addInt32($j13);
220 $x14 = $x14->addInt32($j14);
221 $x15 = $x15->addInt32($j15);
222
223 /*
224 x0 = XOR(x0, LOAD32_LE(m + 0));
225 x1 = XOR(x1, LOAD32_LE(m + 4));
226 x2 = XOR(x2, LOAD32_LE(m + 8));
227 x3 = XOR(x3, LOAD32_LE(m + 12));
228 x4 = XOR(x4, LOAD32_LE(m + 16));
229 x5 = XOR(x5, LOAD32_LE(m + 20));
230 x6 = XOR(x6, LOAD32_LE(m + 24));
231 x7 = XOR(x7, LOAD32_LE(m + 28));
232 x8 = XOR(x8, LOAD32_LE(m + 32));
233 x9 = XOR(x9, LOAD32_LE(m + 36));
234 x10 = XOR(x10, LOAD32_LE(m + 40));
235 x11 = XOR(x11, LOAD32_LE(m + 44));
236 x12 = XOR(x12, LOAD32_LE(m + 48));
237 x13 = XOR(x13, LOAD32_LE(m + 52));
238 x14 = XOR(x14, LOAD32_LE(m + 56));
239 x15 = XOR(x15, LOAD32_LE(m + 60));
240 */
241 $x0 = $x0->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4)));
242 $x1 = $x1->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 4, 4)));
243 $x2 = $x2->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 8, 4)));
244 $x3 = $x3->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4)));
245 $x4 = $x4->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 16, 4)));
246 $x5 = $x5->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 20, 4)));
247 $x6 = $x6->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 24, 4)));
248 $x7 = $x7->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 28, 4)));
249 $x8 = $x8->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 32, 4)));
250 $x9 = $x9->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 36, 4)));
251 $x10 = $x10->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 40, 4)));
252 $x11 = $x11->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 44, 4)));
253 $x12 = $x12->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 48, 4)));
254 $x13 = $x13->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 52, 4)));
255 $x14 = $x14->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 56, 4)));
256 $x15 = $x15->xorInt32(ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 60, 4)));
257
258 /*
259 j12 = PLUSONE(j12);
260 if (!j12) {
261 j13 = PLUSONE(j13);
262 }
263 */
264 /** @var ParagonIE_Sodium_Core32_Int32 $j12 */
265 $j12 = $j12->addInt(1);
266 if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0) {
267 $j13 = $j13->addInt(1);
268 }
269
270 /*
271 STORE32_LE(c + 0, x0);
272 STORE32_LE(c + 4, x1);
273 STORE32_LE(c + 8, x2);
274 STORE32_LE(c + 12, x3);
275 STORE32_LE(c + 16, x4);
276 STORE32_LE(c + 20, x5);
277 STORE32_LE(c + 24, x6);
278 STORE32_LE(c + 28, x7);
279 STORE32_LE(c + 32, x8);
280 STORE32_LE(c + 36, x9);
281 STORE32_LE(c + 40, x10);
282 STORE32_LE(c + 44, x11);
283 STORE32_LE(c + 48, x12);
284 STORE32_LE(c + 52, x13);
285 STORE32_LE(c + 56, x14);
286 STORE32_LE(c + 60, x15);
287 */
288
289 $block = $x0->toReverseString() .
290 $x1->toReverseString() .
291 $x2->toReverseString() .
292 $x3->toReverseString() .
293 $x4->toReverseString() .
294 $x5->toReverseString() .
295 $x6->toReverseString() .
296 $x7->toReverseString() .
297 $x8->toReverseString() .
298 $x9->toReverseString() .
299 $x10->toReverseString() .
300 $x11->toReverseString() .
301 $x12->toReverseString() .
302 $x13->toReverseString() .
303 $x14->toReverseString() .
304 $x15->toReverseString();
305
306 /* Partial block */
307 if ($bytes < 64) {
308 $c .= self::substr($block, 0, $bytes);
309 break;
310 }
311
312 /* Full block */
313 $c .= $block;
314 $bytes -= 64;
315 if ($bytes <= 0) {
316 break;
317 }
318 $message = self::substr($message, 64);
319 }
320 /* end for(;;) loop */
321
322 $ctx[12] = $j12;
323 $ctx[13] = $j13;
324 return $c;
325 }
326
327 /**
328 * @internal You should not use this directly from another application
329 *
330 * @param int $len
331 * @param string $nonce
332 * @param string $key
333 * @return string
334 * @throws SodiumException
335 * @throws TypeError
336 */
337 public static function stream($len = 64, $nonce = '', $key = '')
338 {
339 return self::encryptBytes(
340 new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce),
341 str_repeat("\x00", $len)
342 );
343 }
344
345 /**
346 * @internal You should not use this directly from another application
347 *
348 * @param int $len
349 * @param string $nonce
350 * @param string $key
351 * @return string
352 * @throws SodiumException
353 * @throws TypeError
354 */
355 public static function ietfStream($len, $nonce = '', $key = '')
356 {
357 return self::encryptBytes(
358 new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce),
359 str_repeat("\x00", $len)
360 );
361 }
362
363 /**
364 * @internal You should not use this directly from another application
365 *
366 * @param string $message
367 * @param string $nonce
368 * @param string $key
369 * @param string $ic
370 * @return string
371 * @throws SodiumException
372 * @throws TypeError
373 */
374 public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
375 {
376 return self::encryptBytes(
377 new ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce, $ic),
378 $message
379 );
380 }
381
382 /**
383 * @internal You should not use this directly from another application
384 *
385 * @param string $message
386 * @param string $nonce
387 * @param string $key
388 * @param string $ic
389 * @return string
390 * @throws SodiumException
391 * @throws TypeError
392 */
393 public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
394 {
395 return self::encryptBytes(
396 new ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce, $ic),
397 $message
398 );
399 }
400}
401