GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Encryption   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 249
Duplicated Lines 3.21 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 1
dl 8
loc 249
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 1 1
A encryptId() 0 16 3
A decryptId() 4 18 3
A decryptIdWithDash() 4 20 3
A getCharacters() 0 21 4
B encrypt() 0 26 4
B decrypt() 0 32 5
B hashEquals() 0 23 4

How to fix   Duplicated Code   

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:

1
<?php
2
3
/**
4
 * Encryption and Decryption Class
5
 *
6
 * @license    http://opensource.org/licenses/MIT The MIT License (MIT)
7
 * @author     Omar El Gabry <[email protected]>
8
 */
9
10
class Encryption{
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
11
12
    /**
13
     * Cipher algorithm
14
     *
15
     * @var string
16
     */
17
    const CIPHER = 'aes-256-cbc';
18
19
    /**
20
     * Hash function
21
     *
22
     * @var string
23
     */
24
    const HASH_FUNCTION = 'sha256';
25
26
    /**
27
     * constructor for Encryption object.
28
     *
29
     * @access private
30
     */
31
    private function __construct(){}
32
33
    /**
34
     * Encrypt an id.
35
     *
36
     * @access public
37
     * @static static method
38
     * @param  integer|string	$id
39
     * @return string
40
     * @see http://kvz.io/blog/2009/06/10/create-short-ids-with-php-like-youtube-or-tinyurl/
41
     */
42
    public static function encryptId($id){
43
44
        $encryptId  = "";
45
        $chars = self::getCharacters();
46
        $base  = strlen($chars);
47
        $id    = ((int)$id * 9518436) + 1142;
48
49
        for ($t = ($id != 0 ? floor(log($id, $base)) : 0); $t >= 0; $t--) {
50
            $bcp = bcpow($base, $t);
51
            $a   = floor($id / $bcp) % $base;
52
            $encryptId = $encryptId . substr($chars, $a, 1);
53
            $id  = $id - ($a * $bcp);
54
        }
55
56
        return $encryptId;
57
    }
58
59
    /**
60
     * Decryption for Id.
61
     *
62
     * @access public
63
     * @static static method
64
     * @param  string	$id
65
     * @return integer
66
     * @throws Exception if $id is empty
67
     */
68
    public static function decryptId($id){
69
70
        if(empty($id)){
71
            throw new Exception("the id to decrypt can't be empty");
72
        }
73
74
        $decryptId  = 0;
75
        $chars = self::getCharacters();
76
        $base  = strlen($chars);
77
        $len   = strlen($id) - 1;
78
79 View Code Duplication
        for ($t = $len; $t >= 0; $t--) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
80
            $bcp = bcpow($base, $len - $t);
81
            $decryptId += strpos($chars, substr($id, $t, 1)) * (int)$bcp;
82
        }
83
84
        return ((int)$decryptId - 1142) / 9518436;
85
    }
86
87
    /**
88
     * Decryption for Ids with dash '-', Example: "feed-km1chg3"
89
     *
90
     * @access public
91
     * @static static method
92
     * @param  string	$id
93
     * @return integer
94
     * @throws Exception if $id is empty
95
     */
96
    public static function decryptIdWithDash($id){
97
98
        if(empty($id)){
99
            throw new Exception("the id to decrypt can't be empty");
100
        }
101
102
        $decryptId  = 0;
103
        $chars = self::getCharacters();
104
        $base  = strlen($chars);
105
        $id    = explode("-", $id)[1];
106
107
        $len = strlen($id) - 1;
108
109 View Code Duplication
        for ($t = $len; $t >= 0; $t--) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
110
            $bcp = bcpow($base, $len - $t);
111
            $decryptId = $decryptId + strpos($chars, substr($id, $t, 1)) * (int)$bcp;
112
        }
113
114
        return ((int)$decryptId - 1142) / 9518436;
115
    }
116
117
    /**
118
     * get characters that will be used in encryption/decryption provided by a key
119
     *
120
     * @access private
121
     * @static static method
122
     * @return string
123
     * @throws Exception if $id is empty
124
     */
125
    private static function getCharacters(){
126
127
        $chars  = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
128
129
        $i = [];
130
        for ($n = 0; $n < strlen($chars); $n++) {
131
            $i[] = substr($chars, $n, 1);
132
        }
133
134
        $key_hash = hash('sha256', Config::get('HASH_KEY'));
135
        $key_hash = (strlen($key_hash) < strlen($chars) ? hash('sha512', Config::get('HASH_KEY')) : $key_hash);
136
137
        for ($n = 0; $n < strlen($chars); $n++) {
138
            $p[] =  substr($key_hash, $n, 1);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$p was never initialized. Although not strictly required by PHP, it is generally a good practice to add $p = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
139
        }
140
141
        array_multisort($p, SORT_DESC, $i);
142
        $chars = implode($i);
143
144
        return $chars;
145
    }
146
147
    /**
148
     * Encrypt a string.
149
     *
150
     * @access public
151
     * @static static method
152
     * @param  string	$plain
153
     * @return string
154
     * @throws Exception If functions don't exists
155
     */
156
    public static function encrypt($plain){
157
158
        if(!function_exists('openssl_cipher_iv_length') ||
159
            !function_exists('openssl_random_pseudo_bytes') ||
160
            !function_exists('openssl_encrypt')){
161
            throw new Exception("Encryption function don't exists");
162
        }
163
164
        // generate initialization vector,
165
        // this will make $iv different every time,
166
        // so, encrypted string will be also different.
167
        $iv_size = openssl_cipher_iv_length(self::CIPHER);
168
        $iv      = openssl_random_pseudo_bytes($iv_size);
169
170
        // generate key for authentication using ENCRYPTION_KEY & HMAC_SALT
171
        $key = mb_substr(hash(self::HASH_FUNCTION, Config::get('ENCRYPTION_KEY') . Config::get('HMAC_SALT')), 0, 32, '8bit');
172
173
        // append initialization vector
174
        $encrypted_string = openssl_encrypt($plain, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
175
        $ciphertext       = $iv . $encrypted_string;
176
177
        // apply the HMAC
178
        $hmac = hash_hmac('sha256', $ciphertext, $key);
179
180
        return $hmac . $ciphertext;
181
    }
182
183
    /**
184
     * Decrypted a string.
185
     *
186
     * @access public
187
     * @static static method
188
     * @param  string $ciphertext
189
     * @return string
190
     * @throws Exception If $ciphertext is empty, or If functions don't exists
191
     */
192
    public static function decrypt($ciphertext){
193
194
        if(empty($ciphertext)){
195
            throw new Exception("the string to decrypt can't be empty");
196
        }
197
198
        if(!function_exists('openssl_cipher_iv_length') ||
199
            !function_exists('openssl_decrypt')){
200
            throw new Exception("Encryption function don't exists");
201
        }
202
203
        // generate key used for authentication using ENCRYPTION_KEY & HMAC_SALT
204
        $key = mb_substr(hash(self::HASH_FUNCTION, Config::get('ENCRYPTION_KEY') . Config::get('HMAC_SALT')), 0, 32, '8bit');
205
206
        // split cipher into: hmac, cipher & iv
207
        $macSize    = 64;
208
        $hmac 	    = mb_substr($ciphertext, 0, $macSize, '8bit');
209
        $iv_cipher  = mb_substr($ciphertext, $macSize, null, '8bit');
210
211
        // generate original hmac & compare it with the one in $ciphertext
212
        $originalHmac = hash_hmac('sha256', $iv_cipher, $key);
213
        if(!self::hashEquals($hmac, $originalHmac)){
214
            return false;
215
        }
216
217
        // split out the initialization vector and cipher
218
        $iv_size = openssl_cipher_iv_length(self::CIPHER);
219
        $iv      = mb_substr($iv_cipher, 0, $iv_size, '8bit');
220
        $cipher  = mb_substr($iv_cipher, $iv_size, null, '8bit');
221
222
        return openssl_decrypt($cipher, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv);
223
    }
224
225
    /**
226
     * A timing attack resistant comparison.
227
     *
228
     * @access private
229
     * @static static method
230
     * @param string $hmac The hmac from the ciphertext being decrypted.
231
     * @param string $compare The comparison hmac.
232
     * @return bool
233
     * @see https://github.com/sarciszewski/php-future/blob/bd6c91fb924b2b35a3e4f4074a642868bd051baf/src/Security.php#L36
234
     */
235
    private static function hashEquals($hmac, $compare){
236
237
        if (function_exists('hash_equals')) {
238
            return hash_equals($hmac, $compare);
239
        }
240
241
        // if hash_equals() is not available,
242
        // then use the following snippet.
243
        // It's equivalent to hash_equals() in PHP 5.6.
244
        $hashLength    = mb_strlen($hmac, '8bit');
245
        $compareLength = mb_strlen($compare, '8bit');
246
247
        if ($hashLength !== $compareLength) {
248
            return false;
249
        }
250
251
        $result = 0;
252
        for ($i = 0; $i < $hashLength; $i++) {
253
            $result |= (ord($hmac[$i]) ^ ord($compare[$i]));
254
        }
255
256
        return $result === 0;
257
    }
258
}
259