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,1655 @@
1
+<?php
2
+
3
+if (class_exists('ParagonIE_Sodium_Crypto', 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_Crypto
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_Core_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_Core_Util::strlen($ad);
85
+
86
+        /** @var string $mac - Message authentication code */
87
+        $mac = ParagonIE_Sodium_Core_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_Core_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_Core_ChaCha20::stream(
98
+            32,
99
+            $nonce,
100
+            $key
101
+        );
102
+
103
+        /* Recalculate the Poly1305 authentication tag (MAC): */
104
+        $state = new ParagonIE_Sodium_Core_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_Core_Util::store64_le($adlen));
112
+        $state->update($ciphertext);
113
+        $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
114
+        $computed_mac = $state->finish();
115
+
116
+        /* Compare the given MAC with the recalculated MAC: */
117
+        if (!ParagonIE_Sodium_Core_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_Core_ChaCha20::streamXorIc(
123
+            $ciphertext,
124
+            $nonce,
125
+            $key,
126
+            ParagonIE_Sodium_Core_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_Core_Util::strlen($message);
151
+
152
+        /** @var int $adlen - Length of the associated data */
153
+        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
154
+
155
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
156
+        $block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
157
+            32,
158
+            $nonce,
159
+            $key
160
+        );
161
+        $state = new ParagonIE_Sodium_Core_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_Core_ChaCha20::streamXorIc(
170
+            $message,
171
+            $nonce,
172
+            $key,
173
+            ParagonIE_Sodium_Core_Util::store64_le(1)
174
+        );
175
+
176
+        $state->update($ad);
177
+        $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
178
+        $state->update($ciphertext);
179
+        $state->update(ParagonIE_Sodium_Core_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_Core_Util::strlen($ad);
204
+
205
+        /** @var int $len - Length of message (ciphertext + MAC) */
206
+        $len = ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStream(
213
+            32,
214
+            $nonce,
215
+            $key
216
+        );
217
+
218
+        /** @var string $mac - Message authentication code */
219
+        $mac = ParagonIE_Sodium_Core_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_Core_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_Core_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_Core_Util::store64_le($adlen));
244
+        $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
245
+        $computed_mac = $state->finish();
246
+
247
+        /* Compare the given MAC with the recalculated MAC: */
248
+        if (!ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStreamXorIc(
254
+            $ciphertext,
255
+            $nonce,
256
+            $key,
257
+            ParagonIE_Sodium_Core_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_Core_Util::strlen($message);
282
+
283
+        /** @var int $adlen - Length of the associated data */
284
+        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
285
+
286
+        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
287
+        $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
288
+            32,
289
+            $nonce,
290
+            $key
291
+        );
292
+        $state = new ParagonIE_Sodium_Core_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_Core_ChaCha20::ietfStreamXorIc(
301
+            $message,
302
+            $nonce,
303
+            $key,
304
+            ParagonIE_Sodium_Core_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_Core_Util::store64_le($adlen));
312
+        $state->update(ParagonIE_Sodium_Core_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_Core_HChaCha20::hChaCha20(
336
+            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
337
+            $key
338
+        );
339
+        $nonceLast = "\x00\x00\x00\x00" .
340
+            ParagonIE_Sodium_Core_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_Core_HChaCha20::hChaCha20(
365
+            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
366
+            $key
367
+        );
368
+        $nonceLast = "\x00\x00\x00\x00" .
369
+            ParagonIE_Sodium_Core_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_Core_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_Core_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
+        $c = self::secretbox(
428
+            $plaintext,
429
+            $nonce,
430
+            self::box_beforenm(
431
+                self::box_secretkey($keypair),
432
+                self::box_publickey($keypair)
433
+            )
434
+        );
435
+        return $c;
436
+    }
437
+
438
+    /**
439
+     * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
440
+     *
441
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
442
+     *
443
+     * @param string $message
444
+     * @param string $publicKey
445
+     * @return string
446
+     * @throws SodiumException
447
+     * @throws TypeError
448
+     */
449
+    public static function box_seal($message, $publicKey)
450
+    {
451
+        /** @var string $ephemeralKeypair */
452
+        $ephemeralKeypair = self::box_keypair();
453
+
454
+        /** @var string $ephemeralSK */
455
+        $ephemeralSK = self::box_secretkey($ephemeralKeypair);
456
+
457
+        /** @var string $ephemeralPK */
458
+        $ephemeralPK = self::box_publickey($ephemeralKeypair);
459
+
460
+        /** @var string $nonce */
461
+        $nonce = self::generichash(
462
+            $ephemeralPK . $publicKey,
463
+            '',
464
+            24
465
+        );
466
+
467
+        /** @var string $keypair - The combined keypair used in crypto_box() */
468
+        $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
469
+
470
+        /** @var string $ciphertext Ciphertext + MAC from crypto_box */
471
+        $ciphertext = self::box($message, $nonce, $keypair);
472
+        try {
473
+            ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
474
+            ParagonIE_Sodium_Compat::memzero($ephemeralSK);
475
+            ParagonIE_Sodium_Compat::memzero($nonce);
476
+        } catch (SodiumException $ex) {
477
+            $ephemeralKeypair = null;
478
+            $ephemeralSK = null;
479
+            $nonce = null;
480
+        }
481
+        return $ephemeralPK . $ciphertext;
482
+    }
483
+
484
+    /**
485
+     * Opens a message encrypted via box_seal().
486
+     *
487
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
488
+     *
489
+     * @param string $message
490
+     * @param string $keypair
491
+     * @return string
492
+     * @throws SodiumException
493
+     * @throws TypeError
494
+     */
495
+    public static function box_seal_open($message, $keypair)
496
+    {
497
+        /** @var string $ephemeralPK */
498
+        $ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32);
499
+
500
+        /** @var string $ciphertext (ciphertext + MAC) */
501
+        $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32);
502
+
503
+        /** @var string $secretKey */
504
+        $secretKey = self::box_secretkey($keypair);
505
+
506
+        /** @var string $publicKey */
507
+        $publicKey = self::box_publickey($keypair);
508
+
509
+        /** @var string $nonce */
510
+        $nonce = self::generichash(
511
+            $ephemeralPK . $publicKey,
512
+            '',
513
+            24
514
+        );
515
+
516
+        /** @var string $keypair */
517
+        $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
518
+
519
+        /** @var string $m */
520
+        $m = self::box_open($ciphertext, $nonce, $keypair);
521
+        try {
522
+            ParagonIE_Sodium_Compat::memzero($secretKey);
523
+            ParagonIE_Sodium_Compat::memzero($ephemeralPK);
524
+            ParagonIE_Sodium_Compat::memzero($nonce);
525
+        } catch (SodiumException $ex) {
526
+            $secretKey = null;
527
+            $ephemeralPK = null;
528
+            $nonce = null;
529
+        }
530
+        return $m;
531
+    }
532
+
533
+    /**
534
+     * Used by crypto_box() to get the crypto_secretbox() key.
535
+     *
536
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
537
+     *
538
+     * @param string $sk
539
+     * @param string $pk
540
+     * @return string
541
+     * @throws SodiumException
542
+     * @throws TypeError
543
+     */
544
+    public static function box_beforenm($sk, $pk)
545
+    {
546
+        return ParagonIE_Sodium_Core_HSalsa20::hsalsa20(
547
+            str_repeat("\x00", 16),
548
+            self::scalarmult($sk, $pk)
549
+        );
550
+    }
551
+
552
+    /**
553
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
554
+     *
555
+     * @return string
556
+     * @throws Exception
557
+     * @throws SodiumException
558
+     * @throws TypeError
559
+     */
560
+    public static function box_keypair()
561
+    {
562
+        $sKey = random_bytes(32);
563
+        $pKey = self::scalarmult_base($sKey);
564
+        return $sKey . $pKey;
565
+    }
566
+
567
+    /**
568
+     * @param string $seed
569
+     * @return string
570
+     * @throws SodiumException
571
+     * @throws TypeError
572
+     */
573
+    public static function box_seed_keypair($seed)
574
+    {
575
+        $sKey = ParagonIE_Sodium_Core_Util::substr(
576
+            hash('sha512', $seed, true),
577
+            0,
578
+            32
579
+        );
580
+        $pKey = self::scalarmult_base($sKey);
581
+        return $sKey . $pKey;
582
+    }
583
+
584
+    /**
585
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
586
+     *
587
+     * @param string $sKey
588
+     * @param string $pKey
589
+     * @return string
590
+     * @throws TypeError
591
+     */
592
+    public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
593
+    {
594
+        return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) .
595
+            ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32);
596
+    }
597
+
598
+    /**
599
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
600
+     *
601
+     * @param string $keypair
602
+     * @return string
603
+     * @throws RangeException
604
+     * @throws TypeError
605
+     */
606
+    public static function box_secretkey($keypair)
607
+    {
608
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) {
609
+            throw new RangeException(
610
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
611
+            );
612
+        }
613
+        return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32);
614
+    }
615
+
616
+    /**
617
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
618
+     *
619
+     * @param string $keypair
620
+     * @return string
621
+     * @throws RangeException
622
+     * @throws TypeError
623
+     */
624
+    public static function box_publickey($keypair)
625
+    {
626
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
627
+            throw new RangeException(
628
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
629
+            );
630
+        }
631
+        return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32);
632
+    }
633
+
634
+    /**
635
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
636
+     *
637
+     * @param string $sKey
638
+     * @return string
639
+     * @throws RangeException
640
+     * @throws SodiumException
641
+     * @throws TypeError
642
+     */
643
+    public static function box_publickey_from_secretkey($sKey)
644
+    {
645
+        if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
646
+            throw new RangeException(
647
+                'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
648
+            );
649
+        }
650
+        return self::scalarmult_base($sKey);
651
+    }
652
+
653
+    /**
654
+     * Decrypt a message encrypted with box().
655
+     *
656
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
657
+     *
658
+     * @param string $ciphertext
659
+     * @param string $nonce
660
+     * @param string $keypair
661
+     * @return string
662
+     * @throws SodiumException
663
+     * @throws TypeError
664
+     */
665
+    public static function box_open($ciphertext, $nonce, $keypair)
666
+    {
667
+        return self::secretbox_open(
668
+            $ciphertext,
669
+            $nonce,
670
+            self::box_beforenm(
671
+                self::box_secretkey($keypair),
672
+                self::box_publickey($keypair)
673
+            )
674
+        );
675
+    }
676
+
677
+    /**
678
+     * Calculate a BLAKE2b hash.
679
+     *
680
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
681
+     *
682
+     * @param string $message
683
+     * @param string|null $key
684
+     * @param int $outlen
685
+     * @return string
686
+     * @throws RangeException
687
+     * @throws SodiumException
688
+     * @throws TypeError
689
+     */
690
+    public static function generichash($message, $key = '', $outlen = 32)
691
+    {
692
+        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
693
+        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
694
+
695
+        $k = null;
696
+        if (!empty($key)) {
697
+            /** @var SplFixedArray $k */
698
+            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
699
+            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
700
+                throw new RangeException('Invalid key size');
701
+            }
702
+        }
703
+
704
+        /** @var SplFixedArray $in */
705
+        $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
706
+
707
+        /** @var SplFixedArray $ctx */
708
+        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen);
709
+        ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count());
710
+
711
+        /** @var SplFixedArray $out */
712
+        $out = new SplFixedArray($outlen);
713
+        $out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out);
714
+
715
+        /** @var array<int, int> */
716
+        $outArray = $out->toArray();
717
+        return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
718
+    }
719
+
720
+    /**
721
+     * Finalize a BLAKE2b hashing context, returning the hash.
722
+     *
723
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
724
+     *
725
+     * @param string $ctx
726
+     * @param int $outlen
727
+     * @return string
728
+     * @throws SodiumException
729
+     * @throws TypeError
730
+     */
731
+    public static function generichash_final($ctx, $outlen = 32)
732
+    {
733
+        if (!is_string($ctx)) {
734
+            throw new TypeError('Context must be a string');
735
+        }
736
+        $out = new SplFixedArray($outlen);
737
+
738
+        /** @var SplFixedArray $context */
739
+        $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
740
+
741
+        /** @var SplFixedArray $out */
742
+        $out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out);
743
+
744
+        /** @var array<int, int> */
745
+        $outArray = $out->toArray();
746
+        return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
747
+    }
748
+
749
+    /**
750
+     * Initialize a hashing context for BLAKE2b.
751
+     *
752
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
753
+     *
754
+     * @param string $key
755
+     * @param int $outputLength
756
+     * @return string
757
+     * @throws RangeException
758
+     * @throws SodiumException
759
+     * @throws TypeError
760
+     */
761
+    public static function generichash_init($key = '', $outputLength = 32)
762
+    {
763
+        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
764
+        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
765
+
766
+        $k = null;
767
+        if (!empty($key)) {
768
+            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
769
+            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
770
+                throw new RangeException('Invalid key size');
771
+            }
772
+        }
773
+
774
+        /** @var SplFixedArray $ctx */
775
+        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength);
776
+
777
+        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
778
+    }
779
+
780
+    /**
781
+     * Initialize a hashing context for BLAKE2b.
782
+     *
783
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
784
+     *
785
+     * @param string $key
786
+     * @param int $outputLength
787
+     * @param string $salt
788
+     * @param string $personal
789
+     * @return string
790
+     * @throws RangeException
791
+     * @throws SodiumException
792
+     * @throws TypeError
793
+     */
794
+    public static function generichash_init_salt_personal(
795
+        $key = '',
796
+        $outputLength = 32,
797
+        $salt = '',
798
+        $personal = ''
799
+    ) {
800
+        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
801
+        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
802
+
803
+        $k = null;
804
+        if (!empty($key)) {
805
+            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
806
+            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
807
+                throw new RangeException('Invalid key size');
808
+            }
809
+        }
810
+        if (!empty($salt)) {
811
+            $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
812
+        } else {
813
+            $s = null;
814
+        }
815
+        if (!empty($salt)) {
816
+            $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
817
+        } else {
818
+            $p = null;
819
+        }
820
+
821
+        /** @var SplFixedArray $ctx */
822
+        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p);
823
+
824
+        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
825
+    }
826
+
827
+    /**
828
+     * Update a hashing context for BLAKE2b with $message
829
+     *
830
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
831
+     *
832
+     * @param string $ctx
833
+     * @param string $message
834
+     * @return string
835
+     * @throws SodiumException
836
+     * @throws TypeError
837
+     */
838
+    public static function generichash_update($ctx, $message)
839
+    {
840
+        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
841
+        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
842
+
843
+        /** @var SplFixedArray $context */
844
+        $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
845
+
846
+        /** @var SplFixedArray $in */
847
+        $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
848
+
849
+        ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count());
850
+
851
+        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context);
852
+    }
853
+
854
+    /**
855
+     * Libsodium's crypto_kx().
856
+     *
857
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
858
+     *
859
+     * @param string $my_sk
860
+     * @param string $their_pk
861
+     * @param string $client_pk
862
+     * @param string $server_pk
863
+     * @return string
864
+     * @throws SodiumException
865
+     * @throws TypeError
866
+     */
867
+    public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
868
+    {
869
+        return ParagonIE_Sodium_Compat::crypto_generichash(
870
+            ParagonIE_Sodium_Compat::crypto_scalarmult($my_sk, $their_pk) .
871
+            $client_pk .
872
+            $server_pk
873
+        );
874
+    }
875
+
876
+    /**
877
+     * ECDH over Curve25519
878
+     *
879
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
880
+     *
881
+     * @param string $sKey
882
+     * @param string $pKey
883
+     * @return string
884
+     *
885
+     * @throws SodiumException
886
+     * @throws TypeError
887
+     */
888
+    public static function scalarmult($sKey, $pKey)
889
+    {
890
+        $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
891
+        self::scalarmult_throw_if_zero($q);
892
+        return $q;
893
+    }
894
+
895
+    /**
896
+     * ECDH over Curve25519, using the basepoint.
897
+     * Used to get a secret key from a public key.
898
+     *
899
+     * @param string $secret
900
+     * @return string
901
+     *
902
+     * @throws SodiumException
903
+     * @throws TypeError
904
+     */
905
+    public static function scalarmult_base($secret)
906
+    {
907
+        $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
908
+        self::scalarmult_throw_if_zero($q);
909
+        return $q;
910
+    }
911
+
912
+    /**
913
+     * This throws an Error if a zero public key was passed to the function.
914
+     *
915
+     * @param string $q
916
+     * @return void
917
+     * @throws SodiumException
918
+     * @throws TypeError
919
+     */
920
+    protected static function scalarmult_throw_if_zero($q)
921
+    {
922
+        $d = 0;
923
+        for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
924
+            $d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]);
925
+        }
926
+
927
+        /* branch-free variant of === 0 */
928
+        if (-(1 & (($d - 1) >> 8))) {
929
+            throw new SodiumException('Zero public key is not allowed');
930
+        }
931
+    }
932
+
933
+    /**
934
+     * XSalsa20-Poly1305 authenticated symmetric-key encryption.
935
+     *
936
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
937
+     *
938
+     * @param string $plaintext
939
+     * @param string $nonce
940
+     * @param string $key
941
+     * @return string
942
+     * @throws SodiumException
943
+     * @throws TypeError
944
+     */
945
+    public static function secretbox($plaintext, $nonce, $key)
946
+    {
947
+        /** @var string $subkey */
948
+        $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
949
+
950
+        /** @var string $block0 */
951
+        $block0 = str_repeat("\x00", 32);
952
+
953
+        /** @var int $mlen - Length of the plaintext message */
954
+        $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
955
+        $mlen0 = $mlen;
956
+        if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
957
+            $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
958
+        }
959
+        $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
960
+
961
+        /** @var string $block0 */
962
+        $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
963
+            $block0,
964
+            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
965
+            $subkey
966
+        );
967
+
968
+        /** @var string $c */
969
+        $c = ParagonIE_Sodium_Core_Util::substr(
970
+            $block0,
971
+            self::secretbox_xsalsa20poly1305_ZEROBYTES
972
+        );
973
+        if ($mlen > $mlen0) {
974
+            $c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
975
+                ParagonIE_Sodium_Core_Util::substr(
976
+                    $plaintext,
977
+                    self::secretbox_xsalsa20poly1305_ZEROBYTES
978
+                ),
979
+                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
980
+                1,
981
+                $subkey
982
+            );
983
+        }
984
+        $state = new ParagonIE_Sodium_Core_Poly1305_State(
985
+            ParagonIE_Sodium_Core_Util::substr(
986
+                $block0,
987
+                0,
988
+                self::onetimeauth_poly1305_KEYBYTES
989
+            )
990
+        );
991
+        try {
992
+            ParagonIE_Sodium_Compat::memzero($block0);
993
+            ParagonIE_Sodium_Compat::memzero($subkey);
994
+        } catch (SodiumException $ex) {
995
+            $block0 = null;
996
+            $subkey = null;
997
+        }
998
+
999
+        $state->update($c);
1000
+
1001
+        /** @var string $c - MAC || ciphertext */
1002
+        $c = $state->finish() . $c;
1003
+        unset($state);
1004
+
1005
+        return $c;
1006
+    }
1007
+
1008
+    /**
1009
+     * Decrypt a ciphertext generated via secretbox().
1010
+     *
1011
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1012
+     *
1013
+     * @param string $ciphertext
1014
+     * @param string $nonce
1015
+     * @param string $key
1016
+     * @return string
1017
+     * @throws SodiumException
1018
+     * @throws TypeError
1019
+     */
1020
+    public static function secretbox_open($ciphertext, $nonce, $key)
1021
+    {
1022
+        /** @var string $mac */
1023
+        $mac = ParagonIE_Sodium_Core_Util::substr(
1024
+            $ciphertext,
1025
+            0,
1026
+            self::secretbox_xsalsa20poly1305_MACBYTES
1027
+        );
1028
+
1029
+        /** @var string $c */
1030
+        $c = ParagonIE_Sodium_Core_Util::substr(
1031
+            $ciphertext,
1032
+            self::secretbox_xsalsa20poly1305_MACBYTES
1033
+        );
1034
+
1035
+        /** @var int $clen */
1036
+        $clen = ParagonIE_Sodium_Core_Util::strlen($c);
1037
+
1038
+        /** @var string $subkey */
1039
+        $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
1040
+
1041
+        /** @var string $block0 */
1042
+        $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
1043
+            64,
1044
+            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1045
+            $subkey
1046
+        );
1047
+        $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
1048
+            $mac,
1049
+            $c,
1050
+            ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
1051
+        );
1052
+        if (!$verified) {
1053
+            try {
1054
+                ParagonIE_Sodium_Compat::memzero($subkey);
1055
+            } catch (SodiumException $ex) {
1056
+                $subkey = null;
1057
+            }
1058
+            throw new SodiumException('Invalid MAC');
1059
+        }
1060
+
1061
+        /** @var string $m - Decrypted message */
1062
+        $m = ParagonIE_Sodium_Core_Util::xorStrings(
1063
+            ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
1064
+            ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
1065
+        );
1066
+        if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
1067
+            // We had more than 1 block, so let's continue to decrypt the rest.
1068
+            $m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
1069
+                ParagonIE_Sodium_Core_Util::substr(
1070
+                    $c,
1071
+                    self::secretbox_xsalsa20poly1305_ZEROBYTES
1072
+                ),
1073
+                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1074
+                1,
1075
+                (string) $subkey
1076
+            );
1077
+        }
1078
+        return $m;
1079
+    }
1080
+
1081
+    /**
1082
+     * XChaCha20-Poly1305 authenticated symmetric-key encryption.
1083
+     *
1084
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1085
+     *
1086
+     * @param string $plaintext
1087
+     * @param string $nonce
1088
+     * @param string $key
1089
+     * @return string
1090
+     * @throws SodiumException
1091
+     * @throws TypeError
1092
+     */
1093
+    public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
1094
+    {
1095
+        /** @var string $subkey */
1096
+        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
1097
+            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
1098
+            $key
1099
+        );
1100
+        $nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
1101
+
1102
+        /** @var string $block0 */
1103
+        $block0 = str_repeat("\x00", 32);
1104
+
1105
+        /** @var int $mlen - Length of the plaintext message */
1106
+        $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
1107
+        $mlen0 = $mlen;
1108
+        if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
1109
+            $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
1110
+        }
1111
+        $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
1112
+
1113
+        /** @var string $block0 */
1114
+        $block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1115
+            $block0,
1116
+            $nonceLast,
1117
+            $subkey
1118
+        );
1119
+
1120
+        /** @var string $c */
1121
+        $c = ParagonIE_Sodium_Core_Util::substr(
1122
+            $block0,
1123
+            self::secretbox_xchacha20poly1305_ZEROBYTES
1124
+        );
1125
+        if ($mlen > $mlen0) {
1126
+            $c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1127
+                ParagonIE_Sodium_Core_Util::substr(
1128
+                    $plaintext,
1129
+                    self::secretbox_xchacha20poly1305_ZEROBYTES
1130
+                ),
1131
+                $nonceLast,
1132
+                $subkey,
1133
+                ParagonIE_Sodium_Core_Util::store64_le(1)
1134
+            );
1135
+        }
1136
+        $state = new ParagonIE_Sodium_Core_Poly1305_State(
1137
+            ParagonIE_Sodium_Core_Util::substr(
1138
+                $block0,
1139
+                0,
1140
+                self::onetimeauth_poly1305_KEYBYTES
1141
+            )
1142
+        );
1143
+        try {
1144
+            ParagonIE_Sodium_Compat::memzero($block0);
1145
+            ParagonIE_Sodium_Compat::memzero($subkey);
1146
+        } catch (SodiumException $ex) {
1147
+            $block0 = null;
1148
+            $subkey = null;
1149
+        }
1150
+
1151
+        $state->update($c);
1152
+
1153
+        /** @var string $c - MAC || ciphertext */
1154
+        $c = $state->finish() . $c;
1155
+        unset($state);
1156
+
1157
+        return $c;
1158
+    }
1159
+
1160
+    /**
1161
+     * Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
1162
+     *
1163
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1164
+     *
1165
+     * @param string $ciphertext
1166
+     * @param string $nonce
1167
+     * @param string $key
1168
+     * @return string
1169
+     * @throws SodiumException
1170
+     * @throws TypeError
1171
+     */
1172
+    public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
1173
+    {
1174
+        /** @var string $mac */
1175
+        $mac = ParagonIE_Sodium_Core_Util::substr(
1176
+            $ciphertext,
1177
+            0,
1178
+            self::secretbox_xchacha20poly1305_MACBYTES
1179
+        );
1180
+
1181
+        /** @var string $c */
1182
+        $c = ParagonIE_Sodium_Core_Util::substr(
1183
+            $ciphertext,
1184
+            self::secretbox_xchacha20poly1305_MACBYTES
1185
+        );
1186
+
1187
+        /** @var int $clen */
1188
+        $clen = ParagonIE_Sodium_Core_Util::strlen($c);
1189
+
1190
+        /** @var string $subkey */
1191
+        $subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key);
1192
+
1193
+        /** @var string $block0 */
1194
+        $block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
1195
+            64,
1196
+            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1197
+            $subkey
1198
+        );
1199
+        $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
1200
+            $mac,
1201
+            $c,
1202
+            ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
1203
+        );
1204
+
1205
+        if (!$verified) {
1206
+            try {
1207
+                ParagonIE_Sodium_Compat::memzero($subkey);
1208
+            } catch (SodiumException $ex) {
1209
+                $subkey = null;
1210
+            }
1211
+            throw new SodiumException('Invalid MAC');
1212
+        }
1213
+
1214
+        /** @var string $m - Decrypted message */
1215
+        $m = ParagonIE_Sodium_Core_Util::xorStrings(
1216
+            ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
1217
+            ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
1218
+        );
1219
+
1220
+        if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
1221
+            // We had more than 1 block, so let's continue to decrypt the rest.
1222
+            $m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1223
+                ParagonIE_Sodium_Core_Util::substr(
1224
+                    $c,
1225
+                    self::secretbox_xchacha20poly1305_ZEROBYTES
1226
+                ),
1227
+                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1228
+                (string) $subkey,
1229
+                ParagonIE_Sodium_Core_Util::store64_le(1)
1230
+            );
1231
+        }
1232
+        return $m;
1233
+    }
1234
+
1235
+    /**
1236
+     * @param string $key
1237
+     * @return array<int, string> Returns a state and a header.
1238
+     * @throws Exception
1239
+     * @throws SodiumException
1240
+     */
1241
+    public static function secretstream_xchacha20poly1305_init_push($key)
1242
+    {
1243
+        # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
1244
+        $out = random_bytes(24);
1245
+
1246
+        # crypto_core_hchacha20(state->k, out, k, NULL);
1247
+        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
1248
+        $state = new ParagonIE_Sodium_Core_SecretStream_State(
1249
+            $subkey,
1250
+            ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4)
1251
+        );
1252
+
1253
+        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
1254
+        $state->counterReset();
1255
+
1256
+        # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
1257
+        #        crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1258
+        # memset(state->_pad, 0, sizeof state->_pad);
1259
+        return array(
1260
+            $state->toString(),
1261
+            $out
1262
+        );
1263
+    }
1264
+
1265
+    /**
1266
+     * @param string $key
1267
+     * @param string $header
1268
+     * @return string Returns a state.
1269
+     * @throws Exception
1270
+     */
1271
+    public static function secretstream_xchacha20poly1305_init_pull($key, $header)
1272
+    {
1273
+        # crypto_core_hchacha20(state->k, in, k, NULL);
1274
+        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
1275
+            ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
1276
+            $key
1277
+        );
1278
+        $state = new ParagonIE_Sodium_Core_SecretStream_State(
1279
+            $subkey,
1280
+            ParagonIE_Sodium_Core_Util::substr($header, 16)
1281
+        );
1282
+        $state->counterReset();
1283
+        # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
1284
+        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1285
+        # memset(state->_pad, 0, sizeof state->_pad);
1286
+        # return 0;
1287
+        return $state->toString();
1288
+    }
1289
+
1290
+    /**
1291
+     * @param string $state
1292
+     * @param string $msg
1293
+     * @param string $aad
1294
+     * @param int $tag
1295
+     * @return string
1296
+     * @throws SodiumException
1297
+     */
1298
+    public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
1299
+    {
1300
+        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
1301
+        # crypto_onetimeauth_poly1305_state poly1305_state;
1302
+        # unsigned char                     block[64U];
1303
+        # unsigned char                     slen[8U];
1304
+        # unsigned char                    *c;
1305
+        # unsigned char                    *mac;
1306
+
1307
+        $msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
1308
+        $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
1309
+
1310
+        if ((($msglen + 63) >> 6) > 0xfffffffe) {
1311
+            throw new SodiumException(
1312
+                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
1313
+            );
1314
+        }
1315
+
1316
+        # if (outlen_p != NULL) {
1317
+        #     *outlen_p = 0U;
1318
+        # }
1319
+        # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
1320
+        #     sodium_misuse();
1321
+        # }
1322
+
1323
+        # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
1324
+        # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
1325
+        # sodium_memzero(block, sizeof block);
1326
+        $auth = new ParagonIE_Sodium_Core_Poly1305_State(
1327
+            ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
1328
+        );
1329
+
1330
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
1331
+        $auth->update($aad);
1332
+
1333
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
1334
+        #     (0x10 - adlen) & 0xf);
1335
+        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
1336
+
1337
+        # memset(block, 0, sizeof block);
1338
+        # block[0] = tag;
1339
+        # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
1340
+        #                                    state->nonce, 1U, state->k);
1341
+        $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
1342
+            ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63),
1343
+            $st->getCombinedNonce(),
1344
+            $st->getKey(),
1345
+            ParagonIE_Sodium_Core_Util::store64_le(1)
1346
+        );
1347
+
1348
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
1349
+        $auth->update($block);
1350
+
1351
+        # out[0] = block[0];
1352
+        $out = $block[0];
1353
+        # c = out + (sizeof tag);
1354
+        # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
1355
+        $cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
1356
+            $msg,
1357
+            $st->getCombinedNonce(),
1358
+            $st->getKey(),
1359
+            ParagonIE_Sodium_Core_Util::store64_le(2)
1360
+        );
1361
+
1362
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
1363
+        $auth->update($cipher);
1364
+
1365
+        $out .= $cipher;
1366
+        unset($cipher);
1367
+
1368
+        # crypto_onetimeauth_poly1305_update
1369
+        # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
1370
+        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
1371
+
1372
+        # STORE64_LE(slen, (uint64_t) adlen);
1373
+        $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
1374
+
1375
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1376
+        $auth->update($slen);
1377
+
1378
+        # STORE64_LE(slen, (sizeof block) + mlen);
1379
+        $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
1380
+
1381
+        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1382
+        $auth->update($slen);
1383
+
1384
+        # mac = c + mlen;
1385
+        # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
1386
+        $mac = $auth->finish();
1387
+        $out .= $mac;
1388
+
1389
+        # sodium_memzero(&poly1305_state, sizeof poly1305_state);
1390
+        unset($auth);
1391
+
1392
+
1393
+        # XOR_BUF(STATE_INONCE(state), mac,
1394
+        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1395
+        $st->xorNonce($mac);
1396
+
1397
+        # sodium_increment(STATE_COUNTER(state),
1398
+        #     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
1399
+        $st->incrementCounter();
1400
+        // Overwrite by reference:
1401
+        $state = $st->toString();
1402
+
1403
+        /** @var bool $rekey */
1404
+        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
1405
+        # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
1406
+        #     sodium_is_zero(STATE_COUNTER(state),
1407
+        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
1408
+        #     crypto_secretstream_xchacha20poly1305_rekey(state);
1409
+        # }
1410
+        if ($rekey || $st->needsRekey()) {
1411
+            // DO REKEY
1412
+            self::secretstream_xchacha20poly1305_rekey($state);
1413
+        }
1414
+        # if (outlen_p != NULL) {
1415
+        #     *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
1416
+        # }
1417
+        return $out;
1418
+    }
1419
+
1420
+    /**
1421
+     * @param string $state
1422
+     * @param string $cipher
1423
+     * @param string $aad
1424
+     * @return bool|array{0: string, 1: int}
1425
+     * @throws SodiumException
1426
+     */
1427
+    public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
1428
+    {
1429
+        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
1430
+
1431
+        $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
1432
+        #     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
1433
+        $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
1434
+        $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
1435
+
1436
+        #     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
1437
+        #         sodium_misuse();
1438
+        #     }
1439
+        if ((($msglen + 63) >> 6) > 0xfffffffe) {
1440
+            throw new SodiumException(
1441
+                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
1442
+            );
1443
+        }
1444
+
1445
+        #     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
1446
+        #     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
1447
+        #     sodium_memzero(block, sizeof block);
1448
+        $auth = new ParagonIE_Sodium_Core_Poly1305_State(
1449
+            ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
1450
+        );
1451
+
1452
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
1453
+        $auth->update($aad);
1454
+
1455
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
1456
+        #         (0x10 - adlen) & 0xf);
1457
+        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
1458
+
1459
+
1460
+        #     memset(block, 0, sizeof block);
1461
+        #     block[0] = in[0];
1462
+        #     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
1463
+        #                                        state->nonce, 1U, state->k);
1464
+        $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
1465
+            $cipher[0] . str_repeat("\0", 63),
1466
+            $st->getCombinedNonce(),
1467
+            $st->getKey(),
1468
+            ParagonIE_Sodium_Core_Util::store64_le(1)
1469
+        );
1470
+        #     tag = block[0];
1471
+        #     block[0] = in[0];
1472
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
1473
+        $tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
1474
+        $block[0] = $cipher[0];
1475
+        $auth->update($block);
1476
+
1477
+
1478
+        #     c = in + (sizeof tag);
1479
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
1480
+        $auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen));
1481
+
1482
+        #     crypto_onetimeauth_poly1305_update
1483
+        #     (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
1484
+        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
1485
+
1486
+        #     STORE64_LE(slen, (uint64_t) adlen);
1487
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1488
+        $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
1489
+        $auth->update($slen);
1490
+
1491
+        #     STORE64_LE(slen, (sizeof block) + mlen);
1492
+        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
1493
+        $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
1494
+        $auth->update($slen);
1495
+
1496
+        #     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
1497
+        #     sodium_memzero(&poly1305_state, sizeof poly1305_state);
1498
+        $mac = $auth->finish();
1499
+
1500
+        #     stored_mac = c + mlen;
1501
+        #     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
1502
+        #     sodium_memzero(mac, sizeof mac);
1503
+        #         return -1;
1504
+        #     }
1505
+
1506
+        $stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16);
1507
+        if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
1508
+            return false;
1509
+        }
1510
+
1511
+        #     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
1512
+        $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
1513
+            ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
1514
+            $st->getCombinedNonce(),
1515
+            $st->getKey(),
1516
+            ParagonIE_Sodium_Core_Util::store64_le(2)
1517
+        );
1518
+
1519
+        #     XOR_BUF(STATE_INONCE(state), mac,
1520
+        #         crypto_secretstream_xchacha20poly1305_INONCEBYTES);
1521
+        $st->xorNonce($mac);
1522
+
1523
+        #     sodium_increment(STATE_COUNTER(state),
1524
+        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
1525
+        $st->incrementCounter();
1526
+
1527
+        #     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
1528
+        #         sodium_is_zero(STATE_COUNTER(state),
1529
+        #             crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
1530
+        #         crypto_secretstream_xchacha20poly1305_rekey(state);
1531
+        #     }
1532
+
1533
+        // Overwrite by reference:
1534
+        $state = $st->toString();
1535
+
1536
+        /** @var bool $rekey */
1537
+        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
1538
+        if ($rekey || $st->needsRekey()) {
1539
+            // DO REKEY
1540
+            self::secretstream_xchacha20poly1305_rekey($state);
1541
+        }
1542
+        return array($out, $tag);
1543
+    }
1544
+
1545
+    /**
1546
+     * @param string $state
1547
+     * @return void
1548
+     * @throws SodiumException
1549
+     */
1550
+    public static function secretstream_xchacha20poly1305_rekey(&$state)
1551
+    {
1552
+        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
1553
+        # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
1554
+        # crypto_secretstream_xchacha20poly1305_INONCEBYTES];
1555
+        # size_t        i;
1556
+        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
1557
+        #     new_key_and_inonce[i] = state->k[i];
1558
+        # }
1559
+        $new_key_and_inonce = $st->getKey();
1560
+
1561
+        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
1562
+        #     new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
1563
+        #         STATE_INONCE(state)[i];
1564
+        # }
1565
+        $new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
1566
+
1567
+        # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
1568
+        #                                 sizeof new_key_and_inonce,
1569
+        #                                 state->nonce, state->k);
1570
+
1571
+        $st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
1572
+            $new_key_and_inonce,
1573
+            $st->getCombinedNonce(),
1574
+            $st->getKey(),
1575
+            ParagonIE_Sodium_Core_Util::store64_le(0)
1576
+        ));
1577
+
1578
+        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
1579
+        #     state->k[i] = new_key_and_inonce[i];
1580
+        # }
1581
+        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
1582
+        #     STATE_INONCE(state)[i] =
1583
+        #          new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
1584
+        # }
1585
+        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
1586
+        $st->counterReset();
1587
+
1588
+        $state = $st->toString();
1589
+    }
1590
+
1591
+    /**
1592
+     * Detached Ed25519 signature.
1593
+     *
1594
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1595
+     *
1596
+     * @param string $message
1597
+     * @param string $sk
1598
+     * @return string
1599
+     * @throws SodiumException
1600
+     * @throws TypeError
1601
+     */
1602
+    public static function sign_detached($message, $sk)
1603
+    {
1604
+        return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk);
1605
+    }
1606
+
1607
+    /**
1608
+     * Attached Ed25519 signature. (Returns a signed message.)
1609
+     *
1610
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1611
+     *
1612
+     * @param string $message
1613
+     * @param string $sk
1614
+     * @return string
1615
+     * @throws SodiumException
1616
+     * @throws TypeError
1617
+     */
1618
+    public static function sign($message, $sk)
1619
+    {
1620
+        return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk);
1621
+    }
1622
+
1623
+    /**
1624
+     * Opens a signed message. If valid, returns the message.
1625
+     *
1626
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1627
+     *
1628
+     * @param string $signedMessage
1629
+     * @param string $pk
1630
+     * @return string
1631
+     * @throws SodiumException
1632
+     * @throws TypeError
1633
+     */
1634
+    public static function sign_open($signedMessage, $pk)
1635
+    {
1636
+        return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk);
1637
+    }
1638
+
1639
+    /**
1640
+     * Verify a detached signature of a given message and public key.
1641
+     *
1642
+     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1643
+     *
1644
+     * @param string $signature
1645
+     * @param string $message
1646
+     * @param string $pk
1647
+     * @return bool
1648
+     * @throws SodiumException
1649
+     * @throws TypeError
1650
+     */
1651
+    public static function sign_verify_detached($signature, $message, $pk)
1652
+    {
1653
+        return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk);
1654
+    }
1655
+}