Completed
Push — develop ( f0d100...266ee2 )
by J.D.
04:14
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

62 Methods

Rating   Name   Duplication   Size   Complexity  
A bin2hex() 13 13 3
A compare() 14 14 3
B crypto_aead_chacha20poly1305_decrypt() 55 55 7
B crypto_aead_chacha20poly1305_encrypt() 52 52 6
B crypto_aead_chacha20poly1305_ietf_decrypt() 55 55 7
B crypto_aead_chacha20poly1305_ietf_encrypt() 52 52 6
B crypto_aead_xchacha20poly1305_ietf_decrypt() 0 38 5
B crypto_aead_xchacha20poly1305_ietf_encrypt() 0 35 4
B crypto_auth() 22 22 5
B crypto_auth_verify() 26 26 6
B crypto_box() 26 26 6
B crypto_box_seal() 22 22 5
B crypto_box_seal_open() 22 22 5
A crypto_box_keypair() 0 10 3
B crypto_box_keypair_from_secretkey_and_publickey() 25 25 6
C crypto_box_open() 0 29 7
B crypto_box_publickey() 21 21 5
B crypto_box_publickey_from_secretkey() 21 21 5
B crypto_box_secretkey() 21 21 5
A crypto_box_seed_keypair() 13 13 3
C crypto_generichash() 8 31 8
B crypto_generichash_final() 0 25 5
C crypto_generichash_init() 8 30 8
A crypto_generichash_update() 21 21 4
B crypto_kx() 0 56 9
A crypto_pwhash() 19 19 3
A crypto_pwhash_str() 17 17 3
A crypto_pwhash_str_verify() 16 16 3
A crypto_pwhash_scryptsalsa208sha256() 19 19 3
A crypto_pwhash_scryptsalsa208sha256_str() 17 17 3
A crypto_pwhash_scryptsalsa208sha256_str_verify() 16 16 3
C crypto_scalarmult() 0 33 8
B crypto_scalarmult_base() 0 24 6
B crypto_secretbox() 26 26 6
B crypto_secretbox_open() 26 26 6
A crypto_secretbox_xchacha20poly1305() 19 19 4
A crypto_secretbox_xchacha20poly1305_open() 20 20 4
B crypto_shorthash() 22 22 5
B crypto_stream() 26 26 6
B crypto_stream_xor() 26 26 6
B crypto_sign() 22 22 5
B crypto_sign_open() 25 25 6
A crypto_sign_keypair() 0 15 4
A crypto_sign_seed_keypair() 19 19 4
B crypto_sign_publickey() 21 21 5
B crypto_sign_publickey_from_secretkey() 21 21 5
B crypto_sign_secretkey() 21 21 5
B crypto_sign_detached() 22 22 5
B crypto_sign_verify_detached() 26 26 6
B crypto_sign_ed25519_sk_to_curve25519() 0 27 5
A hex2bin() 13 13 3
B increment() 0 26 4
A library_version_major() 0 10 3
A library_version_minor() 0 10 3
A memcmp() 0 11 2
A memzero() 18 18 3
A randombytes_buf() 15 15 4
A randombytes_uniform() 15 15 4
A randombytes_random16() 0 7 2
A version_string() 0 10 3
D use_fallback() 0 36 9
A isPhp72OrGreater() 0 12 4

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 View Code Duplication
    public static function bin2hex($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function compare($left, $right)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_aead_chacha20poly1305_decrypt(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_aead_chacha20poly1305_encrypt(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_aead_chacha20poly1305_ietf_decrypt(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_aead_chacha20poly1305_ietf_encrypt(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_auth($message, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_auth_verify($mac, $message, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box($plaintext, $nonce, $keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_seal($plaintext, $publicKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_seal_open($ciphertext, $keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_publickey($keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_publickey_from_secretkey($secretKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_secretkey($keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_box_seed_keypair($seed)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if (!empty($key)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
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 View Code Duplication
        if (!empty($key)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_generichash_update(&$ctx, $message)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash_str($passwd, $opslimit, $memlimit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash_str_verify($passwd, $hash)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_secretbox($plaintext, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_secretbox_open($ciphertext, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_shorthash($message, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_stream($len, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_stream_xor($message, $nonce, $key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign($message, $secretKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_open($signedMessage, $publicKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_seed_keypair($seed)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_publickey($keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_publickey_from_secretkey($secretKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_secretkey($keypair)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_detached($message, $secretKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function crypto_sign_verify_detached($signature, $message, $publicKey)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function hex2bin($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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 View Code Duplication
    public static function memzero(&$var)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
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 View Code Duplication
    public static function randombytes_buf($numBytes)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
    public static function randombytes_uniform($range)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
            /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
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