Completed
Push — develop ( f0d100...266ee2 )
by J.D.
04:14
created

ParagonIE_Sodium_Crypto   D

Complexity

Total Complexity 65

Size/Duplication

Total Lines 1175
Duplicated Lines 55.74 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 655
loc 1175
rs 4.8421
c 0
b 0
f 0
wmc 65
lcom 1
cbo 11

35 Methods

Rating   Name   Duplication   Size   Complexity  
A aead_chacha20poly1305_decrypt() 58 58 3
B aead_chacha20poly1305_encrypt() 39 39 2
A aead_chacha20poly1305_ietf_decrypt() 64 64 3
B aead_chacha20poly1305_ietf_encrypt() 41 41 2
A aead_xchacha20poly1305_ietf_decrypt() 0 15 1
A aead_xchacha20poly1305_ietf_encrypt() 15 15 1
A auth() 0 8 1
A auth_verify() 0 7 1
A box() 12 12 1
B box_seal() 34 34 2
B box_seal_open() 37 37 2
A box_beforenm() 0 7 1
A box_keypair() 0 6 1
A box_seed_keypair() 0 10 1
A box_keypair_from_secretkey_and_publickey() 0 5 1
A box_secretkey() 7 7 2
A box_publickey() 7 7 2
A box_publickey_from_secretkey() 0 7 2
A box_open() 0 11 1
B generichash() 29 29 3
A generichash_final() 17 17 2
A generichash_init() 18 18 3
A generichash_update() 15 15 1
A keyExchange() 0 8 1
A scalarmult() 0 6 1
A scalarmult_base() 0 6 1
A scalarmult_throw_if_zero() 12 12 3
B secretbox() 62 62 4
B secretbox_open() 60 60 4
B secretbox_xchacha20poly1305() 66 66 4
B secretbox_xchacha20poly1305_open() 62 62 4
A sign_detached() 0 4 1
A sign() 0 4 1
A sign_open() 0 4 1
A sign_verify_detached() 0 4 1

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_Crypto 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_Crypto, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
if (class_exists('ParagonIE_Sodium_Crypto', false)) {
4
    return;
5
}
6
7
/**
8
 * Class ParagonIE_Sodium_Crypto
9
 *
10
 * ATTENTION!
11
 *
12
 * If you are using this library, you should be using
13
 * ParagonIE_Sodium_Compat in your code, not this class.
14
 */
15
abstract class ParagonIE_Sodium_Crypto
16
{
17
    const aead_chacha20poly1305_KEYBYTES = 32;
18
    const aead_chacha20poly1305_NSECBYTES = 0;
19
    const aead_chacha20poly1305_NPUBBYTES = 8;
20
    const aead_chacha20poly1305_ABYTES = 16;
21
22
    const aead_chacha20poly1305_IETF_KEYBYTES = 32;
23
    const aead_chacha20poly1305_IETF_NSECBYTES = 0;
24
    const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
25
    const aead_chacha20poly1305_IETF_ABYTES = 16;
26
27
    const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
28
    const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
29
    const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
30
    const aead_xchacha20poly1305_IETF_ABYTES = 16;
31
32
    const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
33
    const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
34
    const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
35
    const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
36
    const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
37
    const box_curve25519xsalsa20poly1305_MACBYTES = 16;
38
    const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
39
    const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
40
41
    const onetimeauth_poly1305_BYTES = 16;
42
    const onetimeauth_poly1305_KEYBYTES = 32;
43
44
    const secretbox_xsalsa20poly1305_KEYBYTES = 32;
45
    const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
46
    const secretbox_xsalsa20poly1305_MACBYTES = 16;
47
    const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
48
    const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
49
50
    const secretbox_xchacha20poly1305_KEYBYTES = 32;
51
    const secretbox_xchacha20poly1305_NONCEBYTES = 24;
52
    const secretbox_xchacha20poly1305_MACBYTES = 16;
53
    const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
54
    const secretbox_xchacha20poly1305_ZEROBYTES = 32;
55
56
    const stream_salsa20_KEYBYTES = 32;
57
58
    /**
59
     * AEAD Decryption with ChaCha20-Poly1305
60
     *
61
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
62
     *
63
     * @param string $message
64
     * @param string $ad
65
     * @param string $nonce
66
     * @param string $key
67
     * @return string
68
     * @throws Error
69
     */
70 View Code Duplication
    public static function 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...
71
        $message = '',
72
        $ad = '',
73
        $nonce = '',
74
        $key = ''
75
    ) {
76
        /** @var int $len - Length of message (ciphertext + MAC) */
77
        $len = ParagonIE_Sodium_Core_Util::strlen($message);
78
79
        /** @var int  $clen - Length of ciphertext */
80
        $clen = $len - self::aead_chacha20poly1305_ABYTES;
81
82
        /** @var int $adlen - Length of associated data */
83
        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
84
85
        /** @var string $mac - Message authentication code */
86
        $mac = ParagonIE_Sodium_Core_Util::substr(
87
            $message,
88
            $clen,
89
            self::aead_chacha20poly1305_ABYTES
90
        );
91
92
        /** @var string $ciphertext - The encrypted message (sans MAC) */
93
        $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 0, $clen);
94
95
        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
96
        $block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
97
            32,
98
            $nonce,
99
            $key
100
        );
101
102
        /* Recalculate the Poly1305 authentication tag (MAC): */
103
        $state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
104
        try {
105
            ParagonIE_Sodium_Compat::memzero($block0);
106
        } 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...
107
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
108
        }
109
        $state->update($ad);
110
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
111
        $state->update($ciphertext);
112
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
113
        $computed_mac = $state->finish();
114
115
        /* Compare the given MAC with the recalculated MAC: */
116
        if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
117
            throw new Error('Invalid MAC');
118
        }
119
120
        // Here, we know that the MAC is valid, so we decrypt and return the plaintext
121
        return ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
122
            $ciphertext,
123
            $nonce,
124
            $key,
125
            ParagonIE_Sodium_Core_Util::store64_le(1)
126
        );
127
    }
128
129
    /**
130
     * AEAD Encryption with ChaCha20-Poly1305
131
     *
132
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
133
     *
134
     * @param string $message
135
     * @param string $ad
136
     * @param string $nonce
137
     * @param string $key
138
     * @return string
139
     */
140 View Code Duplication
    public static function 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...
141
        $message = '',
142
        $ad = '',
143
        $nonce = '',
144
        $key = ''
145
    ) {
146
        /** @var int $len - Length of the plaintext message */
147
        $len = ParagonIE_Sodium_Core_Util::strlen($message);
148
149
        /** @var int $adlen - Length of the associated data */
150
        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
151
152
        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
153
        $block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
154
            32,
155
            $nonce,
156
            $key
157
        );
158
        $state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
159
        try {
160
            ParagonIE_Sodium_Compat::memzero($block0);
161
        } 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...
162
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
163
        }
164
165
        /** @var string $ciphertext - Raw encrypted data */
166
        $ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
167
            $message,
168
            $nonce,
169
            $key,
170
            ParagonIE_Sodium_Core_Util::store64_le(1)
171
        );
172
173
        $state->update($ad);
174
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
175
        $state->update($ciphertext);
176
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
177
        return $ciphertext . $state->finish();
178
    }
179
180
    /**
181
     * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
182
     *
183
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
184
     *
185
     * @param string $message
186
     * @param string $ad
187
     * @param string $nonce
188
     * @param string $key
189
     * @return string
190
     * @throws Error
191
     */
192 View Code Duplication
    public static function 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...
193
        $message = '',
194
        $ad = '',
195
        $nonce = '',
196
        $key = ''
197
    ) {
198
        /** @var int $adlen - Length of associated data */
199
        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
200
201
        /** @var int $len - Length of message (ciphertext + MAC) */
202
        $len = ParagonIE_Sodium_Core_Util::strlen($message);
203
204
        /** @var int  $clen - Length of ciphertext */
205
        $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
206
207
        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
208
        $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
209
            32,
210
            $nonce,
211
            $key
212
        );
213
214
        /** @var string $mac - Message authentication code */
215
        $mac = ParagonIE_Sodium_Core_Util::substr(
216
            $message,
217
            $len - self::aead_chacha20poly1305_IETF_ABYTES,
218
            self::aead_chacha20poly1305_IETF_ABYTES
219
        );
220
221
        /** @var string $ciphertext - The encrypted message (sans MAC) */
222
        $ciphertext = ParagonIE_Sodium_Core_Util::substr(
223
            $message,
224
            0,
225
            $len - self::aead_chacha20poly1305_IETF_ABYTES
226
        );
227
228
        /* Recalculate the Poly1305 authentication tag (MAC): */
229
        $state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
230
        try {
231
            ParagonIE_Sodium_Compat::memzero($block0);
232
        } 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...
233
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
234
        }
235
        $state->update($ad);
236
        $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
237
        $state->update($ciphertext);
238
        $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf));
239
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
240
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen));
241
        $computed_mac = $state->finish();
242
243
        /* Compare the given MAC with the recalculated MAC: */
244
        if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) {
245
            throw new Error('Invalid MAC');
246
        }
247
248
        // Here, we know that the MAC is valid, so we decrypt and return the plaintext
249
        return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
250
            $ciphertext,
251
            $nonce,
252
            $key,
253
            ParagonIE_Sodium_Core_Util::store64_le(1)
254
        );
255
    }
256
257
    /**
258
     * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
259
     *
260
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
261
     *
262
     * @param string $message
263
     * @param string $ad
264
     * @param string $nonce
265
     * @param string $key
266
     * @return string
267
     */
268 View Code Duplication
    public static function 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...
269
        $message = '',
270
        $ad = '',
271
        $nonce = '',
272
        $key = ''
273
    ) {
274
        /** @var int $len - Length of the plaintext message */
275
        $len = ParagonIE_Sodium_Core_Util::strlen($message);
276
277
        /** @var int $adlen - Length of the associated data */
278
        $adlen = ParagonIE_Sodium_Core_Util::strlen($ad);
279
280
        /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
281
        $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream(
282
            32,
283
            $nonce,
284
            $key
285
        );
286
        $state = new ParagonIE_Sodium_Core_Poly1305_State($block0);
287
        try {
288
            ParagonIE_Sodium_Compat::memzero($block0);
289
        } 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...
290
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
291
        }
292
293
        /** @var string $ciphertext - Raw encrypted data */
294
        $ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
295
            $message,
296
            $nonce,
297
            $key,
298
            ParagonIE_Sodium_Core_Util::store64_le(1)
299
        );
300
301
        $state->update($ad);
302
        $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
303
        $state->update($ciphertext);
304
        $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf)));
305
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen));
306
        $state->update(ParagonIE_Sodium_Core_Util::store64_le($len));
307
        return $ciphertext . $state->finish();
308
    }
309
310
    /**
311
     * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
312
     *
313
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
314
     *
315
     * @param string $message
316
     * @param string $ad
317
     * @param string $nonce
318
     * @param string $key
319
     * @return string
320
     * @throws Error
321
     */
322
    public static function aead_xchacha20poly1305_ietf_decrypt(
323
        $message = '',
324
        $ad = '',
325
        $nonce = '',
326
        $key = ''
327
    ) {
328
        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
329
            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
330
            $key
331
        );
332
        $nonceLast = "\x00\x00\x00\x00" .
333
            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
334
335
        return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
336
    }
337
338
    /**
339
     * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
340
     *
341
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
342
     *
343
     * @param string $message
344
     * @param string $ad
345
     * @param string $nonce
346
     * @param string $key
347
     * @return string
348
     */
349 View Code Duplication
    public static function aead_xchacha20poly1305_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...
350
        $message = '',
351
        $ad = '',
352
        $nonce = '',
353
        $key = ''
354
    ) {
355
        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
356
            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
357
            $key
358
        );
359
        $nonceLast = "\x00\x00\x00\x00" .
360
            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
361
362
        return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
363
    }
364
365
    /**
366
     * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
367
     *
368
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
369
     *
370
     * @param string $message
371
     * @param string $key
372
     * @return string
373
     */
374
    public static function auth($message, $key)
375
    {
376
        return ParagonIE_Sodium_Core_Util::substr(
377
            hash_hmac('sha512', $message, $key, true),
378
            0,
379
            32
380
        );
381
    }
382
383
    /**
384
     * HMAC-SHA-512-256 validation. Constant-time via hash_equals().
385
     *
386
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
387
     *
388
     * @param string $mac
389
     * @param string $message
390
     * @param string $key
391
     * @return bool
392
     */
393
    public static function auth_verify($mac, $message, $key)
394
    {
395
        return ParagonIE_Sodium_Core_Util::hashEquals(
396
            $mac,
397
            self::auth($message, $key)
398
        );
399
    }
400
401
    /**
402
     * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
403
     *
404
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
405
     *
406
     * @param string $plaintext
407
     * @param string $nonce
408
     * @param string $keypair
409
     * @return string
410
     */
411 View Code Duplication
    public static function 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...
412
    {
413
        $c = self::secretbox(
414
            $plaintext,
415
            $nonce,
416
            self::box_beforenm(
417
                self::box_secretkey($keypair),
418
                self::box_publickey($keypair)
419
            )
420
        );
421
        return $c;
422
    }
423
424
    /**
425
     * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
426
     *
427
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
428
     *
429
     * @param string $message
430
     * @param string $publicKey
431
     * @return string
432
     */
433 View Code Duplication
    public static function box_seal($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...
434
    {
435
        /** @var string $ephemeralKeypair */
436
        $ephemeralKeypair = self::box_keypair();
437
438
        /** @var string $ephemeralSK */
439
        $ephemeralSK = self::box_secretkey($ephemeralKeypair);
440
441
        /** @var string $ephemeralPK */
442
        $ephemeralPK = self::box_publickey($ephemeralKeypair);
443
444
        /** @var string $nonce */
445
        $nonce = self::generichash(
446
            $ephemeralPK . $publicKey,
447
            '',
448
            24
449
        );
450
451
        /** @var string $keypair - The combined keypair used in crypto_box() */
452
        $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
453
454
        /** @var string $ciphertext Ciphertext + MAC from crypto_box */
455
        $ciphertext = self::box($message, $nonce, $keypair);
456
        try {
457
            ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
458
            ParagonIE_Sodium_Compat::memzero($ephemeralSK);
459
            ParagonIE_Sodium_Compat::memzero($nonce);
460
        } 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...
461
            $ephemeralKeypair = null;
0 ignored issues
show
Unused Code introduced by
$ephemeralKeypair is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
462
            $ephemeralSK = null;
0 ignored issues
show
Unused Code introduced by
$ephemeralSK is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
463
            $nonce = null;
0 ignored issues
show
Unused Code introduced by
$nonce is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
464
        }
465
        return $ephemeralPK . $ciphertext;
466
    }
467
468
    /**
469
     * Opens a message encrypted via box_seal().
470
     *
471
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
472
     *
473
     * @param string $message
474
     * @param string $keypair
475
     * @return string
476
     */
477 View Code Duplication
    public static function box_seal_open($message, $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...
478
    {
479
        /** @var string $ephemeralPK */
480
        $ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32);
481
482
        /** @var string $ciphertext (ciphertext + MAC) */
483
        $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32);
484
485
        /** @var string $secretKey */
486
        $secretKey = self::box_secretkey($keypair);
487
488
        /** @var string $publicKey */
489
        $publicKey = self::box_publickey($keypair);
490
491
        /** @var string $nonce */
492
        $nonce = self::generichash(
493
            $ephemeralPK . $publicKey,
494
            '',
495
            24
496
        );
497
498
        /** @var string $keypair */
499
        $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
500
501
        /** @var string $m */
502
        $m = self::box_open($ciphertext, $nonce, $keypair);
503
        try {
504
            ParagonIE_Sodium_Compat::memzero($secretKey);
505
            ParagonIE_Sodium_Compat::memzero($ephemeralPK);
506
            ParagonIE_Sodium_Compat::memzero($nonce);
507
        } 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...
508
            $secretKey = null;
0 ignored issues
show
Unused Code introduced by
$secretKey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
509
            $ephemeralPK = null;
0 ignored issues
show
Unused Code introduced by
$ephemeralPK is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
510
            $nonce = null;
0 ignored issues
show
Unused Code introduced by
$nonce is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
511
        }
512
        return $m;
513
    }
514
515
    /**
516
     * Used by crypto_box() to get the crypto_secretbox() key.
517
     *
518
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
519
     *
520
     * @param string $sk
521
     * @param string $pk
522
     * @return string
523
     */
524
    public static function box_beforenm($sk, $pk)
525
    {
526
        return ParagonIE_Sodium_Core_HSalsa20::hsalsa20(
527
            str_repeat("\x00", 16),
528
            self::scalarmult($sk, $pk)
529
        );
530
    }
531
532
    /**
533
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
534
     *
535
     * @return string
536
     */
537
    public static function box_keypair()
538
    {
539
        $sKey = random_bytes(32);
540
        $pKey = self::scalarmult_base($sKey);
541
        return $sKey . $pKey;
542
    }
543
544
    /**
545
     * @param string $seed
546
     * @return string
547
     */
548
    public static function box_seed_keypair($seed)
549
    {
550
        $sKey = ParagonIE_Sodium_Core_Util::substr(
551
            hash('sha512', $seed, true),
552
            0,
553
            32
554
        );
555
        $pKey = self::scalarmult_base($sKey);
556
        return $sKey . $pKey;
557
    }
558
559
    /**
560
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
561
     *
562
     * @param string $sKey
563
     * @param string $pKey
564
     * @return string
565
     */
566
    public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
567
    {
568
        return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) .
569
            ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32);
570
    }
571
572
    /**
573
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
574
     *
575
     * @param string $keypair
576
     * @return string
577
     * @throws RangeException
578
     */
579 View Code Duplication
    public static function 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...
580
    {
581
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) {
582
            throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.');
583
        }
584
        return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32);
585
    }
586
587
    /**
588
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
589
     *
590
     * @param string $keypair
591
     * @return string
592
     * @throws RangeException
593
     */
594 View Code Duplication
    public static function 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...
595
    {
596
        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
597
            throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.');
598
        }
599
        return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32);
600
    }
601
602
    /**
603
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
604
     *
605
     * @param string $sKey
606
     * @return string
607
     * @throws RangeException
608
     */
609
    public static function box_publickey_from_secretkey($sKey)
610
    {
611
        if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
612
            throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.');
613
        }
614
        return self::scalarmult_base($sKey);
615
    }
616
617
    /**
618
     * Decrypt a message encrypted with box().
619
     *
620
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
621
     *
622
     * @param string $ciphertext
623
     * @param string $nonce
624
     * @param string $nonce
625
     * @param string $keypair
626
     * @return string
627
     */
628
    public static function box_open($ciphertext, $nonce, $keypair)
629
    {
630
        return self::secretbox_open(
631
            $ciphertext,
632
            $nonce,
633
            self::box_beforenm(
634
                self::box_secretkey($keypair),
635
                self::box_publickey($keypair)
636
            )
637
        );
638
    }
639
640
    /**
641
     * Calculate a BLAKE2b hash.
642
     *
643
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
644
     *
645
     * @param string $message
646
     * @param string|null $key
647
     * @param int $outlen
648
     * @return string
649
     * @throws RangeException
650
     */
651 View Code Duplication
    public static function generichash($message, $key = '', $outlen = 32)
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...
652
    {
653
        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
654
        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
655
656
        $k = null;
657
        if (!empty($key)) {
658
            /** @var SplFixedArray $k */
659
            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
660
            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
661
                throw new RangeException('Invalid key size');
662
            }
663
        }
664
665
        /** @var SplFixedArray $in */
666
        $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
667
668
        /** @var SplFixedArray $ctx */
669
        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen);
670
        ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count());
671
672
        /** @var SplFixedArray $out */
673
        $out = new SplFixedArray($outlen);
674
        $out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out);
675
676
        /** @var array<int, int> */
677
        $outArray = $out->toArray();
678
        return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
679
    }
680
681
    /**
682
     * Finalize a BLAKE2b hashing context, returning the hash.
683
     *
684
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
685
     *
686
     * @param string $ctx
687
     * @param int $outlen
688
     * @return string
689
     * @throws TypeError
690
     */
691 View Code Duplication
    public static function generichash_final($ctx, $outlen = 32)
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...
692
    {
693
        if (!is_string($ctx)) {
694
            throw new TypeError('Context must be a string');
695
        }
696
        $out = new SplFixedArray($outlen);
697
698
        /** @var SplFixedArray $context */
699
        $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
700
701
        /** @var SplFixedArray $out */
702
        $out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out);
703
704
        /** @var array<int, int> */
705
        $outArray = $out->toArray();
706
        return ParagonIE_Sodium_Core_Util::intArrayToString($outArray);
707
    }
708
709
    /**
710
     * Initialize a hashing context for BLAKE2b.
711
     *
712
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
713
     *
714
     * @param string $key
715
     * @param int $outputLength
716
     * @return string
717
     * @throws RangeException
718
     */
719 View Code Duplication
    public static function generichash_init($key = '', $outputLength = 32)
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...
720
    {
721
        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
722
        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
723
724
        $k = null;
725
        if (!empty($key)) {
726
            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
727
            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
728
                throw new RangeException('Invalid key size');
729
            }
730
        }
731
732
        /** @var SplFixedArray $ctx */
733
        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength);
734
735
        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
736
    }
737
738
    /**
739
     * Update a hashing context for BLAKE2b with $message
740
     *
741
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
742
     *
743
     * @param string $ctx
744
     * @param string $message
745
     * @return string
746
     */
747 View Code Duplication
    public static function 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...
748
    {
749
        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
750
        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
751
752
        /** @var SplFixedArray $context */
753
        $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx);
754
755
        /** @var SplFixedArray $in */
756
        $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message);
757
758
        ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count());
759
760
        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context);
761
    }
762
763
    /**
764
     * Libsodium's crypto_kx().
765
     *
766
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
767
     *
768
     * @param string $my_sk
769
     * @param string $their_pk
770
     * @param string $client_pk
771
     * @param string $server_pk
772
     * @return string
773
     */
774
    public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
775
    {
776
        return self::generichash(
777
            self::scalarmult($my_sk, $their_pk) .
778
            $client_pk .
779
            $server_pk
780
        );
781
    }
782
783
    /**
784
     * ECDH over Curve25519
785
     *
786
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
787
     *
788
     * @param string $sKey
789
     * @param string $pKey
790
     * @return string
791
     *
792
     * @throws Error
793
     */
794
    public static function scalarmult($sKey, $pKey)
795
    {
796
        $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
797
        self::scalarmult_throw_if_zero($q);
798
        return $q;
799
    }
800
801
    /**
802
     * ECDH over Curve25519, using the basepoint.
803
     * Used to get a secret key from a public key.
804
     *
805
     * @param string $secret
806
     * @return string
807
     *
808
     * @throws Error
809
     */
810
    public static function scalarmult_base($secret)
811
    {
812
        $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
813
        self::scalarmult_throw_if_zero($q);
814
        return $q;
815
    }
816
817
    /**
818
     * This throws an Error if a zero public key was passed to the function.
819
     *
820
     * @param string $q
821
     * @return void
822
     * @throws Error
823
     */
824 View Code Duplication
    protected static function scalarmult_throw_if_zero($q)
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...
825
    {
826
        $d = 0;
827
        for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
828
            $d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]);
829
        }
830
831
        /* branch-free variant of === 0 */
832
        if (-(1 & (($d - 1) >> 8))) {
833
            throw new Error('Zero public key is not allowed');
834
        }
835
    }
836
837
    /**
838
     * XSalsa20-Poly1305 authenticated symmetric-key encryption.
839
     *
840
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
841
     *
842
     * @param string $plaintext
843
     * @param string $nonce
844
     * @param string $key
845
     * @return string
846
     */
847 View Code Duplication
    public static function 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...
848
    {
849
        /** @var string $subkey */
850
        $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
851
852
        /** @var string $block0 */
853
        $block0 = str_repeat("\x00", 32);
854
855
        /** @var int $mlen - Length of the plaintext message */
856
        $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
857
        $mlen0 = $mlen;
858
        if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
859
            $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
860
        }
861
        $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
862
863
        /** @var string $block0 */
864
        $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor(
865
            $block0,
866
            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
867
            $subkey
868
        );
869
870
        /** @var string $c */
871
        $c = ParagonIE_Sodium_Core_Util::substr(
872
            $block0,
873
            self::secretbox_xsalsa20poly1305_ZEROBYTES
874
        );
875
        if ($mlen > $mlen0) {
876
            $c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
877
                ParagonIE_Sodium_Core_Util::substr(
878
                    $plaintext,
879
                    self::secretbox_xsalsa20poly1305_ZEROBYTES
880
                ),
881
                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
882
                1,
883
                $subkey
884
            );
885
        }
886
        $state = new ParagonIE_Sodium_Core_Poly1305_State(
887
            ParagonIE_Sodium_Core_Util::substr(
888
                $block0,
889
                0,
890
                self::onetimeauth_poly1305_KEYBYTES
891
            )
892
        );
893
        try {
894
            ParagonIE_Sodium_Compat::memzero($block0);
895
            ParagonIE_Sodium_Compat::memzero($subkey);
896
        } 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...
897
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
898
            $subkey = null;
0 ignored issues
show
Unused Code introduced by
$subkey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
899
        }
900
901
        $state->update($c);
902
903
        /** @var string $c - MAC || ciphertext */
904
        $c = $state->finish() . $c;
905
        unset($state);
906
907
        return $c;
908
    }
909
910
    /**
911
     * Decrypt a ciphertext generated via secretbox().
912
     *
913
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
914
     *
915
     * @param string $ciphertext
916
     * @param string $nonce
917
     * @param string $key
918
     * @return string
919
     * @throws Error
920
     */
921 View Code Duplication
    public static function 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...
922
    {
923
        /** @var string $mac */
924
        $mac = ParagonIE_Sodium_Core_Util::substr(
925
            $ciphertext,
926
            0,
927
            self::secretbox_xsalsa20poly1305_MACBYTES
928
        );
929
930
        /** @var string $c */
931
        $c = ParagonIE_Sodium_Core_Util::substr(
932
            $ciphertext,
933
            self::secretbox_xsalsa20poly1305_MACBYTES
934
        );
935
936
        /** @var int $clen */
937
        $clen = ParagonIE_Sodium_Core_Util::strlen($c);
938
939
        /** @var string $subkey */
940
        $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
941
942
        /** @var string $block0 */
943
        $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20(
944
            64,
945
            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
946
            $subkey
947
        );
948
        $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
949
            $mac,
950
            $c,
951
            ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
952
        );
953
        if (!$verified) {
954
            try {
955
                ParagonIE_Sodium_Compat::memzero($subkey);
956
            } 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...
957
                $subkey = null;
0 ignored issues
show
Unused Code introduced by
$subkey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
958
            }
959
            throw new Error('Invalid MAC');
960
        }
961
962
        /** @var string $m - Decrypted message */
963
        $m = ParagonIE_Sodium_Core_Util::xorStrings(
964
            ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
965
            ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
966
        );
967
        if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
968
            // We had more than 1 block, so let's continue to decrypt the rest.
969
            $m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic(
970
                ParagonIE_Sodium_Core_Util::substr(
971
                    $c,
972
                    self::secretbox_xsalsa20poly1305_ZEROBYTES
973
                ),
974
                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
975
                1,
976
                $subkey
977
            );
978
        }
979
        return $m;
980
    }
981
982
    /**
983
     * XChaCha20-Poly1305 authenticated symmetric-key encryption.
984
     *
985
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
986
     *
987
     * @param string $plaintext
988
     * @param string $nonce
989
     * @param string $key
990
     * @return string
991
     */
992 View Code Duplication
    public static function 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...
993
    {
994
        /** @var string $subkey */
995
        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
996
            ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16),
997
            $key
998
        );
999
        $nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8);
1000
1001
        /** @var string $block0 */
1002
        $block0 = str_repeat("\x00", 32);
1003
1004
        /** @var int $mlen - Length of the plaintext message */
1005
        $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext);
1006
        $mlen0 = $mlen;
1007
        if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
1008
            $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
1009
        }
1010
        $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0);
1011
1012
        /** @var string $block0 */
1013
        $block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1014
            $block0,
1015
            $nonceLast,
1016
            $subkey
1017
        );
1018
1019
        /** @var string $c */
1020
        $c = ParagonIE_Sodium_Core_Util::substr(
1021
            $block0,
1022
            self::secretbox_xchacha20poly1305_ZEROBYTES
1023
        );
1024
        if ($mlen > $mlen0) {
1025
            $c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1026
                ParagonIE_Sodium_Core_Util::substr(
1027
                    $plaintext,
1028
                    self::secretbox_xchacha20poly1305_ZEROBYTES
1029
                ),
1030
                $nonceLast,
1031
                $subkey,
1032
                ParagonIE_Sodium_Core_Util::store64_le(1)
1033
            );
1034
        }
1035
        $state = new ParagonIE_Sodium_Core_Poly1305_State(
1036
            ParagonIE_Sodium_Core_Util::substr(
1037
                $block0,
1038
                0,
1039
                self::onetimeauth_poly1305_KEYBYTES
1040
            )
1041
        );
1042
        try {
1043
            ParagonIE_Sodium_Compat::memzero($block0);
1044
            ParagonIE_Sodium_Compat::memzero($subkey);
1045
        } 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...
1046
            $block0 = null;
0 ignored issues
show
Unused Code introduced by
$block0 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1047
            $subkey = null;
0 ignored issues
show
Unused Code introduced by
$subkey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1048
        }
1049
1050
        $state->update($c);
1051
1052
        /** @var string $c - MAC || ciphertext */
1053
        $c = $state->finish() . $c;
1054
        unset($state);
1055
1056
        return $c;
1057
    }
1058
1059
    /**
1060
     * Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
1061
     *
1062
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1063
     *
1064
     * @param string $ciphertext
1065
     * @param string $nonce
1066
     * @param string $key
1067
     * @return string
1068
     * @throws Error
1069
     */
1070 View Code Duplication
    public static function 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...
1071
    {
1072
        /** @var string $mac */
1073
        $mac = ParagonIE_Sodium_Core_Util::substr(
1074
            $ciphertext,
1075
            0,
1076
            self::secretbox_xchacha20poly1305_MACBYTES
1077
        );
1078
1079
        /** @var string $c */
1080
        $c = ParagonIE_Sodium_Core_Util::substr(
1081
            $ciphertext,
1082
            self::secretbox_xchacha20poly1305_MACBYTES
1083
        );
1084
1085
        /** @var int $clen */
1086
        $clen = ParagonIE_Sodium_Core_Util::strlen($c);
1087
1088
        /** @var string $subkey */
1089
        $subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key);
1090
1091
        /** @var string $block0 */
1092
        $block0 = ParagonIE_Sodium_Core_ChaCha20::stream(
1093
            64,
1094
            ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1095
            $subkey
1096
        );
1097
        $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify(
1098
            $mac,
1099
            $c,
1100
            ParagonIE_Sodium_Core_Util::substr($block0, 0, 32)
1101
        );
1102
1103
        if (!$verified) {
1104
            try {
1105
                ParagonIE_Sodium_Compat::memzero($subkey);
1106
            } 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...
1107
                $subkey = null;
0 ignored issues
show
Unused Code introduced by
$subkey is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1108
            }
1109
            throw new Error('Invalid MAC');
1110
        }
1111
1112
        /** @var string $m - Decrypted message */
1113
        $m = ParagonIE_Sodium_Core_Util::xorStrings(
1114
            ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
1115
            ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
1116
        );
1117
1118
        if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
1119
            // We had more than 1 block, so let's continue to decrypt the rest.
1120
            $m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc(
1121
                ParagonIE_Sodium_Core_Util::substr(
1122
                    $c,
1123
                    self::secretbox_xchacha20poly1305_ZEROBYTES
1124
                ),
1125
                ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8),
1126
                $subkey,
1127
                ParagonIE_Sodium_Core_Util::store64_le(1)
1128
            );
1129
        }
1130
        return $m;
1131
    }
1132
1133
    /**
1134
     * Detached Ed25519 signature.
1135
     *
1136
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1137
     *
1138
     * @param string $message
1139
     * @param string $sk
1140
     * @return string
1141
     */
1142
    public static function sign_detached($message, $sk)
1143
    {
1144
        return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk);
1145
    }
1146
1147
    /**
1148
     * Attached Ed25519 signature. (Returns a signed message.)
1149
     *
1150
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1151
     *
1152
     * @param string $message
1153
     * @param string $sk
1154
     * @return string
1155
     */
1156
    public static function sign($message, $sk)
1157
    {
1158
        return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk);
1159
    }
1160
1161
    /**
1162
     * Opens a signed message. If valid, returns the message.
1163
     *
1164
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1165
     *
1166
     * @param string $signedMessage
1167
     * @param string $pk
1168
     * @return string
1169
     */
1170
    public static function sign_open($signedMessage, $pk)
1171
    {
1172
        return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk);
1173
    }
1174
1175
    /**
1176
     * Verify a detached signature of a given message and public key.
1177
     *
1178
     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1179
     *
1180
     * @param string $signature
1181
     * @param string $message
1182
     * @param string $pk
1183
     * @return bool
1184
     */
1185
    public static function sign_verify_detached($signature, $message, $pk)
1186
    {
1187
        return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk);
1188
    }
1189
}
1190