Diff: STRATO-apps/wordpress_03/app/wp-includes/sodium_compat/src/Core/Util.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
<?php
2
+
3
+
if (class_exists('ParagonIE_Sodium_Core_Util', false)) {
4
+
return;
5
+
}
6
+
7
+
/**
8
+
* Class ParagonIE_Sodium_Core_Util
9
+
*/
10
+
abstract class ParagonIE_Sodium_Core_Util
11
+
{
12
+
const U32_MAX = 0xFFFFFFFF;
13
+
14
+
/**
15
+
* @param int $integer
16
+
* @param int $size (16, 32, 64)
17
+
* @return int
18
+
*/
19
+
public static function abs($integer, $size = 0)
20
+
{
21
+
/** @var int $realSize */
22
+
$realSize = (PHP_INT_SIZE << 3) - 1;
23
+
if ($size) {
24
+
--$size;
25
+
} else {
26
+
/** @var int $size */
27
+
$size = $realSize;
28
+
}
29
+
30
+
$negative = -(($integer >> $size) & 1);
31
+
return (int) (
32
+
($integer ^ $negative)
33
+
+
34
+
(($negative >> $realSize) & 1)
35
+
);
36
+
}
37
+
38
+
/**
39
+
* @param string $a
40
+
* @param string $b
41
+
* @return string
42
+
* @throws SodiumException
43
+
*/
44
+
public static function andStrings($a, $b)
45
+
{
46
+
/* Type checks: */
47
+
if (!is_string($a)) {
48
+
throw new TypeError('Argument 1 must be a string');
49
+
}
50
+
if (!is_string($b)) {
51
+
throw new TypeError('Argument 2 must be a string');
52
+
}
53
+
$len = self::strlen($a);
54
+
if (self::strlen($b) !== $len) {
55
+
throw new SodiumException('Both strings must be of equal length to combine with bitwise AND');
56
+
}
57
+
return $a & $b;
58
+
}
59
+
60
+
/**
61
+
* Convert a binary string into a hexadecimal string without cache-timing
62
+
* leaks
63
+
*
64
+
* @internal You should not use this directly from another application
65
+
*
66
+
* @param string $binaryString (raw binary)
67
+
* @return string
68
+
* @throws TypeError
69
+
*/
70
+
public static function bin2hex($binaryString)
71
+
{
72
+
/* Type checks: */
73
+
if (!is_string($binaryString)) {
74
+
throw new TypeError('Argument 1 must be a string, ' . gettype($binaryString) . ' given.');
75
+
}
76
+
77
+
$hex = '';
78
+
$len = self::strlen($binaryString);
79
+
for ($i = 0; $i < $len; ++$i) {
80
+
/** @var array<int, int> $chunk */
81
+
$chunk = unpack('C', $binaryString[$i]);
82
+
/** @var int $c */
83
+
$c = $chunk[1] & 0xf;
84
+
/** @var int $b */
85
+
$b = $chunk[1] >> 4;
86
+
$hex .= pack(
87
+
'CC',
88
+
(87 + $b + ((($b - 10) >> 8) & ~38)),
89
+
(87 + $c + ((($c - 10) >> 8) & ~38))
90
+
);
91
+
}
92
+
return $hex;
93
+
}
94
+
95
+
/**
96
+
* Convert a binary string into a hexadecimal string without cache-timing
97
+
* leaks, returning uppercase letters (as per RFC 4648)
98
+
*
99
+
* @internal You should not use this directly from another application
100
+
*
101
+
* @param string $bin_string (raw binary)
102
+
* @return string
103
+
* @throws TypeError
104
+
*/
105
+
public static function bin2hexUpper($bin_string)
106
+
{
107
+
$hex = '';
108
+
$len = self::strlen($bin_string);
109
+
for ($i = 0; $i < $len; ++$i) {
110
+
/** @var array<int, int> $chunk */
111
+
$chunk = unpack('C', $bin_string[$i]);
112
+
/**
113
+
* Lower 16 bits
114
+
*
115
+
* @var int $c
116
+
*/
117
+
$c = $chunk[1] & 0xf;
118
+
119
+
/**
120
+
* Upper 16 bits
121
+
* @var int $b
122
+
*/
123
+
$b = $chunk[1] >> 4;
124
+
125
+
/**
126
+
* Use pack() and binary operators to turn the two integers
127
+
* into hexadecimal characters. We don't use chr() here, because
128
+
* it uses a lookup table internally and we want to avoid
129
+
* cache-timing side-channels.
130
+
*/
131
+
$hex .= pack(
132
+
'CC',
133
+
(55 + $b + ((($b - 10) >> 8) & ~6)),
134
+
(55 + $c + ((($c - 10) >> 8) & ~6))
135
+
);
136
+
}
137
+
return $hex;
138
+
}
139
+
140
+
/**
141
+
* Cache-timing-safe variant of ord()
142
+
*
143
+
* @internal You should not use this directly from another application
144
+
*
145
+
* @param string $chr
146
+
* @return int
147
+
* @throws SodiumException
148
+
* @throws TypeError
149
+
*/
150
+
public static function chrToInt($chr)
151
+
{
152
+
/* Type checks: */
153
+
if (!is_string($chr)) {
154
+
throw new TypeError('Argument 1 must be a string, ' . gettype($chr) . ' given.');
155
+
}
156
+
if (self::strlen($chr) !== 1) {
157
+
throw new SodiumException('chrToInt() expects a string that is exactly 1 character long');
158
+
}
159
+
/** @var array<int, int> $chunk */
160
+
$chunk = unpack('C', $chr);
161
+
return (int) ($chunk[1]);
162
+
}
163
+
164
+
/**
165
+
* Compares two strings.
166
+
*
167
+
* @internal You should not use this directly from another application
168
+
*
169
+
* @param string $left
170
+
* @param string $right
171
+
* @param int $len
172
+
* @return int
173
+
* @throws SodiumException
174
+
* @throws TypeError
175
+
*/
176
+
public static function compare($left, $right, $len = null)
177
+
{
178
+
$leftLen = self::strlen($left);
179
+
$rightLen = self::strlen($right);
180
+
if ($len === null) {
181
+
$len = max($leftLen, $rightLen);
182
+
$left = str_pad($left, $len, "\x00", STR_PAD_RIGHT);
183
+
$right = str_pad($right, $len, "\x00", STR_PAD_RIGHT);
184
+
} elseif ($leftLen !== $rightLen) {
185
+
throw new SodiumException("Argument #1 and argument #2 must have the same length");
186
+
}
187
+
188
+
$gt = 0;
189
+
$eq = 1;
190
+
$i = $len;
191
+
while ($i !== 0) {
192
+
--$i;
193
+
$gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq;
194
+
$eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8;
195
+
}
196
+
return ($gt + $gt + $eq) - 1;
197
+
}
198
+
199
+
/**
200
+
* If a variable does not match a given type, throw a TypeError.
201
+
*
202
+
* @param mixed $mixedVar
203
+
* @param string $type
204
+
* @param int $argumentIndex
205
+
* @throws TypeError
206
+
* @throws SodiumException
207
+
* @return void
208
+
*/
209
+
public static function declareScalarType(&$mixedVar = null, $type = 'void', $argumentIndex = 0)
210
+
{
211
+
if (func_num_args() === 0) {
212
+
/* Tautology, by default */
213
+
return;
214
+
}
215
+
if (func_num_args() === 1) {
216
+
throw new TypeError('Declared void, but passed a variable');
217
+
}
218
+
$realType = strtolower(gettype($mixedVar));
219
+
$type = strtolower($type);
220
+
switch ($type) {
221
+
case 'null':
222
+
if ($mixedVar !== null) {
223
+
throw new TypeError('Argument ' . $argumentIndex . ' must be null, ' . $realType . ' given.');
224
+
}
225
+
break;
226
+
case 'integer':
227
+
case 'int':
228
+
$allow = array('int', 'integer');
229
+
if (!in_array($type, $allow)) {
230
+
throw new TypeError('Argument ' . $argumentIndex . ' must be an integer, ' . $realType . ' given.');
231
+
}
232
+
$mixedVar = (int) $mixedVar;
233
+
break;
234
+
case 'boolean':
235
+
case 'bool':
236
+
$allow = array('bool', 'boolean');
237
+
if (!in_array($type, $allow)) {
238
+
throw new TypeError('Argument ' . $argumentIndex . ' must be a boolean, ' . $realType . ' given.');
239
+
}
240
+
$mixedVar = (bool) $mixedVar;
241
+
break;
242
+
case 'string':
243
+
if (!is_string($mixedVar)) {
244
+
throw new TypeError('Argument ' . $argumentIndex . ' must be a string, ' . $realType . ' given.');
245
+
}
246
+
$mixedVar = (string) $mixedVar;
247
+
break;
248
+
case 'decimal':
249
+
case 'double':
250
+
case 'float':
251
+
$allow = array('decimal', 'double', 'float');
252
+
if (!in_array($type, $allow)) {
253
+
throw new TypeError('Argument ' . $argumentIndex . ' must be a float, ' . $realType . ' given.');
254
+
}
255
+
$mixedVar = (float) $mixedVar;
256
+
break;
257
+
case 'object':
258
+
if (!is_object($mixedVar)) {
259
+
throw new TypeError('Argument ' . $argumentIndex . ' must be an object, ' . $realType . ' given.');
260
+
}
261
+
break;
262
+
case 'array':
263
+
if (!is_array($mixedVar)) {
264
+
if (is_object($mixedVar)) {
265
+
if ($mixedVar instanceof ArrayAccess) {
266
+
return;
267
+
}
268
+
}
269
+
throw new TypeError('Argument ' . $argumentIndex . ' must be an array, ' . $realType . ' given.');
270
+
}
271
+
break;
272
+
default:
273
+
throw new SodiumException('Unknown type (' . $realType .') does not match expect type (' . $type . ')');
274
+
}
275
+
}
276
+
277
+
/**
278
+
* Evaluate whether or not two strings are equal (in constant-time)
279
+
*
280
+
* @param string $left
281
+
* @param string $right
282
+
* @return bool
283
+
* @throws SodiumException
284
+
* @throws TypeError
285
+
*/
286
+
public static function hashEquals($left, $right)
287
+
{
288
+
/* Type checks: */
289
+
if (!is_string($left)) {
290
+
throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.');
291
+
}
292
+
if (!is_string($right)) {
293
+
throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.');
294
+
}
295
+
296
+
if (is_callable('hash_equals')) {
297
+
return hash_equals($left, $right);
298
+
}
299
+
$d = 0;
300
+
/** @var int $len */
301
+
$len = self::strlen($left);
302
+
if ($len !== self::strlen($right)) {
303
+
return false;
304
+
}
305
+
for ($i = 0; $i < $len; ++$i) {
306
+
$d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]);
307
+
}
308
+
309
+
if ($d !== 0) {
310
+
return false;
311
+
}
312
+
return $left === $right;
313
+
}
314
+
315
+
/**
316
+
* Catch hash_update() failures and throw instead of silently proceeding
317
+
*
318
+
* @param HashContext|resource &$hs
319
+
* @param string $data
320
+
* @return void
321
+
* @throws SodiumException
322
+
* @psalm-suppress PossiblyInvalidArgument
323
+
*/
324
+
protected static function hash_update(&$hs, $data)
325
+
{
326
+
if (!hash_update($hs, $data)) {
327
+
throw new SodiumException('hash_update() failed');
328
+
}
329
+
}
330
+
331
+
/**
332
+
* Convert a hexadecimal string into a binary string without cache-timing
333
+
* leaks
334
+
*
335
+
* @internal You should not use this directly from another application
336
+
*
337
+
* @param string $hexString
338
+
* @param string $ignore
339
+
* @param bool $strictPadding
340
+
* @return string (raw binary)
341
+
*
342
+
* @throws SodiumException
343
+
* @throws TypeError
344
+
*/
345
+
public static function hex2bin($hexString, $ignore = '', $strictPadding = false)
346
+
{
347
+
/* Type checks: */
348
+
if (!is_string($hexString)) {
349
+
throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.');
350
+
}
351
+
if (!is_string($ignore)) {
352
+
throw new TypeError('Argument 2 must be a string, ' . gettype($hexString) . ' given.');
353
+
}
354
+
355
+
$hex_pos = 0;
356
+
$bin = '';
357
+
$c_acc = 0;
358
+
$hex_len = self::strlen($hexString);
359
+
$state = 0;
360
+
361
+
$chunk = unpack('C*', $hexString);
362
+
while ($hex_pos < $hex_len) {
363
+
++$hex_pos;
364
+
/** @var int $c */
365
+
$c = $chunk[$hex_pos];
366
+
$c_num = $c ^ 48;
367
+
$c_num0 = ($c_num - 10) >> 8;
368
+
$c_alpha = ($c & ~32) - 55;
369
+
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
370
+
if (($c_num0 | $c_alpha0) === 0) {
371
+
if ($ignore && $state === 0 && strpos($ignore, self::intToChr($c)) !== false) {
372
+
continue;
373
+
}
374
+
throw new RangeException(
375
+
'hex2bin() only expects hexadecimal characters'
376
+
);
377
+
}
378
+
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
379
+
if ($state === 0) {
380
+
$c_acc = $c_val * 16;
381
+
} else {
382
+
$bin .= pack('C', $c_acc | $c_val);
383
+
}
384
+
$state ^= 1;
385
+
}
386
+
if ($strictPadding && $state !== 0) {
387
+
throw new SodiumException(
388
+
'Expected an even number of hexadecimal characters'
389
+
);
390
+
}
391
+
return $bin;
392
+
}
393
+
394
+
/**
395
+
* Turn an array of integers into a string
396
+
*
397
+
* @internal You should not use this directly from another application
398
+
*
399
+
* @param array<int, int> $ints
400
+
* @return string
401
+
*/
402
+
public static function intArrayToString(array $ints)
403
+
{
404
+
$args = $ints;
405
+
foreach ($args as $i => $v) {
406
+
$args[$i] = (int) ($v & 0xff);
407
+
}
408
+
array_unshift($args, str_repeat('C', count($ints)));
409
+
return (string) (call_user_func_array('pack', $args));
410
+
}
411
+
412
+
/**
413
+
* Cache-timing-safe variant of ord()
414
+
*
415
+
* @internal You should not use this directly from another application
416
+
*
417
+
* @param int $int
418
+
* @return string
419
+
* @throws TypeError
420
+
*/
421
+
public static function intToChr($int)
422
+
{
423
+
return pack('C', $int);
424
+
}
425
+
426
+
/**
427
+
* Load a 3 character substring into an integer
428
+
*
429
+
* @internal You should not use this directly from another application
430
+
*
431
+
* @param string $string
432
+
* @return int
433
+
* @throws RangeException
434
+
* @throws TypeError
435
+
*/
436
+
public static function load_3($string)
437
+
{
438
+
/* Type checks: */
439
+
if (!is_string($string)) {
440
+
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
441
+
}
442
+
443
+
/* Input validation: */
444
+
if (self::strlen($string) < 3) {
445
+
throw new RangeException(
446
+
'String must be 3 bytes or more; ' . self::strlen($string) . ' given.'
447
+
);
448
+
}
449
+
/** @var array<int, int> $unpacked */
450
+
$unpacked = unpack('V', $string . "\0");
451
+
return (int) ($unpacked[1] & 0xffffff);
452
+
}
453
+
454
+
/**
455
+
* Load a 4 character substring into an integer
456
+
*
457
+
* @internal You should not use this directly from another application
458
+
*
459
+
* @param string $string
460
+
* @return int
461
+
* @throws RangeException
462
+
* @throws TypeError
463
+
*/
464
+
public static function load_4($string)
465
+
{
466
+
/* Type checks: */
467
+
if (!is_string($string)) {
468
+
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
469
+
}
470
+
471
+
/* Input validation: */
472
+
if (self::strlen($string) < 4) {
473
+
throw new RangeException(
474
+
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
475
+
);
476
+
}
477
+
/** @var array<int, int> $unpacked */
478
+
$unpacked = unpack('V', $string);
479
+
return (int) $unpacked[1];
480
+
}
481
+
482
+
/**
483
+
* Load a 8 character substring into an integer
484
+
*
485
+
* @internal You should not use this directly from another application
486
+
*
487
+
* @param string $string
488
+
* @return int
489
+
* @throws RangeException
490
+
* @throws SodiumException
491
+
* @throws TypeError
492
+
*/
493
+
public static function load64_le($string)
494
+
{
495
+
/* Type checks: */
496
+
if (!is_string($string)) {
497
+
throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.');
498
+
}
499
+
500
+
/* Input validation: */
501
+
if (self::strlen($string) < 4) {
502
+
throw new RangeException(
503
+
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
504
+
);
505
+
}
506
+
if (PHP_VERSION_ID >= 50603 && PHP_INT_SIZE === 8) {
507
+
/** @var array<int, int> $unpacked */
508
+
$unpacked = unpack('P', $string);
509
+
return (int) $unpacked[1];
510
+
}
511
+
512
+
/** @var int $result */
513
+
$result = (self::chrToInt($string[0]) & 0xff);
514
+
$result |= (self::chrToInt($string[1]) & 0xff) << 8;
515
+
$result |= (self::chrToInt($string[2]) & 0xff) << 16;
516
+
$result |= (self::chrToInt($string[3]) & 0xff) << 24;
517
+
$result |= (self::chrToInt($string[4]) & 0xff) << 32;
518
+
$result |= (self::chrToInt($string[5]) & 0xff) << 40;
519
+
$result |= (self::chrToInt($string[6]) & 0xff) << 48;
520
+
$result |= (self::chrToInt($string[7]) & 0xff) << 56;
521
+
return (int) $result;
522
+
}
523
+
524
+
/**
525
+
* @internal You should not use this directly from another application
526
+
*
527
+
* @param string $left
528
+
* @param string $right
529
+
* @return int
530
+
* @throws SodiumException
531
+
* @throws TypeError
532
+
*/
533
+
public static function memcmp($left, $right)
534
+
{
535
+
$e = (int) !self::hashEquals($left, $right);
536
+
return 0 - $e;
537
+
}
538
+
539
+
/**
540
+
* Multiply two integers in constant-time
541
+
*
542
+
* Micro-architecture timing side-channels caused by how your CPU
543
+
* implements multiplication are best prevented by never using the
544
+
* multiplication operators and ensuring that our code always takes
545
+
* the same number of operations to complete, regardless of the values
546
+
* of $a and $b.
547
+
*
548
+
* @internal You should not use this directly from another application
549
+
*
550
+
* @param int $a
551
+
* @param int $b
552
+
* @param int $size Limits the number of operations (useful for small,
553
+
* constant operands)
554
+
* @return int
555
+
*/
556
+
public static function mul($a, $b, $size = 0)
557
+
{
558
+
if (ParagonIE_Sodium_Compat::$fastMult) {
559
+
return (int) ($a * $b);
560
+
}
561
+
562
+
static $defaultSize = null;
563
+
/** @var int $defaultSize */
564
+
if (!$defaultSize) {
565
+
/** @var int $defaultSize */
566
+
$defaultSize = (PHP_INT_SIZE << 3) - 1;
567
+
}
568
+
if ($size < 1) {
569
+
/** @var int $size */
570
+
$size = $defaultSize;
571
+
}
572
+
/** @var int $size */
573
+
574
+
$c = 0;
575
+
576
+
/**
577
+
* Mask is either -1 or 0.
578
+
*
579
+
* -1 in binary looks like 0x1111 ... 1111
580
+
* 0 in binary looks like 0x0000 ... 0000
581
+
*
582
+
* @var int
583
+
*/
584
+
$mask = -(($b >> ((int) $defaultSize)) & 1);
585
+
586
+
/**
587
+
* Ensure $b is a positive integer, without creating
588
+
* a branching side-channel
589
+
*
590
+
* @var int $b
591
+
*/
592
+
$b = ($b & ~$mask) | ($mask & -$b);
593
+
594
+
/**
595
+
* Unless $size is provided:
596
+
*
597
+
* This loop always runs 32 times when PHP_INT_SIZE is 4.
598
+
* This loop always runs 64 times when PHP_INT_SIZE is 8.
599
+
*/
600
+
for ($i = $size; $i >= 0; --$i) {
601
+
$c += (int) ($a & -($b & 1));
602
+
$a <<= 1;
603
+
$b >>= 1;
604
+
}
605
+
$c = (int) @($c & -1);
606
+
607
+
/**
608
+
* If $b was negative, we then apply the same value to $c here.
609
+
* It doesn't matter much if $a was negative; the $c += above would
610
+
* have produced a negative integer to begin with. But a negative $b
611
+
* makes $b >>= 1 never return 0, so we would end up with incorrect
612
+
* results.
613
+
*
614
+
* The end result is what we'd expect from integer multiplication.
615
+
*/
616
+
return (int) (($c & ~$mask) | ($mask & -$c));
617
+
}
618
+
619
+
/**
620
+
* Convert any arbitrary numbers into two 32-bit integers that represent
621
+
* a 64-bit integer.
622
+
*
623
+
* @internal You should not use this directly from another application
624
+
*
625
+
* @param int|float $num
626
+
* @return array<int, int>
627
+
*/
628
+
public static function numericTo64BitInteger($num)
629
+
{
630
+
$high = 0;
631
+
/** @var int $low */
632
+
if (PHP_INT_SIZE === 4) {
633
+
$low = (int) $num;
634
+
} else {
635
+
$low = $num & 0xffffffff;
636
+
}
637
+
638
+
if ((+(abs($num))) >= 1) {
639
+
if ($num > 0) {
640
+
/** @var int $high */
641
+
$high = min((+(floor($num/4294967296))), 4294967295);
642
+
} else {
643
+
/** @var int $high */
644
+
$high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296))));
645
+
}
646
+
}
647
+
return array((int) $high, (int) $low);
648
+
}
649
+
650
+
/**
651
+
* Store a 24-bit integer into a string, treating it as big-endian.
652
+
*
653
+
* @internal You should not use this directly from another application
654
+
*
655
+
* @param int $int
656
+
* @return string
657
+
* @throws TypeError
658
+
*/
659
+
public static function store_3($int)
660
+
{
661
+
/* Type checks: */
662
+
if (!is_int($int)) {
663
+
if (is_numeric($int)) {
664
+
$int = (int) $int;
665
+
} else {
666
+
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
667
+
}
668
+
}
669
+
/** @var string $packed */
670
+
$packed = pack('N', $int);
671
+
return self::substr($packed, 1, 3);
672
+
}
673
+
674
+
/**
675
+
* Store a 32-bit integer into a string, treating it as little-endian.
676
+
*
677
+
* @internal You should not use this directly from another application
678
+
*
679
+
* @param int $int
680
+
* @return string
681
+
* @throws TypeError
682
+
*/
683
+
public static function store32_le($int)
684
+
{
685
+
/* Type checks: */
686
+
if (!is_int($int)) {
687
+
if (is_numeric($int)) {
688
+
$int = (int) $int;
689
+
} else {
690
+
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
691
+
}
692
+
}
693
+
694
+
/** @var string $packed */
695
+
$packed = pack('V', $int);
696
+
return $packed;
697
+
}
698
+
699
+
/**
700
+
* Store a 32-bit integer into a string, treating it as big-endian.
701
+
*
702
+
* @internal You should not use this directly from another application
703
+
*
704
+
* @param int $int
705
+
* @return string
706
+
* @throws TypeError
707
+
*/
708
+
public static function store_4($int)
709
+
{
710
+
/* Type checks: */
711
+
if (!is_int($int)) {
712
+
if (is_numeric($int)) {
713
+
$int = (int) $int;
714
+
} else {
715
+
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
716
+
}
717
+
}
718
+
719
+
/** @var string $packed */
720
+
$packed = pack('N', $int);
721
+
return $packed;
722
+
}
723
+
724
+
/**
725
+
* Stores a 64-bit integer as an string, treating it as little-endian.
726
+
*
727
+
* @internal You should not use this directly from another application
728
+
*
729
+
* @param int $int
730
+
* @return string
731
+
* @throws TypeError
732
+
*/
733
+
public static function store64_le($int)
734
+
{
735
+
/* Type checks: */
736
+
if (!is_int($int)) {
737
+
if (is_numeric($int)) {
738
+
$int = (int) $int;
739
+
} else {
740
+
throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.');
741
+
}
742
+
}
743
+
744
+
if (PHP_INT_SIZE === 8) {
745
+
if (PHP_VERSION_ID >= 50603) {
746
+
/** @var string $packed */
747
+
$packed = pack('P', $int);
748
+
return $packed;
749
+
}
750
+
return self::intToChr($int & 0xff) .
751
+
self::intToChr(($int >> 8) & 0xff) .
752
+
self::intToChr(($int >> 16) & 0xff) .
753
+
self::intToChr(($int >> 24) & 0xff) .
754
+
self::intToChr(($int >> 32) & 0xff) .
755
+
self::intToChr(($int >> 40) & 0xff) .
756
+
self::intToChr(($int >> 48) & 0xff) .
757
+
self::intToChr(($int >> 56) & 0xff);
758
+
}
759
+
if ($int > PHP_INT_MAX) {
760
+
list($hiB, $int) = self::numericTo64BitInteger($int);
761
+
} else {
762
+
$hiB = 0;
763
+
}
764
+
return
765
+
self::intToChr(($int ) & 0xff) .
766
+
self::intToChr(($int >> 8) & 0xff) .
767
+
self::intToChr(($int >> 16) & 0xff) .
768
+
self::intToChr(($int >> 24) & 0xff) .
769
+
self::intToChr($hiB & 0xff) .
770
+
self::intToChr(($hiB >> 8) & 0xff) .
771
+
self::intToChr(($hiB >> 16) & 0xff) .
772
+
self::intToChr(($hiB >> 24) & 0xff);
773
+
}
774
+
775
+
/**
776
+
* Safe string length
777
+
*
778
+
* @internal You should not use this directly from another application
779
+
*
780
+
* @ref mbstring.func_overload
781
+
*
782
+
* @param string $str
783
+
* @return int
784
+
* @throws TypeError
785
+
*/
786
+
public static function strlen($str)
787
+
{
788
+
/* Type checks: */
789
+
if (!is_string($str)) {
790
+
throw new TypeError('String expected');
791
+
}
792
+
793
+
return (int) (
794
+
self::isMbStringOverride()
795
+
? mb_strlen($str, '8bit')
796
+
: strlen($str)
797
+
);
798
+
}
799
+
800
+
/**
801
+
* Turn a string into an array of integers
802
+
*
803
+
* @internal You should not use this directly from another application
804
+
*
805
+
* @param string $string
806
+
* @return array<int, int>
807
+
* @throws TypeError
808
+
*/
809
+
public static function stringToIntArray($string)
810
+
{
811
+
if (!is_string($string)) {
812
+
throw new TypeError('String expected');
813
+
}
814
+
/**
815
+
* @var array<int, int>
816
+
*/
817
+
$values = array_values(
818
+
unpack('C*', $string)
819
+
);
820
+
return $values;
821
+
}
822
+
823
+
/**
824
+
* Safe substring
825
+
*
826
+
* @internal You should not use this directly from another application
827
+
*
828
+
* @ref mbstring.func_overload
829
+
*
830
+
* @param string $str
831
+
* @param int $start
832
+
* @param int $length
833
+
* @return string
834
+
* @throws TypeError
835
+
*/
836
+
public static function substr($str, $start = 0, $length = null)
837
+
{
838
+
/* Type checks: */
839
+
if (!is_string($str)) {
840
+
throw new TypeError('String expected');
841
+
}
842
+
843
+
if ($length === 0) {
844
+
return '';
845
+
}
846
+
847
+
if (self::isMbStringOverride()) {
848
+
if (PHP_VERSION_ID < 50400 && $length === null) {
849
+
$length = self::strlen($str);
850
+
}
851
+
$sub = (string) mb_substr($str, $start, $length, '8bit');
852
+
} elseif ($length === null) {
853
+
$sub = (string) substr($str, $start);
854
+
} else {
855
+
$sub = (string) substr($str, $start, $length);
856
+
}
857
+
if ($sub !== '') {
858
+
return $sub;
859
+
}
860
+
return '';
861
+
}
862
+
863
+
/**
864
+
* Compare a 16-character byte string in constant time.
865
+
*
866
+
* @internal You should not use this directly from another application
867
+
*
868
+
* @param string $a
869
+
* @param string $b
870
+
* @return bool
871
+
* @throws SodiumException
872
+
* @throws TypeError
873
+
*/
874
+
public static function verify_16($a, $b)
875
+
{
876
+
/* Type checks: */
877
+
if (!is_string($a)) {
878
+
throw new TypeError('String expected');
879
+
}
880
+
if (!is_string($b)) {
881
+
throw new TypeError('String expected');
882
+
}
883
+
return self::hashEquals(
884
+
self::substr($a, 0, 16),
885
+
self::substr($b, 0, 16)
886
+
);
887
+
}
888
+
889
+
/**
890
+
* Compare a 32-character byte string in constant time.
891
+
*
892
+
* @internal You should not use this directly from another application
893
+
*
894
+
* @param string $a
895
+
* @param string $b
896
+
* @return bool
897
+
* @throws SodiumException
898
+
* @throws TypeError
899
+
*/
900
+
public static function verify_32($a, $b)
901
+
{
902
+
/* Type checks: */
903
+
if (!is_string($a)) {
904
+
throw new TypeError('String expected');
905
+
}
906
+
if (!is_string($b)) {
907
+
throw new TypeError('String expected');
908
+
}
909
+
return self::hashEquals(
910
+
self::substr($a, 0, 32),
911
+
self::substr($b, 0, 32)
912
+
);
913
+
}
914
+
915
+
/**
916
+
* Calculate $a ^ $b for two strings.
917
+
*
918
+
* @internal You should not use this directly from another application
919
+
*
920
+
* @param string $a
921
+
* @param string $b
922
+
* @return string
923
+
* @throws TypeError
924
+
*/
925
+
public static function xorStrings($a, $b)
926
+
{
927
+
/* Type checks: */
928
+
if (!is_string($a)) {
929
+
throw new TypeError('Argument 1 must be a string');
930
+
}
931
+
if (!is_string($b)) {
932
+
throw new TypeError('Argument 2 must be a string');
933
+
}
934
+
935
+
return (string) ($a ^ $b);
936
+
}
937
+
938
+
/**
939
+
* Returns whether or not mbstring.func_overload is in effect.
940
+
*
941
+
* @internal You should not use this directly from another application
942
+
*
943
+
* Note: MB_OVERLOAD_STRING === 2, but we don't reference the constant
944
+
* (for nuisance-free PHP 8 support)
945
+
*
946
+
* @return bool
947
+
*/
948
+
protected static function isMbStringOverride()
949
+
{
950
+
static $mbstring = null;
951
+
952
+
if ($mbstring === null) {
953
+
if (!defined('MB_OVERLOAD_STRING')) {
954
+
$mbstring = false;
955
+
return $mbstring;
956
+
}
957
+
$mbstring = extension_loaded('mbstring')
958
+
&& defined('MB_OVERLOAD_STRING')
959
+
&&
960
+
((int) (ini_get('mbstring.func_overload')) & 2);
961
+
// MB_OVERLOAD_STRING === 2
962
+
}
963
+
/** @var bool $mbstring */
964
+
965
+
return $mbstring;
966
+
}
967
+
}
968
+