Completed
Push — master ( 1a55dc...df871f )
by Michael
02:15
created

Str   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 76
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 8
c 3
b 0
f 0
lcom 0
cbo 1
dl 0
loc 76
ccs 17
cts 17
cp 1
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A equal() 0 12 1
A hashSize() 0 4 1
A strlen() 0 8 2
A substr() 0 13 4
1
<?php
2
3
/**
4
 * Str.php
5
 * 
6
 * PHP version 7
7
 * 
8
 * @category Dcrypt
9
 * @package  Dcrypt
10
 * @author   Michael Meyer (mmeyer2k) <[email protected]>
11
 * @license  http://opensource.org/licenses/MIT The MIT License (MIT)
12
 * @link     https://github.com/mmeyer2k/dcrypt
13
 */
14
15
namespace Dcrypt;
16
17
/**
18
 * Provides time-safe string comparison facilities, and safe string operations
19
 * on systems that have mb_* function overloading enabled.
20
 * 
21
 * The functions in this class were inspired by the symfony's StringUtils class. 
22
 * 
23
 * @category Dcrypt
24
 * @package  Dcrypt
25
 * @author   Michael Meyer (mmeyer2k) <[email protected]>
26
 * @license  http://opensource.org/licenses/MIT The MIT License (MIT)
27
 * @link     https://github.com/mmeyer2k/dcrypt
28
 * @link     https://github.com/symfony/Security/blob/master/Core/Util/StringUtils.php
29
 * @link     https://php.net/manual/en/mbstring.overload.php
30
 * @link     https://apigen.ci/github/mmeyer2k/dcrypt/namespace-Dcrypt.html
31
 */
32
final class Str
33
{
34
    /**
35
     * Compares two strings in constant time. Strings are hashed before 
36
     * comparison so information is not leaked when strings are not of
37
     * equal length.
38
     *
39
     * @param string $known       The string of known length to compare against
40
     * @param string $given       The string that the user can control
41
     *
42 14
     * @return bool
43
     */
44 14
    public static function equal(string $known, string $given): bool
45
    {
46
        // We hash the 2 inputs at this point because hash_equals is still 
47
        // vulnerable to timing attacks when the inputs have different sizes.
48 14
        // Inputs are also cast to string like in symfony stringutils.
49 14
        $nonce = Random::bytes(32);
50 14
51
        $known = \hash_hmac('sha256', (string) $known, $nonce, true);
52
        $given = \hash_hmac('sha256', (string) $given, $nonce, true);
53 14
54
        return \hash_equals($known, $given);
55
    }
56
57
    /**
58
     * Determine the length of the output of a given hash algorithm in bytes.
59
     * 
60
     * @param string $algo Name of algorithm to look up
61
     * 
62
     * @return int
63
     */
64
    public static function hashSize(string $algo): int
65
    {
66 14
        return self::strlen(\hash($algo, 'hash me', true));
67
    }
68
69
    /**
70
     * Returns the number of bytes in a string.
71 14
     *
72
     * @param string $string The string whose length we wish to obtain
73 14
     *
74 14
     * @return int
75
     */
76 14
    public static function strlen(string $string): int
77
    {
78
        if (\function_exists('mb_strlen')) {
79
            return \mb_strlen($string, '8bit');
80 14
        }
81
82
        return \strlen($string); // @codeCoverageIgnore
83
    }
84
85
    /**
86
     * Returns part of a string.
87
     *
88
     * @param string $string The string whose length we wish to obtain
89
     * @param int    $start
90 10
     * @param int    $length
91
     * 
92 10
     * @return string the extracted part of string; or FALSE on failure, or an empty string.
93
     */
94
    public static function substr(string $string, int $start, int $length = null): string
95
    {
96
        if (\function_exists('mb_substr')) {
97
            // Fix a weird quirk in PHP versions prior to 5.4.8
98
            if ($length === null && \version_compare('5.4.8', PHP_VERSION)) {
99
                $length = self::strlen($string);
100
            }
101
102 21
            return \mb_substr($string, $start, $length, '8bit');
103
        }
104 21
105 21
        return \substr($string, $start, $length); // @codeCoverageIgnore
106
    }
107
}
108