Completed
Push — master ( 9455de...3ae3f3 )
by Michael
05:54
created

Str   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 104
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 20
Bugs 1 Features 1
Metric Value
wmc 11
c 20
b 1
f 1
lcom 0
cbo 1
dl 0
loc 104
ccs 21
cts 21
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A strcmp() 0 13 2
A equal() 0 16 2
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 5
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
    /**
36
     * Private constant-time strcmp method to use when hash_equals is unavailable.
37
     *
38
     * @param string $knownHash Hash of the known string
39
     * @param string $givenHash Hash of the given string
40
     *
41
     * @return bool true if the two strings are the same, false otherwise
42
     */
43 12
    private static function strcmp($knownHash, $givenHash)
44
    {
45 12
        $result = 0;
46
47
        // XOR the bytes of the 2 input hashes and loop over them.
48
        // Each byte value is then added to a running total...
49 12
        foreach (\str_split($knownHash ^ $givenHash) as $xbyte) {
50 12
            $result += \ord($xbyte);
51 12
        }
52
53
        // Strings are equal if the final result is exactly zero
54 12
        return 0 === $result;
55
    }
56
57
    /**
58
     * Compares two strings in constant time. Strings are hashed before 
59
     * comparison so information is not leaked when strings are not of
60
     * equal length.
61
     *
62
     * @param string $known       The string of known length to compare against
63
     * @param string $given       The string that the user can control
64
     *
65
     * @return bool
66
     */
67 12
    public static function equal($known, $given)
68
    {
69
        // We hash the 2 inputs at this point because hash_equals is still 
70
        // vulnerable to timing attacks when the inputs have different sizes.
71
        // Inputs are also cast to string like in symfony stringutils.
72 12
        $nonce = Random::bytes(32);
73
74 12
        $known = \hash_hmac('sha256', (string) $known, $nonce, true);
75 12
        $given = \hash_hmac('sha256', (string) $given, $nonce, true);
76
77 12
        if (\function_exists('hash_equals')) {
78
            return \hash_equals($known, $given); // @codeCoverageIgnore
79
        }
80
81 12
        return self::strcmp($known, $given);
82
    }
83
84
    /**
85
     * Determine the length of the output of a given hash algorithm in bytes.
86
     * 
87
     * @param string $algo Name of algorithm to look up
88
     * 
89
     * @return int
90
     */
91 20
    public static function hashSize($algo)
92
    {
93 20
        return Str::strlen(\hash($algo, 'hash me', true));
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
94 20
    }
95
96
    /**
97
     * Returns the number of bytes in a string.
98
     *
99
     * @param string $string The string whose length we wish to obtain
100
     *
101
     * @return int
102
     */
103
    public static function strlen($string)
104
    {
105
        if (\function_exists('mb_strlen')) {
106
            return \mb_strlen($string, '8bit');
107
        }
108
109 14
        return \strlen($string); // @codeCoverageIgnore
110
    }
111 14
112
    /**
113 14
     * Returns part of a string.
114 9
     *
115 9
     * @param string $string The string whose length we wish to obtain
116
     * @param int    $start
117 14
     * @param int    $length
118
     * 
119
     * @return string the extracted part of string; or FALSE on failure, or an empty string.
120
     */
121
    public static function substr($string, $start, $length = null)
122
    {
123
        if (\function_exists('mb_substr')) {
124
            // Fix a weird quirk in PHP versions prior to 5.4.8
125
            if ($length === null && \version_compare('5.4.8', PHP_VERSION)) {
126
                $length = self::strlen($string);
127
            }
128
129
            return \mb_substr($string, $start, $length, '8bit');
130
        }
131
132
        return \substr($string, $start, $length); // @codeCoverageIgnore
133
    }
134
135
}
136