Test Failed
Push — develop ( 266ee2...ce70fb )
by J.D.
05:51
created

ParagonIE_Sodium_Compat   D

Complexity

Total Complexity 299

Size/Duplication

Total Lines 2256
Duplicated Lines 44.5 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
dl 1004
loc 2256
rs 4.4102
c 0
b 0
f 0
wmc 299
lcom 1
cbo 9

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ParagonIE_Sodium_Compat often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ParagonIE_Sodium_Compat, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Libsodium compatibility layer
5
 *
6
 * This is the only class you should be interfacing with, as a user of
7
 * sodium_compat.
8
 *
9
 * If the PHP extension for libsodium is installed, it will always use that
10
 * instead of our implementations. You get better performance and stronger
11
 * guarantees against side-channels that way.
12
 *
13
 * However, if your users don't have the PHP extension installed, we offer a
14
 * compatible interface here. It will give you the correct results as if the
15
 * PHP extension was installed. It won't be as fast, of course.
16
 *
17
 * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
18
 *                                                                               *
19
 *     Until audited, this is probably not safe to use! DANGER WILL ROBINSON     *
20
 *                                                                               *
21
 * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
22
 */
23
24
if (class_exists('ParagonIE_Sodium_Compat', false)) {
25
    return;
26
}
27
28
class ParagonIE_Sodium_Compat
29
{
30
    /**
31
     * This parameter prevents the use of the PECL extension.
32
     * It should only be used for unit testing.
33
     *
34
     * @var bool
35
     */
36
    public static $disableFallbackForUnitTests = false;
37
38
    /**
39
     * Use fast multiplication rather than our constant-time multiplication
40
     * implementation. Can be enabled at runtime. Only enable this if you
41
     * are absolutely certain that there is no timing leak on your platform.
42
     *
43
     * @var bool
44
     */
45
    public static $fastMult = false;
46
47
    const LIBRARY_VERSION_MAJOR = 9;
48
    const LIBRARY_VERSION_MINOR = 1;
49
    const VERSION_STRING = 'polyfill-1.0.8';
50
51
    // From libsodium
52
    const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
53
    const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
54
    const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
55
    const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
56
    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
57
    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
58
    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
59
    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
60
    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
61
    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
62
    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
63
    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
64
    const CRYPTO_AUTH_BYTES = 32;
65
    const CRYPTO_AUTH_KEYBYTES = 32;
66
    const CRYPTO_BOX_SEALBYTES = 16;
67
    const CRYPTO_BOX_SECRETKEYBYTES = 32;
68
    const CRYPTO_BOX_PUBLICKEYBYTES = 32;
69
    const CRYPTO_BOX_KEYPAIRBYTES = 64;
70
    const CRYPTO_BOX_MACBYTES = 16;
71
    const CRYPTO_BOX_NONCEBYTES = 24;
72
    const CRYPTO_BOX_SEEDBYTES = 32;
73
    const CRYPTO_KX_BYTES = 32;
74
    const CRYPTO_KX_PUBLICKEYBYTES = 32;
75
    const CRYPTO_KX_SECRETKEYBYTES = 32;
76
    const CRYPTO_GENERICHASH_BYTES = 32;
77
    const CRYPTO_GENERICHASH_BYTES_MIN = 16;
78
    const CRYPTO_GENERICHASH_BYTES_MAX = 64;
79
    const CRYPTO_GENERICHASH_KEYBYTES = 32;
80
    const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
81
    const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
82
    const CRYPTO_PWHASH_SALTBYTES = 16;
83
    const CRYPTO_PWHASH_STRPREFIX = '$argon2i$';
84
    const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
85
    const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
86
    const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
87
    const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
88
    const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
89
    const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
90
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
91
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
92
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
93
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216;
94
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
95
    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824;
96
    const CRYPTO_SCALARMULT_BYTES = 32;
97
    const CRYPTO_SCALARMULT_SCALARBYTES = 32;
98
    const CRYPTO_SHORTHASH_BYTES = 8;
99
    const CRYPTO_SHORTHASH_KEYBYTES = 16;
100
    const CRYPTO_SECRETBOX_KEYBYTES = 32;
101
    const CRYPTO_SECRETBOX_MACBYTES = 16;
102
    const CRYPTO_SECRETBOX_NONCEBYTES = 24;
103
    const CRYPTO_SIGN_BYTES = 64;
104
    const CRYPTO_SIGN_SEEDBYTES = 32;
105
    const CRYPTO_SIGN_PUBLICKEYBYTES = 32;
106
    const CRYPTO_SIGN_SECRETKEYBYTES = 64;
107
    const CRYPTO_SIGN_KEYPAIRBYTES = 96;
108
    const CRYPTO_STREAM_KEYBYTES = 32;
109
    const CRYPTO_STREAM_NONCEBYTES = 24;
110
111
    /**
112
     * Cache-timing-safe implementation of bin2hex().
113
     *
114
     * @param string $string A string (probably raw binary)
115
     * @return string        A hexadecimal-encoded string
116
     * @throws TypeError
117
     */
118
    public static function bin2hex($string)
119
    {
120
        /* Type checks: */
121
        ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
122
123
        if (self::isPhp72OrGreater()) {
124
            return bin2hex($string);
125
        }
126
        if (self::use_fallback('bin2hex')) {
127
            return call_user_func('\\Sodium\\bin2hex', $string);
128
        }
129
        return ParagonIE_Sodium_Core_Util::bin2hex($string);
130
    }
131
132
    /**
133
     * Compare two strings, in constant-time.
134
     * Compared to memcmp(), compare() is more useful for sorting.
135
     *
136
     * @param string $left The left operand; must be a string
137
     * @param string $right The right operand; must be a string
138
     * @return int          < 0 if the left operand is less than the right
139
     *                      0 if both strings are equal
140
     *                      > 0 if the right operand is less than the left
141
     * @throws TypeError
142
     */
143
    public static function compare($left, $right)
144
    {
145
        /* Type checks: */
146
        ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
147
        ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
148
149
        if (self::isPhp72OrGreater()) {
150
            return sodium_compare($left, $right);
151
        }
152
        if (self::use_fallback('compare')) {
153
            return call_user_func('\\Sodium\\compare', $left, $right);
154
        }
155
        return ParagonIE_Sodium_Core_Util::compare($left, $right);
156
    }
157
158
    /**
159
     * Authenticated Encryption with Associated Data: Decryption
160
     *
161
     * Algorithm:
162
     *     ChaCha20-Poly1305
163
     *
164
     * This mode uses a 64-bit random nonce with a 64-bit counter.
165
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
166
     *
167
     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
168
     * @param string $assocData Authenticated Associated Data (unencrypted)
169
     * @param string $nonce Number to be used only Once; must be 8 bytes
170
     * @param string $key Encryption key
171
     *
172
     * @return string            The original plaintext message
173
     * @throws Error
174
     * @throws TypeError
175
     */
176
    public static function crypto_aead_chacha20poly1305_decrypt(
177
        $ciphertext = '',
178
        $assocData = '',
179
        $nonce = '',
180
        $key = ''
181
    ) {
182
        /* Type checks: */
183
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
184
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
185
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
186
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
187
188
        /* Input validation: */
189
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
190
            throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
191
        }
192
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
193
            throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
194
        }
195
        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
196
            throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
197
        }
198
199
        if (self::isPhp72OrGreater()) {
200
            return sodium_crypto_aead_chacha20poly1305_decrypt(
201
                $ciphertext,
202
                $assocData,
203
                $nonce,
204
                $key
205
            );
206
        }
207
        if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) {
208
            return call_user_func(
209
                '\\Sodium\\crypto_aead_chacha20poly1305_decrypt',
210
                $ciphertext,
211
                $assocData,
212
                $nonce,
213
                $key
214
            );
215
        }
216
        if (PHP_INT_SIZE === 4) {
217
            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt(
218
                $ciphertext,
219
                $assocData,
220
                $nonce,
221
                $key
222
            );
223
        }
224
        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt(
225
            $ciphertext,
226
            $assocData,
227
            $nonce,
228
            $key
229
        );
230
    }
231
232
    /**
233
     * Authenticated Encryption with Associated Data
234
     *
235
     * Algorithm:
236
     *     ChaCha20-Poly1305
237
     *
238
     * This mode uses a 64-bit random nonce with a 64-bit counter.
239
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
240
     *
241
     * @param string $plaintext Message to be encrypted
242
     * @param string $assocData Authenticated Associated Data (unencrypted)
243
     * @param string $nonce Number to be used only Once; must be 8 bytes
244
     * @param string $key Encryption key
245
     *
246
     * @return string           Ciphertext with a 16-byte Poly1305 message
247
     *                          authentication code appended
248
     * @throws Error
249
     * @throws TypeError
250
     */
251
    public static function crypto_aead_chacha20poly1305_encrypt(
252
        $plaintext = '',
253
        $assocData = '',
254
        $nonce = '',
255
        $key = ''
256
    ) {
257
        /* Type checks: */
258
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
259
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
260
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
261
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
262
263
        /* Input validation: */
264
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
265
            throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
266
        }
267
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
268
            throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
269
        }
270
271
        if (self::isPhp72OrGreater()) {
272
            return sodium_crypto_aead_chacha20poly1305_encrypt(
273
                $plaintext,
274
                $assocData,
275
                $nonce,
276
                $key
277
            );
278
        }
279
        if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) {
280
            return call_user_func(
281
                '\\Sodium\\crypto_aead_chacha20poly1305_encrypt',
282
                $plaintext,
283
                $assocData,
284
                $nonce,
285
                $key
286
            );
287
        }
288
        if (PHP_INT_SIZE === 4) {
289
            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt(
290
                $plaintext,
291
                $assocData,
292
                $nonce,
293
                $key
294
            );
295
        }
296
        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt(
297
            $plaintext,
298
            $assocData,
299
            $nonce,
300
            $key
301
        );
302
    }
303
304
    /**
305
     * Authenticated Encryption with Associated Data: Decryption
306
     *
307
     * Algorithm:
308
     *     ChaCha20-Poly1305
309
     *
310
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
311
     * Regular mode uses a 64-bit random nonce with a 64-bit counter.
312
     *
313
     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
314
     * @param string $assocData Authenticated Associated Data (unencrypted)
315
     * @param string $nonce Number to be used only Once; must be 12 bytes
316
     * @param string $key Encryption key
317
     *
318
     * @return string            The original plaintext message
319
     * @throws Error
320
     * @throws TypeError
321
     */
322
    public static function crypto_aead_chacha20poly1305_ietf_decrypt(
323
        $ciphertext = '',
324
        $assocData = '',
325
        $nonce = '',
326
        $key = ''
327
    ) {
328
        /* Type checks: */
329
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
330
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
331
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
332
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
333
334
        /* Input validation: */
335
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
336
            throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
337
        }
338
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
339
            throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
340
        }
341
        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
342
            throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
343
        }
344
345
        if (self::isPhp72OrGreater()) {
346
            return sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
347
                $ciphertext,
348
                $assocData,
349
                $nonce,
350
                $key
351
            );
352
        }
353
        if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) {
354
            return call_user_func(
355
                '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt',
356
                $ciphertext,
357
                $assocData,
358
                $nonce,
359
                $key
360
            );
361
        }
362
        if (PHP_INT_SIZE === 4) {
363
            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt(
364
                $ciphertext,
365
                $assocData,
366
                $nonce,
367
                $key
368
            );
369
        }
370
        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt(
371
            $ciphertext,
372
            $assocData,
373
            $nonce,
374
            $key
375
        );
376
    }
377
378
    /**
379
     * Authenticated Encryption with Associated Data
380
     *
381
     * Algorithm:
382
     *     ChaCha20-Poly1305
383
     *
384
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
385
     * Regular mode uses a 64-bit random nonce with a 64-bit counter.
386
     *
387
     * @param string $plaintext Message to be encrypted
388
     * @param string $assocData Authenticated Associated Data (unencrypted)
389
     * @param string $nonce Number to be used only Once; must be 8 bytes
390
     * @param string $key Encryption key
391
     *
392
     * @return string           Ciphertext with a 16-byte Poly1305 message
393
     *                          authentication code appended
394
     * @throws Error
395
     * @throws TypeError
396
     */
397
    public static function crypto_aead_chacha20poly1305_ietf_encrypt(
398
        $plaintext = '',
399
        $assocData = '',
400
        $nonce = '',
401
        $key = ''
402
    ) {
403
        /* Type checks: */
404
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
405
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
406
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
407
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
408
409
        /* Input validation: */
410
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
411
            throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
412
        }
413
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
414
            throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
415
        }
416
417
        if (self::isPhp72OrGreater()) {
418
            return sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
419
                $plaintext,
420
                $assocData,
421
                $nonce,
422
                $key
423
            );
424
        }
425
        if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) {
426
            return call_user_func(
427
                '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt',
428
                $plaintext,
429
                $assocData,
430
                $nonce,
431
                $key
432
            );
433
        }
434
        if (PHP_INT_SIZE === 4) {
435
            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt(
436
                $plaintext,
437
                $assocData,
438
                $nonce,
439
                $key
440
            );
441
        }
442
        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt(
443
            $plaintext,
444
            $assocData,
445
            $nonce,
446
            $key
447
        );
448
    }
449
450
    /**
451
     * Authenticated Encryption with Associated Data: Decryption
452
     *
453
     * Algorithm:
454
     *     XChaCha20-Poly1305
455
     *
456
     * This mode uses a 64-bit random nonce with a 64-bit counter.
457
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
458
     *
459
     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
460
     * @param string $assocData Authenticated Associated Data (unencrypted)
461
     * @param string $nonce Number to be used only Once; must be 8 bytes
462
     * @param string $key Encryption key
463
     *
464
     * @return string            The original plaintext message
465
     * @throws Error
466
     * @throws TypeError
467
     */
468
    public static function crypto_aead_xchacha20poly1305_ietf_decrypt(
469
        $ciphertext = '',
470
        $assocData = '',
471
        $nonce = '',
472
        $key = ''
473
    ) {
474
        /* Type checks: */
475
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
476
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
477
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
478
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
479
480
        /* Input validation: */
481
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
482
            throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long');
483
        }
484
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
485
            throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long');
486
        }
487
        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) {
488
            throw new Error('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long');
489
        }
490
491
        if (PHP_INT_SIZE === 4) {
492
            return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt(
493
                $ciphertext,
494
                $assocData,
495
                $nonce,
496
                $key
497
            );
498
        }
499
        return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt(
500
            $ciphertext,
501
            $assocData,
502
            $nonce,
503
            $key
504
        );
505
    }
506
507
    /**
508
     * Authenticated Encryption with Associated Data
509
     *
510
     * Algorithm:
511
     *     XChaCha20-Poly1305
512
     *
513
     * This mode uses a 64-bit random nonce with a 64-bit counter.
514
     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
515
     *
516
     * @param string $plaintext Message to be encrypted
517
     * @param string $assocData Authenticated Associated Data (unencrypted)
518
     * @param string $nonce Number to be used only Once; must be 8 bytes
519
     * @param string $key Encryption key
520
     *
521
     * @return string           Ciphertext with a 16-byte Poly1305 message
522
     *                          authentication code appended
523
     * @throws Error
524
     * @throws TypeError
525
     */
526
    public static function crypto_aead_xchacha20poly1305_ietf_encrypt(
527
        $plaintext = '',
528
        $assocData = '',
529
        $nonce = '',
530
        $key = ''
531
    ) {
532
        /* Type checks: */
533
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
534
        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
535
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
536
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
537
538
        /* Input validation: */
539
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
540
            throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long');
541
        }
542
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
543
            throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long');
544
        }
545
546
        if (PHP_INT_SIZE === 4) {
547
            return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt(
548
                $plaintext,
549
                $assocData,
550
                $nonce,
551
                $key
552
            );
553
        }
554
        return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt(
555
            $plaintext,
556
            $assocData,
557
            $nonce,
558
            $key
559
        );
560
    }
561
562
    /**
563
     * Authenticate a message. Uses symmetric-key cryptography.
564
     *
565
     * Algorithm:
566
     *     HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits.
567
     *     Not to be confused with HMAC-SHA-512/256 which would use the
568
     *     SHA-512/256 hash function (uses different initial parameters
569
     *     but still truncates to 256 bits to sidestep length-extension
570
     *     attacks).
571
     *
572
     * @param string $message Message to be authenticated
573
     * @param string $key Symmetric authentication key
574
     * @return string         Message authentication code
575
     * @throws Error
576
     * @throws TypeError
577
     */
578
    public static function crypto_auth($message, $key)
579
    {
580
        /* Type checks: */
581
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
582
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
583
584
        /* Input validation: */
585
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
586
            throw new Error('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.');
587
        }
588
589
        if (self::isPhp72OrGreater()) {
590
            return sodium_crypto_auth($message, $key);
591
        }
592
        if (self::use_fallback('crypto_auth')) {
593
            return call_user_func('\\Sodium\\crypto_auth', $message, $key);
594
        }
595
        if (PHP_INT_SIZE === 4) {
596
            return ParagonIE_Sodium_Crypto32::auth($message, $key);
597
        }
598
        return ParagonIE_Sodium_Crypto::auth($message, $key);
599
    }
600
601
    /**
602
     * Verify the MAC of a message previously authenticated with crypto_auth.
603
     *
604
     * @param string $mac Message authentication code
605
     * @param string $message Message whose authenticity you are attempting to
606
     *                        verify (with a given MAC and key)
607
     * @param string $key Symmetric authentication key
608
     * @return bool           TRUE if authenticated, FALSE otherwise
609
     * @throws Error
610
     * @throws TypeError
611
     */
612
    public static function crypto_auth_verify($mac, $message, $key)
613
    {
614
        /* Type checks: */
615
        ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1);
616
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
617
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
618
619
        /* Input validation: */
620
        if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) {
621
            throw new Error('Argument 1 must be CRYPTO_AUTH_BYTES long.');
622
        }
623
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
624
            throw new Error('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.');
625
        }
626
627
        if (self::isPhp72OrGreater()) {
628
            return sodium_crypto_auth_verify($mac, $message, $key);
629
        }
630
        if (self::use_fallback('crypto_auth_verify')) {
631
            return call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key);
632
        }
633
        if (PHP_INT_SIZE === 4) {
634
            return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key);
635
        }
636
        return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key);
637
    }
638
639
    /**
640
     * Authenticated asymmetric-key encryption. Both the sender and recipient
641
     * may decrypt messages.
642
     *
643
     * Algorithm: X25519-XSalsa20-Poly1305.
644
     *     X25519: Elliptic-Curve Diffie Hellman over Curve25519.
645
     *     XSalsa20: Extended-nonce variant of salsa20.
646
     *     Poyl1305: Polynomial MAC for one-time message authentication.
647
     *
648
     * @param string $plaintext The message to be encrypted
649
     * @param string $nonce A Number to only be used Once; must be 24 bytes
650
     * @param string $keypair Your secret key and your recipient's public key
651
     * @return string           Ciphertext with 16-byte Poly1305 MAC
652
     * @throws Error
653
     * @throws TypeError
654
     */
655
    public static function crypto_box($plaintext, $nonce, $keypair)
656
    {
657
        /* Type checks: */
658
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
659
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
660
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
661
662
        /* Input validation: */
663
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
664
            throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
665
        }
666
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
667
            throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
668
        }
669
670
        if (self::isPhp72OrGreater()) {
671
            return sodium_crypto_box($plaintext, $nonce, $keypair);
672
        }
673
        if (self::use_fallback('crypto_box')) {
674
            return call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair);
675
        }
676
        if (PHP_INT_SIZE === 4) {
677
            return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair);
678
        }
679
        return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair);
680
    }
681
682
    /**
683
     * Anonymous public-key encryption. Only the recipient may decrypt messages.
684
     *
685
     * Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box.
686
     *     The sender's X25519 keypair is ephemeral.
687
     *     Nonce is generated from the BLAKE2b hash of both public keys.
688
     *
689
     * This provides ciphertext integrity.
690
     *
691
     * @param string $plaintext Message to be sealed
692
     * @param string $publicKey Your recipient's public key
693
     * @return string           Sealed message that only your recipient can
694
     *                          decrypt
695
     * @throws Error
696
     * @throws TypeError
697
     */
698
    public static function crypto_box_seal($plaintext, $publicKey)
699
    {
700
        /* Type checks: */
701
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
702
        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
703
704
        /* Input validation: */
705
        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
706
            throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
707
        }
708
709
        if (self::isPhp72OrGreater()) {
710
            return sodium_crypto_box_seal($plaintext, $publicKey);
711
        }
712
        if (self::use_fallback('crypto_box_seal')) {
713
            return call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey);
714
        }
715
        if (PHP_INT_SIZE === 4) {
716
            return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey);
717
        }
718
        return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey);
719
    }
720
721
    /**
722
     * Opens a message encrypted with crypto_box_seal(). Requires
723
     * the recipient's keypair (sk || pk) to decrypt successfully.
724
     *
725
     * This validates ciphertext integrity.
726
     *
727
     * @param string $ciphertext Sealed message to be opened
728
     * @param string $keypair    Your crypto_box keypair
729
     * @return string            The original plaintext message
730
     * @throws Error
731
     * @throws TypeError
732
     */
733
    public static function crypto_box_seal_open($ciphertext, $keypair)
734
    {
735
        /* Type checks: */
736
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
737
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2);
738
739
        /* Input validation: */
740
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
741
            throw new Error('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.');
742
        }
743
744
        if (self::isPhp72OrGreater()) {
745
            return sodium_crypto_box_seal_open($ciphertext, $keypair);
746
        }
747
        if (self::use_fallback('crypto_box_seal_open')) {
748
            return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair);
749
        }
750
        if (PHP_INT_SIZE === 4) {
751
            return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair);
752
        }
753
        return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair);
754
    }
755
756
    /**
757
     * Generate a new random X25519 keypair.
758
     *
759
     * @return string A 64-byte string; the first 32 are your secret key, while
760
     *                the last 32 are your public key. crypto_box_secretkey()
761
     *                and crypto_box_publickey() exist to separate them so you
762
     *                don't accidentally get them mixed up!
763
     */
764
    public static function crypto_box_keypair()
765
    {
766
        if (self::isPhp72OrGreater()) {
767
            return sodium_crypto_box_keypair();
768
        }
769
        if (self::use_fallback('crypto_box_keypair')) {
770
            return call_user_func('\\Sodium\\crypto_box_keypair');
771
        }
772
        return ParagonIE_Sodium_Crypto::box_keypair();
773
    }
774
775
    /**
776
     * Combine two keys into a keypair for use in library methods that expect
777
     * a keypair. This doesn't necessarily have to be the same person's keys.
778
     *
779
     * @param string $secretKey Secret key
780
     * @param string $publicKey Public key
781
     * @return string    Keypair
782
     * @throws Error
783
     * @throws TypeError
784
     */
785
    public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey)
786
    {
787
        /* Type checks: */
788
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
789
        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
790
791
        /* Input validation: */
792
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
793
            throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
794
        }
795
        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
796
            throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
797
        }
798
799
        if (self::isPhp72OrGreater()) {
800
            return sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
801
        }
802
        if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) {
803
            return call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey);
804
        }
805
        if (PHP_INT_SIZE === 4) {
806
            return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
807
        }
808
        return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
809
    }
810
811
    /**
812
     * Decrypt a message previously encrypted with crypto_box().
813
     *
814
     * @param string $ciphertext Encrypted message
815
     * @param string $nonce      Number to only be used Once; must be 24 bytes
816
     * @param string $keypair    Your secret key and the sender's public key
817
     * @return string            The original plaintext message
818
     * @throws Error
819
     * @throws TypeError
820
     */
821
    public static function crypto_box_open($ciphertext, $nonce, $keypair)
822
    {
823
        /* Type checks: */
824
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
825
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
826
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
827
828
        /* Input validation: */
829
        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) {
830
            throw new Error('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.');
831
        }
832
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
833
            throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
834
        }
835
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
836
            throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
837
        }
838
839
        if (self::isPhp72OrGreater()) {
840
            return sodium_crypto_box_open($ciphertext, $nonce, $keypair);
841
        }
842
        if (self::use_fallback('crypto_box_open')) {
843
            return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair);
844
        }
845
        if (PHP_INT_SIZE === 4) {
846
            return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair);
847
        }
848
        return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair);
849
    }
850
851
    /**
852
     * Extract the public key from a crypto_box keypair.
853
     *
854
     * @param string $keypair
855
     * @return string         Your crypto_box public key
856
     * @throws Error
857
     * @throws TypeError
858
     */
859
    public static function crypto_box_publickey($keypair)
860
    {
861
        /* Type checks: */
862
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
863
864
        /* Input validation: */
865
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
866
            throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
867
        }
868
869
        if (self::isPhp72OrGreater()) {
870
            return sodium_crypto_box_publickey($keypair);
871
        }
872
        if (self::use_fallback('crypto_box_publickey')) {
873
            return call_user_func('\\Sodium\\crypto_box_publickey', $keypair);
874
        }
875
        if (PHP_INT_SIZE === 4) {
876
            return ParagonIE_Sodium_Crypto32::box_publickey($keypair);
877
        }
878
        return ParagonIE_Sodium_Crypto::box_publickey($keypair);
879
    }
880
881
    /**
882
     * Calculate the X25519 public key from a given X25519 secret key.
883
     *
884
     * @param string $secretKey Any X25519 secret key
885
     * @return string      The corresponding X25519 public key
886
     * @throws Error
887
     * @throws TypeError
888
     */
889
    public static function crypto_box_publickey_from_secretkey($secretKey)
890
    {
891
        /* Type checks: */
892
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
893
894
        /* Input validation: */
895
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
896
            throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
897
        }
898
899
        if (self::isPhp72OrGreater()) {
900
            return sodium_crypto_box_publickey_from_secretkey($secretKey);
901
        }
902
        if (self::use_fallback('crypto_box_publickey_from_secretkey')) {
903
            return call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey);
904
        }
905
        if (PHP_INT_SIZE === 4) {
906
            return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey);
907
        }
908
        return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey);
909
    }
910
911
    /**
912
     * Extract the secret key from a crypto_box keypair.
913
     *
914
     * @param string $keypair
915
     * @return string         Your crypto_box secret key
916
     * @throws Error
917
     * @throws TypeError
918
     */
919
    public static function crypto_box_secretkey($keypair)
920
    {
921
        /* Type checks: */
922
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
923
924
        /* Input validation: */
925
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
926
            throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
927
        }
928
929
        if (self::isPhp72OrGreater()) {
930
            return sodium_crypto_box_secretkey($keypair);
931
        }
932
        if (self::use_fallback('crypto_box_secretkey')) {
933
            return call_user_func('\\Sodium\\crypto_box_secretkey', $keypair);
934
        }
935
        if (PHP_INT_SIZE === 4) {
936
            return ParagonIE_Sodium_Crypto32::box_secretkey($keypair);
937
        }
938
        return ParagonIE_Sodium_Crypto::box_secretkey($keypair);
939
    }
940
941
    /**
942
     * Generate an X25519 keypair from a seed.
943
     *
944
     * @param string $seed
945
     * @return string
946
     */
947
    public static function crypto_box_seed_keypair($seed)
948
    {
949
        /* Type checks: */
950
        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
951
952
        if (self::isPhp72OrGreater()) {
953
            return sodium_crypto_box_seed_keypair($seed);
954
        }
955
        if (self::use_fallback('crypto_box_seed_keypair')) {
956
            return call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed);
957
        }
958
        return ParagonIE_Sodium_Crypto::box_seed_keypair($seed);
959
    }
960
961
    /**
962
     * Calculates a BLAKE2b hash, with an optional key.
963
     *
964
     * @param string $message The message to be hashed
965
     * @param string $key If specified, must be a string between 16 and 64
966
     *                        bytes long
967
     * @param int $length Output length in bytes; must be between 16 and 64
968
     *                        (default = 32)
969
     * @return string         Raw binary
970
     * @throws Error
971
     * @throws TypeError
972
     */
973
    public static function crypto_generichash($message, $key = '', $length = self::CRYPTO_GENERICHASH_BYTES)
974
    {
975
        /* Type checks: */
976
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
977
        if (is_null($key)) {
978
            $key = '';
979
        }
980
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
981
        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3);
982
983
        /* Input validation: */
984
        if (!empty($key)) {
985
            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
986
                throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
987
            }
988
            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
989
                throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
990
            }
991
        }
992
993
        if (self::isPhp72OrGreater()) {
994
            return sodium_crypto_generichash($message, $key, $length);
995
        }
996
        if (self::use_fallback('crypto_generichash')) {
997
            return call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length);
998
        }
999
        if (PHP_INT_SIZE === 4) {
1000
            return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length);
1001
        }
1002
        return ParagonIE_Sodium_Crypto::generichash($message, $key, $length);
1003
    }
1004
1005
    /**
1006
     * Get the final BLAKE2b hash output for a given context.
1007
     *
1008
     * @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init().
1009
     * @param int $length Hash output size.
1010
     * @return string      Final BLAKE2b hash.
1011
     * @throws Error
1012
     * @throws TypeError
1013
     */
1014
    public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES)
1015
    {
1016
        /* Type checks: */
1017
        ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
1018
        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
1019
1020
        if (self::isPhp72OrGreater()) {
1021
            return sodium_crypto_generichash_final($ctx, $length);
1022
        }
1023
        if (self::use_fallback('crypto_generichash_final')) {
1024
            $func = '\\Sodium\\crypto_generichash_final';
1025
            return $func($ctx, $length);
1026
        }
1027
        if (PHP_INT_SIZE === 4) {
1028
            $result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length);
1029
        } else {
1030
            $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length);
1031
        }
1032
        try {
1033
            self::memzero($ctx);
1034
        } catch (Error $ex) {
1035
            unset($ctx);
1036
        }
1037
        return $result;
1038
    }
1039
1040
    /**
1041
     * Initialize a BLAKE2b hashing context, for use in a streaming interface.
1042
     *
1043
     * @param string $key If specified must be a string between 16 and 64 bytes
1044
     * @param int $length The size of the desired hash output
1045
     * @return string     A BLAKE2 hashing context, encoded as a string
1046
     *                    (To be 100% compatible with ext/libsodium)
1047
     * @throws Error
1048
     * @throws TypeError
1049
     */
1050
    public static function crypto_generichash_init($key = '', $length = self::CRYPTO_GENERICHASH_BYTES)
1051
    {
1052
        /* Type checks: */
1053
        if (is_null($key)) {
1054
            $key = '';
1055
        }
1056
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
1057
        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
1058
1059
        /* Input validation: */
1060
        if (!empty($key)) {
1061
            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
1062
                throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
1063
            }
1064
            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
1065
                throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
1066
            }
1067
        }
1068
1069
        if (self::isPhp72OrGreater()) {
1070
            return sodium_crypto_generichash_init($key, $length);
1071
        }
1072
        if (self::use_fallback('crypto_generichash_init')) {
1073
            return call_user_func('\\Sodium\\crypto_generichash_init', $key, $length);
1074
        }
1075
        if (PHP_INT_SIZE === 4) {
1076
            return ParagonIE_Sodium_Crypto32::generichash_init($key, $length);
1077
        }
1078
        return ParagonIE_Sodium_Crypto::generichash_init($key, $length);
1079
    }
1080
1081
    /**
1082
     * Update a BLAKE2b hashing context with additional data.
1083
     *
1084
     * @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init().
1085
     *                        $ctx is passed by reference and gets updated in-place.
1086
     * @param string $message The message to append to the existing hash state.
1087
     * @return void
1088
     * @throws TypeError
1089
     */
1090
    public static function crypto_generichash_update(&$ctx, $message)
1091
    {
1092
        /* Type checks: */
1093
        ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
1094
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
1095
1096
        if (self::isPhp72OrGreater()) {
1097
            sodium_crypto_generichash_update($ctx, $message);
1098
            return;
1099
        }
1100
        if (self::use_fallback('crypto_generichash_update')) {
1101
            $func = '\\Sodium\\crypto_generichash_update';
1102
            $func($ctx, $message);
1103
            return;
1104
        }
1105
        if (PHP_INT_SIZE === 4) {
1106
            $ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message);
1107
        } else {
1108
            $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message);
1109
        }
1110
    }
1111
1112
    /**
1113
     * Perform a key exchange, between a designated client and a server.
1114
     *
1115
     * Typically, you would designate one machine to be the client and the
1116
     * other to be the server. The first two keys are what you'd expect for
1117
     * scalarmult() below, but the latter two public keys don't swap places.
1118
     *
1119
     * | ALICE                          | BOB                                 |
1120
     * | Client                         | Server                              |
1121
     * |--------------------------------|-------------------------------------|
1122
     * | shared = crypto_kx(            | shared = crypto_kx(                 |
1123
     * |     alice_sk,                  |     bob_sk,                         | <- contextual
1124
     * |     bob_pk,                    |     alice_pk,                       | <- contextual
1125
     * |     alice_pk,                  |     alice_pk,                       | <----- static
1126
     * |     bob_pk                     |     bob_pk                          | <----- static
1127
     * | )                              | )                                   |
1128
     *
1129
     * They are used along with the scalarmult product to generate a 256-bit
1130
     * BLAKE2b hash unique to the client and server keys.
1131
     *
1132
     * @param string $my_secret
1133
     * @param string $their_public
1134
     * @param string $client_public
1135
     * @param string $server_public
1136
     * @return string
1137
     * @throws Error
1138
     * @throws TypeError
1139
     */
1140
    public static function crypto_kx($my_secret, $their_public, $client_public, $server_public)
1141
    {
1142
        /* Type checks: */
1143
        ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1);
1144
        ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2);
1145
        ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3);
1146
        ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4);
1147
1148
        /* Input validation: */
1149
        if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1150
            throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1151
        }
1152
        if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1153
            throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1154
        }
1155
        if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1156
            throw new Error('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1157
        }
1158
        if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1159
            throw new Error('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1160
        }
1161
1162
        if (self::isPhp72OrGreater()) {
1163
            if (is_callable('sodium_crypto_kx')) {
1164
                return sodium_crypto_kx(
1165
                    $my_secret,
1166
                    $their_public,
1167
                    $client_public,
1168
                    $server_public
1169
                );
1170
            }
1171
        }
1172
        if (self::use_fallback('crypto_kx')) {
1173
            return call_user_func(
1174
                '\\Sodium\\crypto_kx',
1175
                $my_secret,
1176
                $their_public,
1177
                $client_public,
1178
                $server_public
1179
            );
1180
        }
1181
        if (PHP_INT_SIZE === 4) {
1182
            return ParagonIE_Sodium_Crypto32::keyExchange(
1183
                $my_secret,
1184
                $their_public,
1185
                $client_public,
1186
                $server_public
1187
            );
1188
        }
1189
        return ParagonIE_Sodium_Crypto::keyExchange(
1190
            $my_secret,
1191
            $their_public,
1192
            $client_public,
1193
            $server_public
1194
        );
1195
    }
1196
1197
    /**
1198
     * @param int $outlen
1199
     * @param string $passwd
1200
     * @param string $salt
1201
     * @param int $opslimit
1202
     * @param int $memlimit
1203
     * @return string
1204
     * @throws Error
1205
     */
1206
    public static function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit)
1207
    {
1208
        ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
1209
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
1210
        ParagonIE_Sodium_Core_Util::declareScalarType($salt,  'string', 3);
1211
        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
1212
        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
1213
1214
        if (self::isPhp72OrGreater()) {
1215
            return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit);
1216
        }
1217
        if (self::use_fallback('crypto_pwhash')) {
1218
            return call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit);
1219
        }
1220
        // This is the best we can do.
1221
        throw new Error(
1222
            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
1223
        );
1224
    }
1225
1226
    /**
1227
     * @param string $passwd
1228
     * @param int $opslimit
1229
     * @param int $memlimit
1230
     * @return string
1231
     * @throws Error
1232
     */
1233
    public static function crypto_pwhash_str($passwd, $opslimit, $memlimit)
1234
    {
1235
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
1236
        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
1237
        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
1238
1239
        if (self::isPhp72OrGreater()) {
1240
            return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit);
1241
        }
1242
        if (self::use_fallback('crypto_pwhash_str')) {
1243
            return call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit);
1244
        }
1245
        // This is the best we can do.
1246
        throw new Error(
1247
            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
1248
        );
1249
    }
1250
1251
    /**
1252
     * @param string $passwd
1253
     * @param string $hash
1254
     * @return bool
1255
     * @throws Error
1256
     */
1257
    public static function crypto_pwhash_str_verify($passwd, $hash)
1258
    {
1259
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
1260
        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
1261
1262
        if (self::isPhp72OrGreater()) {
1263
            return sodium_crypto_pwhash_str_verify($passwd, $hash);
1264
        }
1265
        if (self::use_fallback('crypto_pwhash_str_verify')) {
1266
            return call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash);
1267
        }
1268
        // This is the best we can do.
1269
        throw new Error(
1270
            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
1271
        );
1272
    }
1273
1274
    /**
1275
     * @param int $outlen
1276
     * @param string $passwd
1277
     * @param string $salt
1278
     * @param int $opslimit
1279
     * @param int $memlimit
1280
     * @return string
1281
     * @throws Error
1282
     */
1283
    public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit)
1284
    {
1285
        ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
1286
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
1287
        ParagonIE_Sodium_Core_Util::declareScalarType($salt,  'string', 3);
1288
        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
1289
        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
1290
1291
        if (self::isPhp72OrGreater()) {
1292
            return sodium_crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit);
1293
        }
1294
        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
1295
            return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256', $outlen, $passwd, $salt, $opslimit, $memlimit);
1296
        }
1297
        // This is the best we can do.
1298
        throw new Error(
1299
            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
1300
        );
1301
    }
1302
1303
    /**
1304
     * @param string $passwd
1305
     * @param int $opslimit
1306
     * @param int $memlimit
1307
     * @return string
1308
     * @throws Error
1309
     */
1310
    public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit)
1311
    {
1312
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
1313
        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
1314
        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
1315
1316
        if (self::isPhp72OrGreater()) {
1317
            return sodium_crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit);
1318
        }
1319
        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) {
1320
            return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str', $passwd, $opslimit, $memlimit);
1321
        }
1322
        // This is the best we can do.
1323
        throw new Error(
1324
            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
1325
        );
1326
    }
1327
1328
    /**
1329
     * @param string $passwd
1330
     * @param string $hash
1331
     * @return bool
1332
     * @throws Error
1333
     */
1334
    public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
1335
    {
1336
        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
1337
        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
1338
1339
        if (self::isPhp72OrGreater()) {
1340
            return sodium_crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash);
1341
        }
1342
        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) {
1343
            return call_user_func('\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify', $passwd, $hash);
1344
        }
1345
        // This is the best we can do.
1346
        throw new Error(
1347
            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
1348
        );
1349
    }
1350
1351
    /**
1352
     * Calculate the shared secret between your secret key and your
1353
     * recipient's public key.
1354
     *
1355
     * Algorithm: X25519 (ECDH over Curve25519)
1356
     *
1357
     * @param string $secretKey
1358
     * @param string $publicKey
1359
     * @return string
1360
     * @throws Error
1361
     * @throws TypeError
1362
     */
1363
    public static function crypto_scalarmult($secretKey, $publicKey)
1364
    {
1365
        /* Type checks: */
1366
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
1367
        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
1368
1369
        /* Input validation: */
1370
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1371
            throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1372
        }
1373
        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1374
            throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1375
        }
1376
1377
        if (self::isPhp72OrGreater()) {
1378
            return sodium_crypto_scalarmult($secretKey, $publicKey);
1379
        }
1380
        if (self::use_fallback('crypto_scalarmult')) {
1381
            return call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey);
1382
        }
1383
1384
        /* Output validation: Forbid all-zero keys */
1385
        if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
1386
            throw new Error('Zero secret key is not allowed');
1387
        }
1388
        if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) {
1389
            throw new Error('Zero public key is not allowed');
1390
        }
1391
        if (PHP_INT_SIZE === 4) {
1392
            return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey);
1393
        }
1394
        return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey);
1395
    }
1396
1397
    /**
1398
     * Calculate an X25519 public key from an X25519 secret key.
1399
     *
1400
     * @param string $secretKey
1401
     * @return string
1402
     * @throws Error
1403
     * @throws TypeError
1404
     */
1405
    public static function crypto_scalarmult_base($secretKey)
1406
    {
1407
        /* Type checks: */
1408
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
1409
1410
        /* Input validation: */
1411
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1412
            throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1413
        }
1414
1415
        if (self::isPhp72OrGreater()) {
1416
            return sodium_crypto_scalarmult_base($secretKey);
1417
        }
1418
        if (self::use_fallback('crypto_scalarmult_base')) {
1419
            return call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey);
1420
        }
1421
        if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
1422
            throw new Error('Zero secret key is not allowed');
1423
        }
1424
        if (PHP_INT_SIZE === 4) {
1425
            return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey);
1426
        }
1427
        return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey);
1428
    }
1429
1430
    /**
1431
     * Authenticated symmetric-key encryption.
1432
     *
1433
     * Algorithm: XSalsa20-Poly1305
1434
     *
1435
     * @param string $plaintext The message you're encrypting
1436
     * @param string $nonce A Number to be used Once; must be 24 bytes
1437
     * @param string $key Symmetric encryption key
1438
     * @return string           Ciphertext with Poly1305 MAC
1439
     * @throws Error
1440
     * @throws TypeError
1441
     */
1442
    public static function crypto_secretbox($plaintext, $nonce, $key)
1443
    {
1444
        /* Type checks: */
1445
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
1446
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1447
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1448
1449
        /* Input validation: */
1450
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
1451
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1452
        }
1453
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
1454
            throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
1455
        }
1456
1457
        if (self::isPhp72OrGreater()) {
1458
            return sodium_crypto_secretbox($plaintext, $nonce, $key);
1459
        }
1460
        if (self::use_fallback('crypto_secretbox')) {
1461
            return call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key);
1462
        }
1463
        if (PHP_INT_SIZE === 4) {
1464
            return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key);
1465
        }
1466
        return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key);
1467
    }
1468
1469
    /**
1470
     * Decrypts a message previously encrypted with crypto_secretbox().
1471
     *
1472
     * @param string $ciphertext Ciphertext with Poly1305 MAC
1473
     * @param string $nonce      A Number to be used Once; must be 24 bytes
1474
     * @param string $key        Symmetric encryption key
1475
     * @return string            Original plaintext message
1476
     * @throws Error
1477
     * @throws TypeError
1478
     */
1479
    public static function crypto_secretbox_open($ciphertext, $nonce, $key)
1480
    {
1481
        /* Type checks: */
1482
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
1483
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1484
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1485
1486
        /* Input validation: */
1487
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
1488
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1489
        }
1490
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
1491
            throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
1492
        }
1493
1494
        if (self::isPhp72OrGreater()) {
1495
            return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
1496
        }
1497
        if (self::use_fallback('crypto_secretbox_open')) {
1498
            return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key);
1499
        }
1500
        if (PHP_INT_SIZE === 4) {
1501
            return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key);
1502
        }
1503
        return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key);
1504
    }
1505
1506
    /**
1507
     * Authenticated symmetric-key encryption.
1508
     *
1509
     * Algorithm: XChaCha20-Poly1305
1510
     *
1511
     * @param string $plaintext The message you're encrypting
1512
     * @param string $nonce     A Number to be used Once; must be 24 bytes
1513
     * @param string $key       Symmetric encryption key
1514
     * @return string           Ciphertext with Poly1305 MAC
1515
     * @throws Error
1516
     * @throws TypeError
1517
     */
1518
    public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key)
1519
    {
1520
        /* Type checks: */
1521
        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
1522
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1523
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1524
1525
        /* Input validation: */
1526
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
1527
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1528
        }
1529
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
1530
            throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
1531
        }
1532
        if (PHP_INT_SIZE === 4) {
1533
            return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
1534
        }
1535
        return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
1536
    }
1537
    /**
1538
     * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305().
1539
     *
1540
     * @param string $ciphertext Ciphertext with Poly1305 MAC
1541
     * @param string $nonce      A Number to be used Once; must be 24 bytes
1542
     * @param string $key        Symmetric encryption key
1543
     * @return string            Original plaintext message
1544
     * @throws Error
1545
     * @throws TypeError
1546
     */
1547
    public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
1548
    {
1549
        /* Type checks: */
1550
        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
1551
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1552
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1553
1554
        /* Input validation: */
1555
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
1556
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1557
        }
1558
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
1559
            throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
1560
        }
1561
1562
        if (PHP_INT_SIZE === 4) {
1563
            return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
1564
        }
1565
        return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
1566
    }
1567
1568
    /**
1569
     * Calculates a SipHash-2-4 hash of a message for a given key.
1570
     *
1571
     * @param string $message Input message
1572
     * @param string $key SipHash-2-4 key
1573
     * @return string         Hash
1574
     * @throws Error
1575
     * @throws TypeError
1576
     */
1577
    public static function crypto_shorthash($message, $key)
1578
    {
1579
        /* Type checks: */
1580
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
1581
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
1582
1583
        /* Input validation: */
1584
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) {
1585
            throw new Error('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.');
1586
        }
1587
1588
        if (self::isPhp72OrGreater()) {
1589
            return sodium_crypto_shorthash($message, $key);
1590
        }
1591
        if (self::use_fallback('crypto_shorthash')) {
1592
            return call_user_func('\\Sodium\\crypto_shorthash', $message, $key);
1593
        }
1594
        if (PHP_INT_SIZE === 4) {
1595
            return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key);
1596
        }
1597
        return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key);
1598
    }
1599
1600
    /**
1601
     * Expand a key and nonce into a keystream of pseudorandom bytes.
1602
     *
1603
     * @param int $len Number of bytes desired
1604
     * @param string $nonce Number to be used Once; must be 24 bytes
1605
     * @param string $key XSalsa20 key
1606
     * @return string       Pseudorandom stream that can be XORed with messages
1607
     *                      to provide encryption (but not authentication; see
1608
     *                      Poly1305 or crypto_auth() for that, which is not
1609
     *                      optional for security)
1610
     * @throws Error
1611
     * @throws TypeError
1612
     */
1613
    public static function crypto_stream($len, $nonce, $key)
1614
    {
1615
        /* Type checks: */
1616
        ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1);
1617
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1618
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1619
1620
        /* Input validation: */
1621
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
1622
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1623
        }
1624
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
1625
            throw new Error('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.');
1626
        }
1627
1628
        if (self::isPhp72OrGreater()) {
1629
            return sodium_crypto_stream($len, $nonce, $key);
1630
        }
1631
        if (self::use_fallback('crypto_stream')) {
1632
            return call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key);
1633
        }
1634
        if (PHP_INT_SIZE === 4) {
1635
            return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key);
1636
        }
1637
        return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key);
1638
    }
1639
1640
    /**
1641
     * DANGER! UNAUTHENTICATED ENCRYPTION!
1642
     *
1643
     * Unless you are following expert advice, do not used this feature.
1644
     *
1645
     * Algorithm: XSalsa20
1646
     *
1647
     * This DOES NOT provide ciphertext integrity.
1648
     *
1649
     * @param string $message Plaintext message
1650
     * @param string $nonce Number to be used Once; must be 24 bytes
1651
     * @param string $key Encryption key
1652
     * @return string         Encrypted text which is vulnerable to chosen-
1653
     *                        ciphertext attacks unless you implement some
1654
     *                        other mitigation to the ciphertext (i.e.
1655
     *                        Encrypt then MAC)
1656
     * @throws Error
1657
     * @throws TypeError
1658
     */
1659
    public static function crypto_stream_xor($message, $nonce, $key)
1660
    {
1661
        /* Type checks: */
1662
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
1663
        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1664
        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1665
1666
        /* Input validation: */
1667
        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
1668
            throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
1669
        }
1670
        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
1671
            throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
1672
        }
1673
1674
        if (self::isPhp72OrGreater()) {
1675
            return sodium_crypto_stream_xor($message, $nonce, $key);
1676
        }
1677
        if (self::use_fallback('crypto_stream_xor')) {
1678
            return call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key);
1679
        }
1680
        if (PHP_INT_SIZE === 4) {
1681
            return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key);
1682
        }
1683
        return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key);
1684
    }
1685
1686
    /**
1687
     * Returns a signed message. You probably want crypto_sign_detached()
1688
     * instead, which only returns the signature.
1689
     *
1690
     * Algorithm: Ed25519 (EdDSA over Curve25519)
1691
     *
1692
     * @param string $message Message to be signed.
1693
     * @param string $secretKey Secret signing key.
1694
     * @return string           Signed message (signature is prefixed).
1695
     * @throws Error
1696
     * @throws TypeError
1697
     */
1698
    public static function crypto_sign($message, $secretKey)
1699
    {
1700
        /* Type checks: */
1701
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
1702
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
1703
1704
        /* Input validation: */
1705
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
1706
            throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
1707
        }
1708
1709
        if (self::isPhp72OrGreater()) {
1710
            return sodium_crypto_sign($message, $secretKey);
1711
        }
1712
        if (self::use_fallback('crypto_sign')) {
1713
            return call_user_func('\\Sodium\\crypto_sign', $message, $secretKey);
1714
        }
1715
        if (PHP_INT_SIZE === 4) {
1716
            return ParagonIE_Sodium_Crypto32::sign($message, $secretKey);
1717
        }
1718
        return ParagonIE_Sodium_Crypto::sign($message, $secretKey);
1719
    }
1720
1721
    /**
1722
     * Validates a signed message then returns the message.
1723
     *
1724
     * @param string $signedMessage A signed message
1725
     * @param string $publicKey A public key
1726
     * @return string               The original message (if the signature is
1727
     *                              valid for this public key)
1728
     * @throws Error
1729
     * @throws TypeError
1730
     */
1731
    public static function crypto_sign_open($signedMessage, $publicKey)
1732
    {
1733
        /* Type checks: */
1734
        ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1);
1735
        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
1736
1737
        /* Input validation: */
1738
        if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) {
1739
            throw new Error('Argument 1 must be at least CRYPTO_SIGN_BYTES long.');
1740
        }
1741
        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
1742
            throw new Error('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
1743
        }
1744
1745
        if (self::isPhp72OrGreater()) {
1746
            return sodium_crypto_sign_open($signedMessage, $publicKey);
1747
        }
1748
        if (self::use_fallback('crypto_sign_open')) {
1749
            return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey);
1750
        }
1751
        if (PHP_INT_SIZE === 4) {
1752
            return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey);
1753
        }
1754
        return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey);
1755
    }
1756
1757
    /**
1758
     * Generate a new random Ed25519 keypair.
1759
     *
1760
     * @return string
1761
     */
1762
    public static function crypto_sign_keypair()
1763
    {
1764
        if (self::isPhp72OrGreater()) {
1765
            return sodium_crypto_sign_keypair();
1766
        }
1767
        if (self::use_fallback('crypto_sign_keypair')) {
1768
            return call_user_func(
1769
                '\\Sodium\\crypto_sign_keypair'
1770
            );
1771
        }
1772
        if (PHP_INT_SIZE === 4) {
1773
            return ParagonIE_Sodium_Core32_Ed25519::keypair();
1774
        }
1775
        return ParagonIE_Sodium_Core_Ed25519::keypair();
1776
    }
1777
1778
    /**
1779
     * Generate an Ed25519 keypair from a seed.
1780
     *
1781
     * @param string $seed Input seed
1782
     * @return string      Keypair
1783
     */
1784
    public static function crypto_sign_seed_keypair($seed)
1785
    {
1786
        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
1787
1788
        if (self::isPhp72OrGreater()) {
1789
            return sodium_crypto_sign_seed_keypair($seed);
1790
        }
1791
        if (self::use_fallback('crypto_sign_keypair')) {
1792
            return call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed);
1793
        }
1794
        $publicKey = '';
1795
        $secretKey = '';
1796
        if (PHP_INT_SIZE === 4) {
1797
            ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
1798
        } else {
1799
            ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
1800
        }
1801
        return $secretKey . $publicKey;
1802
    }
1803
1804
    /**
1805
     * Extract an Ed25519 public key from an Ed25519 keypair.
1806
     *
1807
     * @param string $keypair Keypair
1808
     * @return string         Public key
1809
     * @throws Error
1810
     * @throws TypeError
1811
     */
1812
    public static function crypto_sign_publickey($keypair)
1813
    {
1814
        /* Type checks: */
1815
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1816
1817
        /* Input validation: */
1818
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
1819
            throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
1820
        }
1821
1822
        if (self::isPhp72OrGreater()) {
1823
            return sodium_crypto_sign_publickey($keypair);
1824
        }
1825
        if (self::use_fallback('crypto_sign_publickey')) {
1826
            return call_user_func('\\Sodium\\crypto_sign_publickey', $keypair);
1827
        }
1828
        if (PHP_INT_SIZE === 4) {
1829
            return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair);
1830
        }
1831
        return ParagonIE_Sodium_Core_Ed25519::publickey($keypair);
1832
    }
1833
1834
    /**
1835
     * Calculate an Ed25519 public key from an Ed25519 secret key.
1836
     *
1837
     * @param string $secretKey Your Ed25519 secret key
1838
     * @return string           The corresponding Ed25519 public key
1839
     * @throws Error
1840
     * @throws TypeError
1841
     */
1842
    public static function crypto_sign_publickey_from_secretkey($secretKey)
1843
    {
1844
        /* Type checks: */
1845
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
1846
1847
        /* Input validation: */
1848
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
1849
            throw new Error('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
1850
        }
1851
1852
        if (self::isPhp72OrGreater()) {
1853
            return sodium_crypto_sign_publickey_from_secretkey($secretKey);
1854
        }
1855
        if (self::use_fallback('crypto_sign_publickey_from_secretkey')) {
1856
            return call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey);
1857
        }
1858
        if (PHP_INT_SIZE === 4) {
1859
            return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey);
1860
        }
1861
        return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey);
1862
    }
1863
1864
    /**
1865
     * Extract an Ed25519 secret key from an Ed25519 keypair.
1866
     *
1867
     * @param string $keypair Keypair
1868
     * @return string         Secret key
1869
     * @throws Error
1870
     * @throws TypeError
1871
     */
1872
    public static function crypto_sign_secretkey($keypair)
1873
    {
1874
        /* Type checks: */
1875
        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1876
1877
        /* Input validation: */
1878
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
1879
            throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
1880
        }
1881
1882
        if (self::isPhp72OrGreater()) {
1883
            return sodium_crypto_sign_secretkey($keypair);
1884
        }
1885
        if (self::use_fallback('crypto_sign_secretkey')) {
1886
            return call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair);
1887
        }
1888
        if (PHP_INT_SIZE === 4) {
1889
            return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair);
1890
        }
1891
        return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair);
1892
    }
1893
1894
    /**
1895
     * Calculate the Ed25519 signature of a message and return ONLY the signature.
1896
     *
1897
     * Algorithm: Ed25519 (EdDSA over Curve25519)
1898
     *
1899
     * @param string $message Message to be signed
1900
     * @param string $secretKey Secret signing key
1901
     * @return string           Digital signature
1902
     * @throws Error
1903
     * @throws TypeError
1904
     */
1905
    public static function crypto_sign_detached($message, $secretKey)
1906
    {
1907
        /* Type checks: */
1908
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
1909
        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
1910
1911
        /* Input validation: */
1912
        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
1913
            throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
1914
        }
1915
1916
        if (self::isPhp72OrGreater()) {
1917
            return sodium_crypto_sign_detached($message, $secretKey);
1918
        }
1919
        if (self::use_fallback('crypto_sign_detached')) {
1920
            return call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey);
1921
        }
1922
        if (PHP_INT_SIZE === 4) {
1923
            return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey);
1924
        }
1925
        return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey);
1926
    }
1927
1928
    /**
1929
     * Verify the Ed25519 signature of a message.
1930
     *
1931
     * @param string $signature Digital sginature
1932
     * @param string $message Message to be verified
1933
     * @param string $publicKey Public key
1934
     * @return bool             TRUE if this signature is good for this public key;
1935
     *                          FALSE otherwise
1936
     * @throws Error
1937
     * @throws TypeError
1938
     */
1939
    public static function crypto_sign_verify_detached($signature, $message, $publicKey)
1940
    {
1941
        /* Type checks: */
1942
        ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1);
1943
        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
1944
        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3);
1945
1946
        /* Input validation: */
1947
        if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) {
1948
            throw new Error('Argument 1 must be CRYPTO_SIGN_BYTES long.');
1949
        }
1950
        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
1951
            throw new Error('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
1952
        }
1953
1954
        if (self::isPhp72OrGreater()) {
1955
            return sodium_crypto_sign_verify_detached($signature, $message, $publicKey);
1956
        }
1957
        if (self::use_fallback('crypto_sign_verify_detached')) {
1958
            return call_user_func('\\Sodium\\crypto_sign_verify_detached', $signature, $message, $publicKey);
1959
        }
1960
        if (PHP_INT_SIZE === 4) {
1961
            return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey);
1962
        }
1963
        return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey);
1964
    }
1965
1966
    /**
1967
     * Convert an Ed25519 secret key to a Curve25519 secret key
1968
     *
1969
     * @param string $sk
1970
     * @return string
1971
     * @throws Error
1972
     */
1973
    public static function crypto_sign_ed25519_sk_to_curve25519($sk)
1974
    {
1975
        /* Type checks: */
1976
        ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
1977
1978
        /* Input validation: */
1979
        if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) {
1980
            throw new Error('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.');
1981
        }
1982
        if (self::isPhp72OrGreater()) {
1983
            if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) {
1984
                return sodium_crypto_sign_ed25519_sk_to_curve25519($sk);
1985
            }
1986
        }
1987
        if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) {
1988
            return call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk);
1989
        }
1990
1991
        $h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true);
1992
        $h[0] = ParagonIE_Sodium_Core_Util::intToChr(
1993
            ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248
1994
        );
1995
        $h[31] = ParagonIE_Sodium_Core_Util::intToChr(
1996
            (ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64
1997
        );
1998
        return ParagonIE_Sodium_Core_Util::substr($h, 0, 32);
1999
    }
2000
2001
    /**
2002
     * Cache-timing-safe implementation of hex2bin().
2003
     *
2004
     * @param string $string Hexadecimal string
2005
     * @return string        Raw binary string
2006
     * @throws TypeError
2007
     */
2008
    public static function hex2bin($string)
2009
    {
2010
        /* Type checks: */
2011
        ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
2012
2013
        if (self::isPhp72OrGreater()) {
2014
            return sodium_hex2bin($string);
2015
        }
2016
        if (self::use_fallback('hex2bin')) {
2017
            return call_user_func('\\Sodium\\hex2bin', $string);
2018
        }
2019
        return ParagonIE_Sodium_Core_Util::hex2bin($string);
2020
    }
2021
2022
    /**
2023
     * Increase a string (little endian)
2024
     *
2025
     * @param string $var
2026
     *
2027
     * @return void
2028
     * @throws Error (Unless libsodium is installed)
2029
     */
2030
    public static function increment(&$var)
2031
    {
2032
        /* Type checks: */
2033
        ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
2034
2035
        if (self::isPhp72OrGreater()) {
2036
            sodium_increment($var);
2037
            return;
2038
        }
2039
        if (self::use_fallback('increment')) {
2040
            @call_user_func('\\Sodium\\increment', $var);
2041
            return;
2042
        }
2043
2044
        $len = ParagonIE_Sodium_Core_Util::strlen($var);
2045
        $c = 1;
2046
        $copy = '';
2047
        for ($i = 0; $i < $len; ++$i) {
2048
            $c += ParagonIE_Sodium_Core_Util::chrToInt(
2049
                ParagonIE_Sodium_Core_Util::substr($var, $i, 1)
2050
            );
2051
            $copy .= ParagonIE_Sodium_Core_Util::intToChr($c);
2052
            $c >>= 8;
2053
        }
2054
        $var = $copy;
2055
    }
2056
2057
    /**
2058
     * The equivalent to the libsodium minor version we aim to be compatible
2059
     * with (sans pwhash and memzero).
2060
     *
2061
     * @return int
2062
     */
2063
    public static function library_version_major()
2064
    {
2065
        if (self::isPhp72OrGreater()) {
2066
            return sodium_library_version_major();
2067
        }
2068
        if (self::use_fallback('library_version_major')) {
2069
            return (int) call_user_func('\\Sodium\\library_version_major');
2070
        }
2071
        return self::LIBRARY_VERSION_MAJOR;
2072
    }
2073
2074
    /**
2075
     * The equivalent to the libsodium minor version we aim to be compatible
2076
     * with (sans pwhash and memzero).
2077
     *
2078
     * @return int
2079
     */
2080
    public static function library_version_minor()
2081
    {
2082
        if (self::isPhp72OrGreater()) {
2083
            return sodium_library_version_minor();
2084
        }
2085
        if (self::use_fallback('library_version_minor')) {
2086
            return (int) call_user_func('\\Sodium\\library_version_minor');
2087
        }
2088
        return self::LIBRARY_VERSION_MINOR;
2089
    }
2090
2091
    /**
2092
     * Compare two strings.
2093
     *
2094
     * @param string $left
2095
     * @param string $right
2096
     * @return int
2097
     * @throws TypeError
2098
     */
2099
    public static function memcmp($left, $right)
2100
    {
2101
        /* Type checks: */
2102
        ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
2103
        ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
2104
2105
        if (self::use_fallback('memcmp')) {
2106
            return call_user_func('\\Sodium\\memcmp', $left, $right);
2107
        }
2108
        return ParagonIE_Sodium_Core_Util::memcmp($left, $right);
2109
    }
2110
2111
    /**
2112
     * It's actually not possible to zero memory buffers in PHP. You need the
2113
     * native library for that.
2114
     *
2115
     * @param string|null $var
2116
     *
2117
     * @return void
2118
     * @throws Error (Unless libsodium is installed)
2119
     */
2120
    public static function memzero(&$var)
2121
    {
2122
        /* Type checks: */
2123
        ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
2124
2125
        if (self::isPhp72OrGreater()) {
2126
            sodium_memzero($var);
2127
            return;
2128
        }
2129
        if (self::use_fallback('memzero')) {
2130
            @call_user_func('\\Sodium\\memzero', $var);
2131
            return;
2132
        }
2133
        // This is the best we can do.
2134
        throw new Error(
2135
            'This is not implemented, as it is not possible to securely wipe memory from PHP'
2136
        );
2137
    }
2138
2139
    /**
2140
     * Generate a string of bytes from the kernel's CSPRNG.
2141
     * Proudly uses /dev/urandom (if getrandom(2) is not available).
2142
     *
2143
     * @param int $numBytes
2144
     * @return string
2145
     * @throws TypeError
2146
     */
2147
    public static function randombytes_buf($numBytes)
2148
    {
2149
        /* Type checks: */
2150
        if (!is_int($numBytes)) {
2151
            if (is_numeric($numBytes)) {
2152
                $numBytes = (int)$numBytes;
2153
            } else {
2154
                throw new TypeError('Argument 1 must be an integer, ' . gettype($numBytes) . ' given.');
2155
            }
2156
        }
2157
        if (self::use_fallback('randombytes_buf')) {
2158
            return call_user_func('\\Sodium\\randombytes_buf', $numBytes);
2159
        }
2160
        return random_bytes($numBytes);
2161
    }
2162
2163
    /**
2164
     * Generate an integer between 0 and $range (non-inclusive).
2165
     *
2166
     * @param int $range
2167
     * @return int
2168
     * @throws TypeError
2169
     */
2170
    public static function randombytes_uniform($range)
2171
    {
2172
        /* Type checks: */
2173
        if (!is_int($range)) {
2174
            if (is_numeric($range)) {
2175
                $range = (int)$range;
2176
            } else {
2177
                throw new TypeError('Argument 1 must be an integer, ' . gettype($range) . ' given.');
2178
            }
2179
        }
2180
        if (self::use_fallback('randombytes_uniform')) {
2181
            return (int) call_user_func('\\Sodium\\randombytes_uniform', $range);
2182
        }
2183
        return random_int(0, $range - 1);
2184
    }
2185
2186
    /**
2187
     * Generate a random 16-bit integer.
2188
     *
2189
     * @return int
2190
     */
2191
    public static function randombytes_random16()
2192
    {
2193
        if (self::use_fallback('randombytes_random16')) {
2194
            return (int) call_user_func('\\Sodium\\randombytes_random16');
2195
        }
2196
        return random_int(0, 65535);
2197
    }
2198
2199
    /**
2200
     * This emulates libsodium's version_string() function, except ours is
2201
     * prefixed with 'polyfill-'.
2202
     *
2203
     * @return string
2204
     */
2205
    public static function version_string()
2206
    {
2207
        if (self::isPhp72OrGreater()) {
2208
            return sodium_version_string();
2209
        }
2210
        if (self::use_fallback('version_string')) {
2211
            return (string) call_user_func('\\Sodium\\version_string');
2212
        }
2213
        return self::VERSION_STRING;
2214
    }
2215
2216
    /**
2217
     * Should we use the libsodium core function instead?
2218
     * This is always a good idea, if it's available. (Unless we're in the
2219
     * middle of running our unit test suite.)
2220
     *
2221
     * If ext/libsodium is available, use it. Return TRUE.
2222
     * Otherwise, we have to use the code provided herein. Return FALSE.
2223
     *
2224
     * @param string $sodium_func_name
2225
     *
2226
     * @return bool
2227
     */
2228
    protected static function use_fallback($sodium_func_name = '')
2229
    {
2230
        static $res = null;
2231
        if ($res === null) {
2232
            $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300;
2233
        }
2234
        if (PHP_INT_SIZE === 4) {
2235
            if ($res && is_callable('\\Sodium\\' . $sodium_func_name)) {
2236
                // We can safely just offload to the PECL extension
2237
                return true;
2238
            }
2239
            /*
2240
            if (DIRECTORY_SEPARATOR === '\\' && PHP_VERSION_ID < 70000) {
2241
                throw new RuntimeException(
2242
                    'Sodium_compat produces incorrect results on systems that do not support 64-bit integers. ' .
2243
                    'Please upgrade to PHP 7 or newer for Windows x64 support.'
2244
                );
2245
            }
2246
            throw new RuntimeException(
2247
                'Sodium_compat produces incorrect results on systems that do not support 64-bit integers.'
2248
            );
2249
            */
2250
        }
2251
        if ($res === false) {
2252
            // No libsodium installed
2253
            return false;
2254
        }
2255
        if (self::$disableFallbackForUnitTests) {
2256
            // Don't fallback. Use the PHP implementation.
2257
            return false;
2258
        }
2259
        if (!empty($sodium_func_name)) {
2260
            return is_callable('\\Sodium\\' . $sodium_func_name);
2261
        }
2262
        return true;
2263
    }
2264
2265
    /**
2266
     * Libsodium as implemented in PHP 7.2
2267
     *
2268
     * @ref https://wiki.php.net/rfc/libsodium
2269
     * @return bool
2270
     */
2271
    protected static function isPhp72OrGreater()
2272
    {
2273
        static $res = null;
2274
        if ($res === null) {
2275
            $res = PHP_VERSION_ID >= 70200 && extension_loaded('sodium');
2276
        }
2277
        if (self::$disableFallbackForUnitTests) {
2278
            // Don't fallback. Use the PHP implementation.
2279
            return false;
2280
        }
2281
        return $res;
2282
    }
2283
}
2284