Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,1654 @@
1
+<?php
2
+
3
+if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
4
+    return;
5
+}
6
+
7
+/**
8
+ * Class ParagonIE_Sodium_Crypto
9
+ *
10
+ * ATTENTION!
11
+ *
12
+ * If you are using this library, you should be using
13
+ * ParagonIE_Sodium_Compat in your code, not this class.
14
+ */
15
+abstract class ParagonIE_Sodium_Crypto32
16
+{
17
+    const aead_chacha20poly1305_KEYBYTES = 32;
18
+    const aead_chacha20poly1305_NSECBYTES = 0;
19
+    const aead_chacha20poly1305_NPUBBYTES = 8;
20
+    const aead_chacha20poly1305_ABYTES = 16;
21
+
22
+    const aead_chacha20poly1305_IETF_KEYBYTES = 32;
23
+    const aead_chacha20poly1305_IETF_NSECBYTES = 0;
24
+    const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
25
+    const aead_chacha20poly1305_IETF_ABYTES = 16;
26
+
27
+    const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
28
+    const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
29
+    const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
30
+    const aead_xchacha20poly1305_IETF_ABYTES = 16;
31
+
32
+    const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
33
+    const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
34
+    const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
35
+    const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
36
+    const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
37
+    const box_curve25519xsalsa20poly1305_MACBYTES = 16;
38
+    const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
39
+    const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
40
+
41
+    const onetimeauth_poly1305_BYTES = 16;
42
+    const onetimeauth_poly1305_KEYBYTES = 32;
43
+
44
+    const secretbox_xsalsa20poly1305_KEYBYTES = 32;
45
+    const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
46
+    const secretbox_xsalsa20poly1305_MACBYTES = 16;
47
+    const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
48
+    const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
49
+
50
+    const secretbox_xchacha20poly1305_KEYBYTES = 32;
51
+    const secretbox_xchacha20poly1305_NONCEBYTES = 24;
52
+    const secretbox_xchacha20poly1305_MACBYTES = 16;
53
+    const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
54
+    const secretbox_xchacha20poly1305_ZEROBYTES = 32;
55
+
56
+    const stream_salsa20_KEYBYTES = 32;
57
+
58
+    /**
59
+     * AEAD Decryption with ChaCha20-Poly1305
60
+     *
61
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
62
+     *
63
+     * @param string $message
64
+     * @param string $ad
65
+     * @param string $nonce
66
+     * @param string $key
67
+     * @return string
68
+     * @throws SodiumException
69
+     * @throws TypeError
70
+     */
71
+    public static function aead_chacha20poly1305_decrypt(
72
+        $message = '',
73
+        $ad = '',
74
+        $nonce = '',
75
+        $key = ''
76
+    ) {
77
+        /** @var int $len - Length of message (ciphertext + MAC) */
78
+        $len = ParagonIE_Sodium_Core32_Util::strlen($message);
79
+
80
+        /** @var int  $clen - Length of ciphertext */
81
+        $clen = $len - self::aead_chacha20poly1305_ABYTES;
82
+
83
+        /** @var int $adlen - Length of associated data */
84
+        $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
85
+
86
+        /** @var string $mac - Message authentication code */
87
+        $mac = ParagonIE_Sodium_Core32_Util::substr(
88
+            $message,
89
+            $clen,
90
+            self::aead_chacha20poly1305_ABYTES
91
+        );
92
+
93
+        /** @var string $ciphertext - The encrypted message (sans MAC) */
94
+        $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen);
95
+
96
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
97
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
98
+            32,
99
+            $nonce,
100
+            $key
101
+        );
102
+
103
+        /* Recalculate the Poly1305 authentication tag (MAC): */
104
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
105
+        try {
106
+            ParagonIE_Sodium_Compat::memzero($block0);
107
+        } catch (SodiumException $ex) {
108
+            $block0 = null;
109
+        }
110
+        $state->update($ad);
111
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
112
+        $state->update($ciphertext);
113
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
114
+        $computed_mac = $state->finish();
115
+
116
+        /* Compare the given MAC with the recalculated MAC: */
117
+        if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
118
+            throw new SodiumException('Invalid MAC');
119
+        }
120
+
121
+        // Here, we know that the MAC is valid, so we decrypt and return the plaintext
122
+        return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
123
+            $ciphertext,
124
+            $nonce,
125
+            $key,
126
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
127
+        );
128
+    }
129
+
130
+    /**
131
+     * AEAD Encryption with ChaCha20-Poly1305
132
+     *
133
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
134
+     *
135
+     * @param string $message
136
+     * @param string $ad
137
+     * @param string $nonce
138
+     * @param string $key
139
+     * @return string
140
+     * @throws SodiumException
141
+     * @throws TypeError
142
+     */
143
+    public static function aead_chacha20poly1305_encrypt(
144
+        $message = '',
145
+        $ad = '',
146
+        $nonce = '',
147
+        $key = ''
148
+    ) {
149
+        /** @var int $len - Length of the plaintext message */
150
+        $len = ParagonIE_Sodium_Core32_Util::strlen($message);
151
+
152
+        /** @var int $adlen - Length of the associated data */
153
+        $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
154
+
155
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
156
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
157
+            32,
158
+            $nonce,
159
+            $key
160
+        );
161
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
162
+        try {
163
+            ParagonIE_Sodium_Compat::memzero($block0);
164
+        } catch (SodiumException $ex) {
165
+            $block0 = null;
166
+        }
167
+
168
+        /** @var string $ciphertext - Raw encrypted data */
169
+        $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
170
+            $message,
171
+            $nonce,
172
+            $key,
173
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
174
+        );
175
+
176
+        $state->update($ad);
177
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
178
+        $state->update($ciphertext);
179
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
180
+        return $ciphertext . $state->finish();
181
+    }
182
+
183
+    /**
184
+     * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
185
+     *
186
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
187
+     *
188
+     * @param string $message
189
+     * @param string $ad
190
+     * @param string $nonce
191
+     * @param string $key
192
+     * @return string
193
+     * @throws SodiumException
194
+     * @throws TypeError
195
+     */
196
+    public static function aead_chacha20poly1305_ietf_decrypt(
197
+        $message = '',
198
+        $ad = '',
199
+        $nonce = '',
200
+        $key = ''
201
+    ) {
202
+        /** @var int $adlen - Length of associated data */
203
+        $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
204
+
205
+        /** @var int $len - Length of message (ciphertext + MAC) */
206
+        $len = ParagonIE_Sodium_Core32_Util::strlen($message);
207
+
208
+        /** @var int  $clen - Length of ciphertext */
209
+        $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
210
+
211
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
212
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
213
+            32,
214
+            $nonce,
215
+            $key
216
+        );
217
+
218
+        /** @var string $mac - Message authentication code */
219
+        $mac = ParagonIE_Sodium_Core32_Util::substr(
220
+            $message,
221
+            $len - self::aead_chacha20poly1305_IETF_ABYTES,
222
+            self::aead_chacha20poly1305_IETF_ABYTES
223
+        );
224
+
225
+        /** @var string $ciphertext - The encrypted message (sans MAC) */
226
+        $ciphertext = ParagonIE_Sodium_Core32_Util::substr(
227
+            $message,
228
+            0,
229
+            $len - self::aead_chacha20poly1305_IETF_ABYTES
230
+        );
231
+
232
+        /* Recalculate the Poly1305 authentication tag (MAC): */
233
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
234
+        try {
235
+            ParagonIE_Sodium_Compat::memzero($block0);
236
+        } catch (SodiumException $ex) {
237
+            $block0 = null;
238
+        }
239
+        $state->update($ad);
240
+        $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
241
+        $state->update($ciphertext);
242
+        $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf));
243
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
244
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
245
+        $computed_mac = $state->finish();
246
+
247
+        /* Compare the given MAC with the recalculated MAC: */
248
+        if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
249
+            throw new SodiumException('Invalid MAC');
250
+        }
251
+
252
+        // Here, we know that the MAC is valid, so we decrypt and return the plaintext
253
+        return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
254
+            $ciphertext,
255
+            $nonce,
256
+            $key,
257
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
258
+        );
259
+    }
260
+
261
+    /**
262
+     * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
263
+     *
264
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
265
+     *
266
+     * @param string $message
267
+     * @param string $ad
268
+     * @param string $nonce
269
+     * @param string $key
270
+     * @return string
271
+     * @throws SodiumException
272
+     * @throws TypeError
273
+     */
274
+    public static function aead_chacha20poly1305_ietf_encrypt(
275
+        $message = '',
276
+        $ad = '',
277
+        $nonce = '',
278
+        $key = ''
279
+    ) {
280
+        /** @var int $len - Length of the plaintext message */
281
+        $len = ParagonIE_Sodium_Core32_Util::strlen($message);
282
+
283
+        /** @var int $adlen - Length of the associated data */
284
+        $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
285
+
286
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
287
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
288
+            32,
289
+            $nonce,
290
+            $key
291
+        );
292
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
293
+        try {
294
+            ParagonIE_Sodium_Compat::memzero($block0);
295
+        } catch (SodiumException $ex) {
296
+            $block0 = null;
297
+        }
298
+
299
+        /** @var string $ciphertext - Raw encrypted data */
300
+        $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
301
+            $message,
302
+            $nonce,
303
+            $key,
304
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
305
+        );
306
+
307
+        $state->update($ad);
308
+        $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
309
+        $state->update($ciphertext);
310
+        $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf)));
311
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
312
+        $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
313
+        return $ciphertext . $state->finish();
314
+    }
315
+
316
+    /**
317
+     * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
318
+     *
319
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
320
+     *
321
+     * @param string $message
322
+     * @param string $ad
323
+     * @param string $nonce
324
+     * @param string $key
325
+     * @return string
326
+     * @throws SodiumException
327
+     * @throws TypeError
328
+     */
329
+    public static function aead_xchacha20poly1305_ietf_decrypt(
330
+        $message = '',
331
+        $ad = '',
332
+        $nonce = '',
333
+        $key = ''
334
+    ) {
335
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
336
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
337
+            $key
338
+        );
339
+        $nonceLast = "\x00\x00\x00\x00" .
340
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
341
+
342
+        return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
343
+    }
344
+
345
+    /**
346
+     * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
347
+     *
348
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
349
+     *
350
+     * @param string $message
351
+     * @param string $ad
352
+     * @param string $nonce
353
+     * @param string $key
354
+     * @return string
355
+     * @throws SodiumException
356
+     * @throws TypeError
357
+     */
358
+    public static function aead_xchacha20poly1305_ietf_encrypt(
359
+        $message = '',
360
+        $ad = '',
361
+        $nonce = '',
362
+        $key = ''
363
+    ) {
364
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
365
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
366
+            $key
367
+        );
368
+        $nonceLast = "\x00\x00\x00\x00" .
369
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
370
+
371
+        return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
372
+    }
373
+
374
+    /**
375
+     * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
376
+     *
377
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
378
+     *
379
+     * @param string $message
380
+     * @param string $key
381
+     * @return string
382
+     * @throws TypeError
383
+     */
384
+    public static function auth($message, $key)
385
+    {
386
+        return ParagonIE_Sodium_Core32_Util::substr(
387
+            hash_hmac('sha512', $message, $key, true),
388
+            0,
389
+            32
390
+        );
391
+    }
392
+
393
+    /**
394
+     * HMAC-SHA-512-256 validation. Constant-time via hash_equals().
395
+     *
396
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
397
+     *
398
+     * @param string $mac
399
+     * @param string $message
400
+     * @param string $key
401
+     * @return bool
402
+     * @throws SodiumException
403
+     * @throws TypeError
404
+     */
405
+    public static function auth_verify($mac, $message, $key)
406
+    {
407
+        return ParagonIE_Sodium_Core32_Util::hashEquals(
408
+            $mac,
409
+            self::auth($message, $key)
410
+        );
411
+    }
412
+
413
+    /**
414
+     * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
415
+     *
416
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
417
+     *
418
+     * @param string $plaintext
419
+     * @param string $nonce
420
+     * @param string $keypair
421
+     * @return string
422
+     * @throws SodiumException
423
+     * @throws TypeError
424
+     */
425
+    public static function box($plaintext, $nonce, $keypair)
426
+    {
427
+        return self::secretbox(
428
+            $plaintext,
429
+            $nonce,
430
+            self::box_beforenm(
431
+                self::box_secretkey($keypair),
432
+                self::box_publickey($keypair)
433
+            )
434
+        );
435
+    }
436
+
437
+    /**
438
+     * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
439
+     *
440
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
441
+     *
442
+     * @param string $message
443
+     * @param string $publicKey
444
+     * @return string
445
+     * @throws SodiumException
446
+     * @throws TypeError
447
+     */
448
+    public static function box_seal($message, $publicKey)
449
+    {
450
+        /** @var string $ephemeralKeypair */
451
+        $ephemeralKeypair = self::box_keypair();
452
+
453
+        /** @var string $ephemeralSK */
454
+        $ephemeralSK = self::box_secretkey($ephemeralKeypair);
455
+
456
+        /** @var string $ephemeralPK */
457
+        $ephemeralPK = self::box_publickey($ephemeralKeypair);
458
+
459
+        /** @var string $nonce */
460
+        $nonce = self::generichash(
461
+            $ephemeralPK . $publicKey,
462
+            '',
463
+            24
464
+        );
465
+
466
+        /** @var string $keypair - The combined keypair used in crypto_box() */
467
+        $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
468
+
469
+        /** @var string $ciphertext Ciphertext + MAC from crypto_box */
470
+        $ciphertext = self::box($message, $nonce, $keypair);
471
+        try {
472
+            ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
473
+            ParagonIE_Sodium_Compat::memzero($ephemeralSK);
474
+            ParagonIE_Sodium_Compat::memzero($nonce);
475
+        } catch (SodiumException $ex) {
476
+            $ephemeralKeypair = null;
477
+            $ephemeralSK = null;
478
+            $nonce = null;
479
+        }
480
+        return $ephemeralPK . $ciphertext;
481
+    }
482
+
483
+    /**
484
+     * Opens a message encrypted via box_seal().
485
+     *
486
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
487
+     *
488
+     * @param string $message
489
+     * @param string $keypair
490
+     * @return string
491
+     * @throws SodiumException
492
+     * @throws TypeError
493
+     */
494
+    public static function box_seal_open($message, $keypair)
495
+    {
496
+        /** @var string $ephemeralPK */
497
+        $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32);
498
+
499
+        /** @var string $ciphertext (ciphertext + MAC) */
500
+        $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
501
+
502
+        /** @var string $secretKey */
503
+        $secretKey = self::box_secretkey($keypair);
504
+
505
+        /** @var string $publicKey */
506
+        $publicKey = self::box_publickey($keypair);
507
+
508
+        /** @var string $nonce */
509
+        $nonce = self::generichash(
510
+            $ephemeralPK . $publicKey,
511
+            '',
512
+            24
513
+        );
514
+
515
+        /** @var string $keypair */
516
+        $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
517
+
518
+        /** @var string $m */
519
+        $m = self::box_open($ciphertext, $nonce, $keypair);
520
+        try {
521
+            ParagonIE_Sodium_Compat::memzero($secretKey);
522
+            ParagonIE_Sodium_Compat::memzero($ephemeralPK);
523
+            ParagonIE_Sodium_Compat::memzero($nonce);
524
+        } catch (SodiumException $ex) {
525
+            $secretKey = null;
526
+            $ephemeralPK = null;
527
+            $nonce = null;
528
+        }
529
+        return $m;
530
+    }
531
+
532
+    /**
533
+     * Used by crypto_box() to get the crypto_secretbox() key.
534
+     *
535
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
536
+     *
537
+     * @param string $sk
538
+     * @param string $pk
539
+     * @return string
540
+     * @throws SodiumException
541
+     * @throws TypeError
542
+     */
543
+    public static function box_beforenm($sk, $pk)
544
+    {
545
+        return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(
546
+            str_repeat("\x00", 16),
547
+            self::scalarmult($sk, $pk)
548
+        );
549
+    }
550
+
551
+    /**
552
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
553
+     *
554
+     * @return string
555
+     * @throws Exception
556
+     * @throws SodiumException
557
+     * @throws TypeError
558
+     */
559
+    public static function box_keypair()
560
+    {
561
+        $sKey = random_bytes(32);
562
+        $pKey = self::scalarmult_base($sKey);
563
+        return $sKey . $pKey;
564
+    }
565
+
566
+    /**
567
+     * @param string $seed
568
+     * @return string
569
+     * @throws SodiumException
570
+     * @throws TypeError
571
+     */
572
+    public static function box_seed_keypair($seed)
573
+    {
574
+        $sKey = ParagonIE_Sodium_Core32_Util::substr(
575
+            hash('sha512', $seed, true),
576
+            0,
577
+            32
578
+        );
579
+        $pKey = self::scalarmult_base($sKey);
580
+        return $sKey . $pKey;
581
+    }
582
+
583
+    /**
584
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
585
+     *
586
+     * @param string $sKey
587
+     * @param string $pKey
588
+     * @return string
589
+     * @throws TypeError
590
+     */
591
+    public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
592
+    {
593
+        return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) .
594
+            ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32);
595
+    }
596
+
597
+    /**
598
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
599
+     *
600
+     * @param string $keypair
601
+     * @return string
602
+     * @throws RangeException
603
+     * @throws TypeError
604
+     */
605
+    public static function box_secretkey($keypair)
606
+    {
607
+        if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) {
608
+            throw new RangeException(
609
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
610
+            );
611
+        }
612
+        return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32);
613
+    }
614
+
615
+    /**
616
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
617
+     *
618
+     * @param string $keypair
619
+     * @return string
620
+     * @throws RangeException
621
+     * @throws TypeError
622
+     */
623
+    public static function box_publickey($keypair)
624
+    {
625
+        if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
626
+            throw new RangeException(
627
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
628
+            );
629
+        }
630
+        return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32);
631
+    }
632
+
633
+    /**
634
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
635
+     *
636
+     * @param string $sKey
637
+     * @return string
638
+     * @throws RangeException
639
+     * @throws SodiumException
640
+     * @throws TypeError
641
+     */
642
+    public static function box_publickey_from_secretkey($sKey)
643
+    {
644
+        if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
645
+            throw new RangeException(
646
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
647
+            );
648
+        }
649
+        return self::scalarmult_base($sKey);
650
+    }
651
+
652
+    /**
653
+     * Decrypt a message encrypted with box().
654
+     *
655
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
656
+     *
657
+     * @param string $ciphertext
658
+     * @param string $nonce
659
+     * @param string $keypair
660
+     * @return string
661
+     * @throws SodiumException
662
+     * @throws TypeError
663
+     */
664
+    public static function box_open($ciphertext, $nonce, $keypair)
665
+    {
666
+        return self::secretbox_open(
667
+            $ciphertext,
668
+            $nonce,
669
+            self::box_beforenm(
670
+                self::box_secretkey($keypair),
671
+                self::box_publickey($keypair)
672
+            )
673
+        );
674
+    }
675
+
676
+    /**
677
+     * Calculate a BLAKE2b hash.
678
+     *
679
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
680
+     *
681
+     * @param string $message
682
+     * @param string|null $key
683
+     * @param int $outlen
684
+     * @return string
685
+     * @throws RangeException
686
+     * @throws SodiumException
687
+     * @throws TypeError
688
+     */
689
+    public static function generichash($message, $key = '', $outlen = 32)
690
+    {
691
+        // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
692
+        ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
693
+
694
+        $k = null;
695
+        if (!empty($key)) {
696
+            /** @var SplFixedArray $k */
697
+            $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
698
+            if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
699
+                throw new RangeException('Invalid key size');
700
+            }
701
+        }
702
+
703
+        /** @var SplFixedArray $in */
704
+        $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
705
+
706
+        /** @var SplFixedArray $ctx */
707
+        $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
708
+        ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count());
709
+
710
+        /** @var SplFixedArray $out */
711
+        $out = new SplFixedArray($outlen);
712
+        $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
713
+
714
+        /** @var array<int, int> */
715
+        $outArray = $out->toArray();
716
+        return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
717
+    }
718
+
719
+    /**
720
+     * Finalize a BLAKE2b hashing context, returning the hash.
721
+     *
722
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
723
+     *
724
+     * @param string $ctx
725
+     * @param int $outlen
726
+     * @return string
727
+     * @throws SodiumException
728
+     * @throws TypeError
729
+     */
730
+    public static function generichash_final($ctx, $outlen = 32)
731
+    {
732
+        if (!is_string($ctx)) {
733
+            throw new TypeError('Context must be a string');
734
+        }
735
+        $out = new SplFixedArray($outlen);
736
+
737
+        /** @var SplFixedArray $context */
738
+        $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
739
+
740
+        /** @var SplFixedArray $out */
741
+        $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
742
+
743
+        /** @var array<int, int> */
744
+        $outArray = $out->toArray();
745
+        return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
746
+    }
747
+
748
+    /**
749
+     * Initialize a hashing context for BLAKE2b.
750
+     *
751
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
752
+     *
753
+     * @param string $key
754
+     * @param int $outputLength
755
+     * @return string
756
+     * @throws RangeException
757
+     * @throws SodiumException
758
+     * @throws TypeError
759
+     */
760
+    public static function generichash_init($key = '', $outputLength = 32)
761
+    {
762
+        // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
763
+        ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
764
+
765
+        $k = null;
766
+        if (!empty($key)) {
767
+            $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
768
+            if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
769
+                throw new RangeException('Invalid key size');
770
+            }
771
+        }
772
+
773
+        /** @var SplFixedArray $ctx */
774
+        $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
775
+
776
+        return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
777
+    }
778
+
779
+    /**
780
+     * Initialize a hashing context for BLAKE2b.
781
+     *
782
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
783
+     *
784
+     * @param string $key
785
+     * @param int $outputLength
786
+     * @param string $salt
787
+     * @param string $personal
788
+     * @return string
789
+     * @throws RangeException
790
+     * @throws SodiumException
791
+     * @throws TypeError
792
+     */
793
+    public static function generichash_init_salt_personal(
794
+        $key = '',
795
+        $outputLength = 32,
796
+        $salt = '',
797
+        $personal = ''
798
+    ) {
799
+        // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
800
+        ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
801
+
802
+        $k = null;
803
+        if (!empty($key)) {
804
+            $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
805
+            if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
806
+                throw new RangeException('Invalid key size');
807
+            }
808
+        }
809
+        if (!empty($salt)) {
810
+            $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
811
+        } else {
812
+            $s = null;
813
+        }
814
+        if (!empty($salt)) {
815
+            $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
816
+        } else {
817
+            $p = null;
818
+        }
819
+
820
+        /** @var SplFixedArray $ctx */
821
+        $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p);
822
+
823
+        return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
824
+    }
825
+
826
+    /**
827
+     * Update a hashing context for BLAKE2b with $message
828
+     *
829
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
830
+     *
831
+     * @param string $ctx
832
+     * @param string $message
833
+     * @return string
834
+     * @throws SodiumException
835
+     * @throws TypeError
836
+     */
837
+    public static function generichash_update($ctx, $message)
838
+    {
839
+        // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
840
+        ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
841
+
842
+        /** @var SplFixedArray $context */
843
+        $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
844
+
845
+        /** @var SplFixedArray $in */
846
+        $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
847
+
848
+        ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count());
849
+
850
+        return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
851
+    }
852
+
853
+    /**
854
+     * Libsodium's crypto_kx().
855
+     *
856
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
857
+     *
858
+     * @param string $my_sk
859
+     * @param string $their_pk
860
+     * @param string $client_pk
861
+     * @param string $server_pk
862
+     * @return string
863
+     * @throws SodiumException
864
+     * @throws TypeError
865
+     */
866
+    public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
867
+    {
868
+        return self::generichash(
869
+            self::scalarmult($my_sk, $their_pk) .
870
+            $client_pk .
871
+            $server_pk
872
+        );
873
+    }
874
+
875
+    /**
876
+     * ECDH over Curve25519
877
+     *
878
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
879
+     *
880
+     * @param string $sKey
881
+     * @param string $pKey
882
+     * @return string
883
+     *
884
+     * @throws SodiumException
885
+     * @throws TypeError
886
+     */
887
+    public static function scalarmult($sKey, $pKey)
888
+    {
889
+        $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
890
+        self::scalarmult_throw_if_zero($q);
891
+        return $q;
892
+    }
893
+
894
+    /**
895
+     * ECDH over Curve25519, using the basepoint.
896
+     * Used to get a secret key from a public key.
897
+     *
898
+     * @param string $secret
899
+     * @return string
900
+     *
901
+     * @throws SodiumException
902
+     * @throws TypeError
903
+     */
904
+    public static function scalarmult_base($secret)
905
+    {
906
+        $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
907
+        self::scalarmult_throw_if_zero($q);
908
+        return $q;
909
+    }
910
+
911
+    /**
912
+     * This throws an Error if a zero public key was passed to the function.
913
+     *
914
+     * @param string $q
915
+     * @return void
916
+     * @throws SodiumException
917
+     * @throws TypeError
918
+     */
919
+    protected static function scalarmult_throw_if_zero($q)
920
+    {
921
+        $d = 0;
922
+        for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
923
+            $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]);
924
+        }
925
+
926
+        /* branch-free variant of === 0 */
927
+        if (-(1 & (($d - 1) >> 8))) {
928
+            throw new SodiumException('Zero public key is not allowed');
929
+        }
930
+    }
931
+
932
+    /**
933
+     * XSalsa20-Poly1305 authenticated symmetric-key encryption.
934
+     *
935
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
936
+     *
937
+     * @param string $plaintext
938
+     * @param string $nonce
939
+     * @param string $key
940
+     * @return string
941
+     * @throws SodiumException
942
+     * @throws TypeError
943
+     */
944
+    public static function secretbox($plaintext, $nonce, $key)
945
+    {
946
+        /** @var string $subkey */
947
+        $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
948
+
949
+        /** @var string $block0 */
950
+        $block0 = str_repeat("\x00", 32);
951
+
952
+        /** @var int $mlen - Length of the plaintext message */
953
+        $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
954
+        $mlen0 = $mlen;
955
+        if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
956
+            $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
957
+        }
958
+        $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
959
+
960
+        /** @var string $block0 */
961
+        $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
962
+            $block0,
963
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
964
+            $subkey
965
+        );
966
+
967
+        /** @var string $c */
968
+        $c = ParagonIE_Sodium_Core32_Util::substr(
969
+            $block0,
970
+            self::secretbox_xsalsa20poly1305_ZEROBYTES
971
+        );
972
+        if ($mlen > $mlen0) {
973
+            $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
974
+                ParagonIE_Sodium_Core32_Util::substr(
975
+                    $plaintext,
976
+                    self::secretbox_xsalsa20poly1305_ZEROBYTES
977
+                ),
978
+                ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
979
+                1,
980
+                $subkey
981
+            );
982
+        }
983
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State(
984
+            ParagonIE_Sodium_Core32_Util::substr(
985
+                $block0,
986
+                0,
987
+                self::onetimeauth_poly1305_KEYBYTES
988
+            )
989
+        );
990
+        try {
991
+            ParagonIE_Sodium_Compat::memzero($block0);
992
+            ParagonIE_Sodium_Compat::memzero($subkey);
993
+        } catch (SodiumException $ex) {
994
+            $block0 = null;
995
+            $subkey = null;
996
+        }
997
+
998
+        $state->update($c);
999
+
1000
+        /** @var string $c - MAC || ciphertext */
1001
+        $c = $state->finish() . $c;
1002
+        unset($state);
1003
+
1004
+        return $c;
1005
+    }
1006
+
1007
+    /**
1008
+     * Decrypt a ciphertext generated via secretbox().
1009
+     *
1010
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1011
+     *
1012
+     * @param string $ciphertext
1013
+     * @param string $nonce
1014
+     * @param string $key
1015
+     * @return string
1016
+     * @throws SodiumException
1017
+     * @throws TypeError
1018
+     */
1019
+    public static function secretbox_open($ciphertext, $nonce, $key)
1020
+    {
1021
+        /** @var string $mac */
1022
+        $mac = ParagonIE_Sodium_Core32_Util::substr(
1023
+            $ciphertext,
1024
+            0,
1025
+            self::secretbox_xsalsa20poly1305_MACBYTES
1026
+        );
1027
+
1028
+        /** @var string $c */
1029
+        $c = ParagonIE_Sodium_Core32_Util::substr(
1030
+            $ciphertext,
1031
+            self::secretbox_xsalsa20poly1305_MACBYTES
1032
+        );
1033
+
1034
+        /** @var int $clen */
1035
+        $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
1036
+
1037
+        /** @var string $subkey */
1038
+        $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
1039
+
1040
+        /** @var string $block0 */
1041
+        $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
1042
+            64,
1043
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1044
+            $subkey
1045
+        );
1046
+        $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
1047
+            $mac,
1048
+            $c,
1049
+            ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
1050
+        );
1051
+        if (!$verified) {
1052
+            try {
1053
+                ParagonIE_Sodium_Compat::memzero($subkey);
1054
+            } catch (SodiumException $ex) {
1055
+                $subkey = null;
1056
+            }
1057
+            throw new SodiumException('Invalid MAC');
1058
+        }
1059
+
1060
+        /** @var string $m - Decrypted message */
1061
+        $m = ParagonIE_Sodium_Core32_Util::xorStrings(
1062
+            ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
1063
+            ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
1064
+        );
1065
+        if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
1066
+            // We had more than 1 block, so let's continue to decrypt the rest.
1067
+            $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
1068
+                ParagonIE_Sodium_Core32_Util::substr(
1069
+                    $c,
1070
+                    self::secretbox_xsalsa20poly1305_ZEROBYTES
1071
+                ),
1072
+                ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1073
+                1,
1074
+                (string) $subkey
1075
+            );
1076
+        }
1077
+        return $m;
1078
+    }
1079
+
1080
+    /**
1081
+     * XChaCha20-Poly1305 authenticated symmetric-key encryption.
1082
+     *
1083
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1084
+     *
1085
+     * @param string $plaintext
1086
+     * @param string $nonce
1087
+     * @param string $key
1088
+     * @return string
1089
+     * @throws SodiumException
1090
+     * @throws TypeError
1091
+     */
1092
+    public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
1093
+    {
1094
+        /** @var string $subkey */
1095
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
1096
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
1097
+            $key
1098
+        );
1099
+        $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
1100
+
1101
+        /** @var string $block0 */
1102
+        $block0 = str_repeat("\x00", 32);
1103
+
1104
+        /** @var int $mlen - Length of the plaintext message */
1105
+        $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
1106
+        $mlen0 = $mlen;
1107
+        if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
1108
+            $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
1109
+        }
1110
+        $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
1111
+
1112
+        /** @var string $block0 */
1113
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1114
+            $block0,
1115
+            $nonceLast,
1116
+            $subkey
1117
+        );
1118
+
1119
+        /** @var string $c */
1120
+        $c = ParagonIE_Sodium_Core32_Util::substr(
1121
+            $block0,
1122
+            self::secretbox_xchacha20poly1305_ZEROBYTES
1123
+        );
1124
+        if ($mlen > $mlen0) {
1125
+            $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1126
+                ParagonIE_Sodium_Core32_Util::substr(
1127
+                    $plaintext,
1128
+                    self::secretbox_xchacha20poly1305_ZEROBYTES
1129
+                ),
1130
+                $nonceLast,
1131
+                $subkey,
1132
+                ParagonIE_Sodium_Core32_Util::store64_le(1)
1133
+            );
1134
+        }
1135
+        $state = new ParagonIE_Sodium_Core32_Poly1305_State(
1136
+            ParagonIE_Sodium_Core32_Util::substr(
1137
+                $block0,
1138
+                0,
1139
+                self::onetimeauth_poly1305_KEYBYTES
1140
+            )
1141
+        );
1142
+        try {
1143
+            ParagonIE_Sodium_Compat::memzero($block0);
1144
+            ParagonIE_Sodium_Compat::memzero($subkey);
1145
+        } catch (SodiumException $ex) {
1146
+            $block0 = null;
1147
+            $subkey = null;
1148
+        }
1149
+
1150
+        $state->update($c);
1151
+
1152
+        /** @var string $c - MAC || ciphertext */
1153
+        $c = $state->finish() . $c;
1154
+        unset($state);
1155
+
1156
+        return $c;
1157
+    }
1158
+
1159
+    /**
1160
+     * Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
1161
+     *
1162
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1163
+     *
1164
+     * @param string $ciphertext
1165
+     * @param string $nonce
1166
+     * @param string $key
1167
+     * @return string
1168
+     * @throws SodiumException
1169
+     * @throws TypeError
1170
+     */
1171
+    public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
1172
+    {
1173
+        /** @var string $mac */
1174
+        $mac = ParagonIE_Sodium_Core32_Util::substr(
1175
+            $ciphertext,
1176
+            0,
1177
+            self::secretbox_xchacha20poly1305_MACBYTES
1178
+        );
1179
+
1180
+        /** @var string $c */
1181
+        $c = ParagonIE_Sodium_Core32_Util::substr(
1182
+            $ciphertext,
1183
+            self::secretbox_xchacha20poly1305_MACBYTES
1184
+        );
1185
+
1186
+        /** @var int $clen */
1187
+        $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
1188
+
1189
+        /** @var string $subkey */
1190
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key);
1191
+
1192
+        /** @var string $block0 */
1193
+        $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
1194
+            64,
1195
+            ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1196
+            $subkey
1197
+        );
1198
+        $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
1199
+            $mac,
1200
+            $c,
1201
+            ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
1202
+        );
1203
+
1204
+        if (!$verified) {
1205
+            try {
1206
+                ParagonIE_Sodium_Compat::memzero($subkey);
1207
+            } catch (SodiumException $ex) {
1208
+                $subkey = null;
1209
+            }
1210
+            throw new SodiumException('Invalid MAC');
1211
+        }
1212
+
1213
+        /** @var string $m - Decrypted message */
1214
+        $m = ParagonIE_Sodium_Core32_Util::xorStrings(
1215
+            ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
1216
+            ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
1217
+        );
1218
+
1219
+        if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
1220
+            // We had more than 1 block, so let's continue to decrypt the rest.
1221
+            $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1222
+                ParagonIE_Sodium_Core32_Util::substr(
1223
+                    $c,
1224
+                    self::secretbox_xchacha20poly1305_ZEROBYTES
1225
+                ),
1226
+                ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1227
+                (string) $subkey,
1228
+                ParagonIE_Sodium_Core32_Util::store64_le(1)
1229
+            );
1230
+        }
1231
+        return $m;
1232
+    }
1233
+
1234
+    /**
1235
+     * @param string $key
1236
+     * @return array<int, string> Returns a state and a header.
1237
+     * @throws Exception
1238
+     * @throws SodiumException
1239
+     */
1240
+    public static function secretstream_xchacha20poly1305_init_push($key)
1241
+    {
1242
+        # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
1243
+        $out = random_bytes(24);
1244
+
1245
+        # crypto_core_hchacha20(state->k, out, k, NULL);
1246
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
1247
+        $state = new ParagonIE_Sodium_Core32_SecretStream_State(
1248
+            $subkey,
1249
+            ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4)
1250
+        );
1251
+
1252
+        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
1253
+        $state->counterReset();
1254
+
1255
+        # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
1256
+        #        crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1257
+        # memset(state->_pad, 0, sizeof state->_pad);
1258
+        return array(
1259
+            $state->toString(),
1260
+            $out
1261
+        );
1262
+    }
1263
+
1264
+    /**
1265
+     * @param string $key
1266
+     * @param string $header
1267
+     * @return string Returns a state.
1268
+     * @throws Exception
1269
+     */
1270
+    public static function secretstream_xchacha20poly1305_init_pull($key, $header)
1271
+    {
1272
+        # crypto_core_hchacha20(state->k, in, k, NULL);
1273
+        $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
1274
+            ParagonIE_Sodium_Core32_Util::substr($header, 0, 16),
1275
+            $key
1276
+        );
1277
+        $state = new ParagonIE_Sodium_Core32_SecretStream_State(
1278
+            $subkey,
1279
+            ParagonIE_Sodium_Core32_Util::substr($header, 16)
1280
+        );
1281
+        $state->counterReset();
1282
+        # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
1283
+        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1284
+        # memset(state->_pad, 0, sizeof state->_pad);
1285
+        # return 0;
1286
+        return $state->toString();
1287
+    }
1288
+
1289
+    /**
1290
+     * @param string $state
1291
+     * @param string $msg
1292
+     * @param string $aad
1293
+     * @param int $tag
1294
+     * @return string
1295
+     * @throws SodiumException
1296
+     */
1297
+    public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
1298
+    {
1299
+        $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
1300
+        # crypto_onetimeauth_poly1305_state poly1305_state;
1301
+        # unsigned char                     block[64U];
1302
+        # unsigned char                     slen[8U];
1303
+        # unsigned char                    *c;
1304
+        # unsigned char                    *mac;
1305
+
1306
+        $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
1307
+        $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
1308
+
1309
+        if ((($msglen + 63) >> 6) > 0xfffffffe) {
1310
+            throw new SodiumException(
1311
+                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
1312
+            );
1313
+        }
1314
+
1315
+        # if (outlen_p != NULL) {
1316
+        #     *outlen_p = 0U;
1317
+        # }
1318
+        # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
1319
+        #     sodium_misuse();
1320
+        # }
1321
+
1322
+        # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
1323
+        # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
1324
+        # sodium_memzero(block, sizeof block);
1325
+        $auth = new ParagonIE_Sodium_Core32_Poly1305_State(
1326
+            ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
1327
+        );
1328
+
1329
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
1330
+        $auth->update($aad);
1331
+
1332
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
1333
+        #     (0x10 - adlen) & 0xf);
1334
+        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
1335
+
1336
+        # memset(block, 0, sizeof block);
1337
+        # block[0] = tag;
1338
+        # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
1339
+        #                                    state->nonce, 1U, state->k);
1340
+        $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
1341
+            ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63),
1342
+            $st->getCombinedNonce(),
1343
+            $st->getKey(),
1344
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
1345
+        );
1346
+
1347
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
1348
+        $auth->update($block);
1349
+
1350
+        # out[0] = block[0];
1351
+        $out = $block[0];
1352
+        # c = out + (sizeof tag);
1353
+        # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
1354
+        $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
1355
+            $msg,
1356
+            $st->getCombinedNonce(),
1357
+            $st->getKey(),
1358
+            ParagonIE_Sodium_Core32_Util::store64_le(2)
1359
+        );
1360
+
1361
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
1362
+        $auth->update($cipher);
1363
+
1364
+        $out .= $cipher;
1365
+        unset($cipher);
1366
+
1367
+        # crypto_onetimeauth_poly1305_update
1368
+        # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
1369
+        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
1370
+
1371
+        # STORE64_LE(slen, (uint64_t) adlen);
1372
+        $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
1373
+
1374
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1375
+        $auth->update($slen);
1376
+
1377
+        # STORE64_LE(slen, (sizeof block) + mlen);
1378
+        $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
1379
+
1380
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1381
+        $auth->update($slen);
1382
+
1383
+        # mac = c + mlen;
1384
+        # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
1385
+        $mac = $auth->finish();
1386
+        $out .= $mac;
1387
+
1388
+        # sodium_memzero(&poly1305_state, sizeof poly1305_state);
1389
+        unset($auth);
1390
+
1391
+
1392
+        # XOR_BUF(STATE_INONCE(state), mac,
1393
+        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1394
+        $st->xorNonce($mac);
1395
+
1396
+        # sodium_increment(STATE_COUNTER(state),
1397
+        #     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
1398
+        $st->incrementCounter();
1399
+        // Overwrite by reference:
1400
+        $state = $st->toString();
1401
+
1402
+        /** @var bool $rekey */
1403
+        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
1404
+        # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
1405
+        #     sodium_is_zero(STATE_COUNTER(state),
1406
+        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
1407
+        #     crypto_secretstream_xchacha20poly1305_rekey(state);
1408
+        # }
1409
+        if ($rekey || $st->needsRekey()) {
1410
+            // DO REKEY
1411
+            self::secretstream_xchacha20poly1305_rekey($state);
1412
+        }
1413
+        # if (outlen_p != NULL) {
1414
+        #     *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
1415
+        # }
1416
+        return $out;
1417
+    }
1418
+
1419
+    /**
1420
+     * @param string $state
1421
+     * @param string $cipher
1422
+     * @param string $aad
1423
+     * @return bool|array{0: string, 1: int}
1424
+     * @throws SodiumException
1425
+     */
1426
+    public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
1427
+    {
1428
+        $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
1429
+
1430
+        $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
1431
+        #     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
1432
+        $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
1433
+        $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
1434
+
1435
+        #     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
1436
+        #         sodium_misuse();
1437
+        #     }
1438
+        if ((($msglen + 63) >> 6) > 0xfffffffe) {
1439
+            throw new SodiumException(
1440
+                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
1441
+            );
1442
+        }
1443
+
1444
+        #     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
1445
+        #     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
1446
+        #     sodium_memzero(block, sizeof block);
1447
+        $auth = new ParagonIE_Sodium_Core32_Poly1305_State(
1448
+            ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
1449
+        );
1450
+
1451
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
1452
+        $auth->update($aad);
1453
+
1454
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
1455
+        #         (0x10 - adlen) & 0xf);
1456
+        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
1457
+
1458
+
1459
+        #     memset(block, 0, sizeof block);
1460
+        #     block[0] = in[0];
1461
+        #     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
1462
+        #                                        state->nonce, 1U, state->k);
1463
+        $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
1464
+            $cipher[0] . str_repeat("\0", 63),
1465
+            $st->getCombinedNonce(),
1466
+            $st->getKey(),
1467
+            ParagonIE_Sodium_Core32_Util::store64_le(1)
1468
+        );
1469
+        #     tag = block[0];
1470
+        #     block[0] = in[0];
1471
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
1472
+        $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
1473
+        $block[0] = $cipher[0];
1474
+        $auth->update($block);
1475
+
1476
+
1477
+        #     c = in + (sizeof tag);
1478
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
1479
+        $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen));
1480
+
1481
+        #     crypto_onetimeauth_poly1305_update
1482
+        #     (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
1483
+        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
1484
+
1485
+        #     STORE64_LE(slen, (uint64_t) adlen);
1486
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1487
+        $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
1488
+        $auth->update($slen);
1489
+
1490
+        #     STORE64_LE(slen, (sizeof block) + mlen);
1491
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1492
+        $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
1493
+        $auth->update($slen);
1494
+
1495
+        #     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
1496
+        #     sodium_memzero(&poly1305_state, sizeof poly1305_state);
1497
+        $mac = $auth->finish();
1498
+
1499
+        #     stored_mac = c + mlen;
1500
+        #     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
1501
+        #     sodium_memzero(mac, sizeof mac);
1502
+        #         return -1;
1503
+        #     }
1504
+
1505
+        $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16);
1506
+        if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
1507
+            return false;
1508
+        }
1509
+
1510
+        #     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
1511
+        $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
1512
+            ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen),
1513
+            $st->getCombinedNonce(),
1514
+            $st->getKey(),
1515
+            ParagonIE_Sodium_Core32_Util::store64_le(2)
1516
+        );
1517
+
1518
+        #     XOR_BUF(STATE_INONCE(state), mac,
1519
+        #         crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1520
+        $st->xorNonce($mac);
1521
+
1522
+        #     sodium_increment(STATE_COUNTER(state),
1523
+        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
1524
+        $st->incrementCounter();
1525
+
1526
+        #     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
1527
+        #         sodium_is_zero(STATE_COUNTER(state),
1528
+        #             crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
1529
+        #         crypto_secretstream_xchacha20poly1305_rekey(state);
1530
+        #     }
1531
+
1532
+        // Overwrite by reference:
1533
+        $state = $st->toString();
1534
+
1535
+        /** @var bool $rekey */
1536
+        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
1537
+        if ($rekey || $st->needsRekey()) {
1538
+            // DO REKEY
1539
+            self::secretstream_xchacha20poly1305_rekey($state);
1540
+        }
1541
+        return array($out, $tag);
1542
+    }
1543
+
1544
+    /**
1545
+     * @param string $state
1546
+     * @return void
1547
+     * @throws SodiumException
1548
+     */
1549
+    public static function secretstream_xchacha20poly1305_rekey(&$state)
1550
+    {
1551
+        $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
1552
+        # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
1553
+        # crypto_secretstream_xchacha20poly1305_INONCEBYTES];
1554
+        # size_t        i;
1555
+        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
1556
+        #     new_key_and_inonce[i] = state->k[i];
1557
+        # }
1558
+        $new_key_and_inonce = $st->getKey();
1559
+
1560
+        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
1561
+        #     new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
1562
+        #         STATE_INONCE(state)[i];
1563
+        # }
1564
+        $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8);
1565
+
1566
+        # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
1567
+        #                                 sizeof new_key_and_inonce,
1568
+        #                                 state->nonce, state->k);
1569
+
1570
+        $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
1571
+            $new_key_and_inonce,
1572
+            $st->getCombinedNonce(),
1573
+            $st->getKey(),
1574
+            ParagonIE_Sodium_Core32_Util::store64_le(0)
1575
+        ));
1576
+
1577
+        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
1578
+        #     state->k[i] = new_key_and_inonce[i];
1579
+        # }
1580
+        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
1581
+        #     STATE_INONCE(state)[i] =
1582
+        #          new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
1583
+        # }
1584
+        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
1585
+        $st->counterReset();
1586
+
1587
+        $state = $st->toString();
1588
+    }
1589
+
1590
+    /**
1591
+     * Detached Ed25519 signature.
1592
+     *
1593
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1594
+     *
1595
+     * @param string $message
1596
+     * @param string $sk
1597
+     * @return string
1598
+     * @throws SodiumException
1599
+     * @throws TypeError
1600
+     */
1601
+    public static function sign_detached($message, $sk)
1602
+    {
1603
+        return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk);
1604
+    }
1605
+
1606
+    /**
1607
+     * Attached Ed25519 signature. (Returns a signed message.)
1608
+     *
1609
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1610
+     *
1611
+     * @param string $message
1612
+     * @param string $sk
1613
+     * @return string
1614
+     * @throws SodiumException
1615
+     * @throws TypeError
1616
+     */
1617
+    public static function sign($message, $sk)
1618
+    {
1619
+        return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
1620
+    }
1621
+
1622
+    /**
1623
+     * Opens a signed message. If valid, returns the message.
1624
+     *
1625
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1626
+     *
1627
+     * @param string $signedMessage
1628
+     * @param string $pk
1629
+     * @return string
1630
+     * @throws SodiumException
1631
+     * @throws TypeError
1632
+     */
1633
+    public static function sign_open($signedMessage, $pk)
1634
+    {
1635
+        return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk);
1636
+    }
1637
+
1638
+    /**
1639
+     * Verify a detached signature of a given message and public key.
1640
+     *
1641
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1642
+     *
1643
+     * @param string $signature
1644
+     * @param string $message
1645
+     * @param string $pk
1646
+     * @return bool
1647
+     * @throws SodiumException
1648
+     * @throws TypeError
1649
+     */
1650
+    public static function sign_verify_detached($signature, $message, $pk)
1651
+    {
1652
+        return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk);
1653
+    }
1654
+}