Total Complexity | 60 |
Total Lines | 644 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like Hash 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.
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 Hash, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
50 | class Hash |
||
51 | { |
||
52 | /**#@+ |
||
53 | * @access private |
||
54 | * @see \phpseclib\Crypt\Hash::__construct() |
||
55 | */ |
||
56 | /** |
||
57 | * Toggles the internal implementation |
||
58 | */ |
||
59 | public const MODE_INTERNAL = 1; |
||
60 | /** |
||
61 | * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. |
||
62 | */ |
||
63 | public const MODE_MHASH = 2; |
||
64 | /** |
||
65 | * Toggles the hash() implementation, which works on PHP 5.1.2+. |
||
66 | */ |
||
67 | public const MODE_HASH = 3; |
||
68 | /**#@-*/ |
||
69 | |||
70 | /** |
||
71 | * Hash Parameter |
||
72 | * |
||
73 | * @see self::setHash() |
||
74 | * @var int |
||
75 | * @access private |
||
76 | */ |
||
77 | public $hashParam; |
||
78 | |||
79 | /** |
||
80 | * Byte-length of compression blocks / key (Internal HMAC) |
||
81 | * |
||
82 | * @see self::setAlgorithm() |
||
83 | * @var int |
||
84 | * @access private |
||
85 | */ |
||
86 | public $b; |
||
87 | |||
88 | /** |
||
89 | * Byte-length of hash output (Internal HMAC) |
||
90 | * |
||
91 | * @see self::setHash() |
||
92 | * @var int |
||
93 | * @access private |
||
94 | */ |
||
95 | public $l = false; |
||
96 | |||
97 | /** |
||
98 | * Hash Algorithm |
||
99 | * |
||
100 | * @see self::setHash() |
||
101 | * @var string |
||
102 | * @access private |
||
103 | */ |
||
104 | public $hash; |
||
105 | |||
106 | /** |
||
107 | * Key |
||
108 | * |
||
109 | * @see self::setKey() |
||
110 | * @var string |
||
111 | * @access private |
||
112 | */ |
||
113 | public $key = false; |
||
114 | |||
115 | /** |
||
116 | * Outer XOR (Internal HMAC) |
||
117 | * |
||
118 | * @see self::setKey() |
||
119 | * @var string |
||
120 | * @access private |
||
121 | */ |
||
122 | public $opad; |
||
123 | |||
124 | /** |
||
125 | * Inner XOR (Internal HMAC) |
||
126 | * |
||
127 | * @see self::setKey() |
||
128 | * @var string |
||
129 | * @access private |
||
130 | */ |
||
131 | public $ipad; |
||
132 | |||
133 | /** |
||
134 | * Default Constructor. |
||
135 | * |
||
136 | * @param string $hash |
||
137 | * @return \phpseclib\Crypt\Hash |
||
138 | * @access public |
||
139 | */ |
||
140 | public function __construct($hash = 'sha256') |
||
141 | { |
||
142 | if (!defined('CRYPT_HASH_MODE')) { |
||
143 | switch (true) { |
||
144 | case extension_loaded('hash'): |
||
145 | define('CRYPT_HASH_MODE', self::MODE_HASH); |
||
146 | break; |
||
147 | case extension_loaded('mhash'): |
||
148 | define('CRYPT_HASH_MODE', self::MODE_MHASH); |
||
149 | break; |
||
150 | default: |
||
151 | define('CRYPT_HASH_MODE', self::MODE_INTERNAL); |
||
152 | } |
||
153 | } |
||
154 | |||
155 | $this->setHash($hash); |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Sets the key for HMACs |
||
160 | * |
||
161 | * Keys can be of any length. |
||
162 | * |
||
163 | * @access public |
||
164 | * @param string $key |
||
165 | */ |
||
166 | public function setKey($key = false) |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Gets the hash function. |
||
173 | * |
||
174 | * As set by the constructor or by the setHash() method. |
||
175 | * |
||
176 | * @access public |
||
177 | * @return string |
||
178 | */ |
||
179 | public function getHash() |
||
180 | { |
||
181 | return $this->hashParam; |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Sets the hash function. |
||
186 | * |
||
187 | * @access public |
||
188 | * @param string $hash |
||
189 | */ |
||
190 | public function setHash($hash) |
||
191 | { |
||
192 | $this->hashParam = $hash = strtolower($hash); |
||
193 | switch ($hash) { |
||
194 | case 'sha256-96': |
||
195 | case 'sha512-96': |
||
196 | $hash = substr($hash, 0, -3); |
||
197 | $this->l = 12; // 96 / 8 = 12 |
||
198 | break; |
||
199 | case 'sha256': |
||
200 | $this->l = 32; |
||
201 | break; |
||
202 | case 'sha384': |
||
203 | $this->l = 48; |
||
204 | break; |
||
205 | case 'sha512': |
||
206 | $this->l = 64; |
||
207 | } |
||
208 | |||
209 | switch ($hash) { |
||
210 | case 'sha384': |
||
211 | case 'sha512': |
||
212 | $mode = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE; |
||
213 | break; |
||
214 | default: |
||
215 | $mode = CRYPT_HASH_MODE; |
||
216 | } |
||
217 | |||
218 | switch ($mode) { |
||
219 | case self::MODE_MHASH: |
||
220 | switch ($hash) { |
||
221 | case 'sha256': |
||
222 | $this->hash = MHASH_SHA256; |
||
223 | break; |
||
224 | default: |
||
225 | $this->hash = MHASH_SHA256; |
||
226 | } |
||
227 | return; |
||
228 | case self::MODE_HASH: |
||
229 | switch ($hash) { |
||
230 | case 'sha256': |
||
231 | case 'sha384': |
||
232 | case 'sha512': |
||
233 | $this->hash = $hash; |
||
234 | return; |
||
235 | default: |
||
236 | $this->hash = 'sha256'; |
||
237 | } |
||
238 | return; |
||
239 | } |
||
240 | |||
241 | switch ($hash) { |
||
242 | case 'sha256': |
||
243 | $this->b = 64; |
||
244 | $this->hash = array($this, '_sha256'); |
||
245 | break; |
||
246 | case 'sha384': |
||
247 | case 'sha512': |
||
248 | $this->b = 128; |
||
249 | $this->hash = array($this, '_sha512'); |
||
250 | break; |
||
251 | default: |
||
252 | $this->b = 64; |
||
253 | $this->hash = array($this, '_sha256'); |
||
254 | } |
||
255 | |||
256 | $this->ipad = str_repeat(chr(0x36), $this->b); |
||
257 | $this->opad = str_repeat(chr(0x5C), $this->b); |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Compute the HMAC. |
||
262 | * |
||
263 | * @access public |
||
264 | * @param string $text |
||
265 | * @return string |
||
266 | */ |
||
267 | public function hash($text) |
||
268 | { |
||
269 | $mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE; |
||
270 | |||
271 | if (!empty($this->key) || is_string($this->key)) { |
||
272 | switch ($mode) { |
||
273 | case self::MODE_MHASH: |
||
274 | $output = mhash($this->hash, $text, $this->key); |
||
275 | break; |
||
276 | case self::MODE_HASH: |
||
277 | $output = hash_hmac($this->hash, $text, $this->key, true); |
||
278 | break; |
||
279 | case self::MODE_INTERNAL: |
||
280 | /* "Applications that use keys longer than B bytes will first hash the key using H and then use the |
||
281 | resultant L byte string as the actual key to HMAC." |
||
282 | |||
283 | -- http://tools.ietf.org/html/rfc2104#section-2 */ |
||
284 | $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key; |
||
285 | |||
286 | $key = str_pad($key, $this->b, chr(0)); // step 1 |
||
287 | $temp = $this->ipad ^ $key; // step 2 |
||
288 | $temp .= $text; // step 3 |
||
289 | $temp = call_user_func($this->hash, $temp); // step 4 |
||
290 | $output = $this->opad ^ $key; // step 5 |
||
291 | $output.= $temp; // step 6 |
||
292 | $output = call_user_func($this->hash, $output); // step 7 |
||
293 | } |
||
294 | } else { |
||
295 | switch ($mode) { |
||
296 | case self::MODE_MHASH: |
||
297 | $output = mhash($this->hash, $text); |
||
298 | break; |
||
299 | case self::MODE_HASH: |
||
300 | $output = hash($this->hash, $text, true); |
||
301 | break; |
||
302 | case self::MODE_INTERNAL: |
||
303 | $output = call_user_func($this->hash, $text); |
||
304 | } |
||
305 | } |
||
306 | |||
307 | return substr($output, 0, $this->l); |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Returns the hash length (in bytes) |
||
312 | * |
||
313 | * @access public |
||
314 | * @return int |
||
315 | */ |
||
316 | public function getLength() |
||
317 | { |
||
318 | return $this->l; |
||
319 | } |
||
320 | |||
321 | /** |
||
322 | * Pure-PHP implementation of SHA256 |
||
323 | * |
||
324 | * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. |
||
325 | * |
||
326 | * @access private |
||
327 | * @param string $m |
||
328 | */ |
||
329 | public function _sha256($m) |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Pure-PHP implementation of SHA384 and SHA512 |
||
431 | * |
||
432 | * @access private |
||
433 | * @param string $m |
||
434 | */ |
||
435 | public function _sha512($m) |
||
436 | { |
||
437 | static $init384, $init512, $k; |
||
438 | |||
439 | if (!isset($k)) { |
||
440 | // Initialize variables |
||
441 | $init384 = array( // initial values for SHA384 |
||
442 | 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', |
||
443 | '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' |
||
444 | ); |
||
445 | $init512 = array( // initial values for SHA512 |
||
446 | '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', |
||
447 | '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' |
||
448 | ); |
||
449 | |||
450 | for ($i = 0; $i < 8; $i++) { |
||
451 | $init384[$i] = new BigInteger($init384[$i], 16); |
||
452 | $init384[$i]->setPrecision(64); |
||
453 | $init512[$i] = new BigInteger($init512[$i], 16); |
||
454 | $init512[$i]->setPrecision(64); |
||
455 | } |
||
456 | |||
457 | // Initialize table of round constants |
||
458 | // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) |
||
459 | $k = array( |
||
460 | '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', |
||
461 | '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', |
||
462 | 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', |
||
463 | '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', |
||
464 | 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', |
||
465 | '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', |
||
466 | '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', |
||
467 | 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', |
||
468 | '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', |
||
469 | '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', |
||
470 | 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', |
||
471 | 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', |
||
472 | '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', |
||
473 | '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', |
||
474 | '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', |
||
475 | '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', |
||
476 | 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', |
||
477 | '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', |
||
478 | '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', |
||
479 | '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' |
||
480 | ); |
||
481 | |||
482 | for ($i = 0; $i < 80; $i++) { |
||
483 | $k[$i] = new BigInteger($k[$i], 16); |
||
484 | } |
||
485 | } |
||
486 | |||
487 | $hash = $this->l == 48 ? $init384 : $init512; |
||
488 | |||
489 | // Pre-processing |
||
490 | $length = strlen($m); |
||
491 | // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 |
||
492 | $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); |
||
493 | $m[$length] = chr(0x80); |
||
494 | // we don't support hashing strings 512MB long |
||
495 | $m.= pack('N4', 0, 0, 0, $length << 3); |
||
496 | |||
497 | // Process the message in successive 1024-bit chunks |
||
498 | $chunks = str_split($m, 128); |
||
499 | foreach ($chunks as $chunk) { |
||
500 | $w = array(); |
||
501 | for ($i = 0; $i < 16; $i++) { |
||
502 | $temp = new BigInteger($this->_string_shift($chunk, 8), 256); |
||
503 | $temp->setPrecision(64); |
||
504 | $w[] = $temp; |
||
505 | } |
||
506 | |||
507 | // Extend the sixteen 32-bit words into eighty 32-bit words |
||
508 | for ($i = 16; $i < 80; $i++) { |
||
509 | $temp = array( |
||
510 | $w[$i - 15]->bitwise_rightRotate(1), |
||
511 | $w[$i - 15]->bitwise_rightRotate(8), |
||
512 | $w[$i - 15]->bitwise_rightShift(7) |
||
513 | ); |
||
514 | $s0 = $temp[0]->bitwise_xor($temp[1]); |
||
515 | $s0 = $s0->bitwise_xor($temp[2]); |
||
516 | $temp = array( |
||
517 | $w[$i - 2]->bitwise_rightRotate(19), |
||
518 | $w[$i - 2]->bitwise_rightRotate(61), |
||
519 | $w[$i - 2]->bitwise_rightShift(6) |
||
520 | ); |
||
521 | $s1 = $temp[0]->bitwise_xor($temp[1]); |
||
522 | $s1 = $s1->bitwise_xor($temp[2]); |
||
523 | $w[$i] = $w[$i - 16]->copy(); |
||
524 | $w[$i] = $w[$i]->add($s0); |
||
525 | $w[$i] = $w[$i]->add($w[$i - 7]); |
||
526 | $w[$i] = $w[$i]->add($s1); |
||
527 | } |
||
528 | |||
529 | // Initialize hash value for this chunk |
||
530 | $a = $hash[0]->copy(); |
||
531 | $b = $hash[1]->copy(); |
||
532 | $c = $hash[2]->copy(); |
||
533 | $d = $hash[3]->copy(); |
||
534 | $e = $hash[4]->copy(); |
||
535 | $f = $hash[5]->copy(); |
||
536 | $g = $hash[6]->copy(); |
||
537 | $h = $hash[7]->copy(); |
||
538 | |||
539 | // Main loop |
||
540 | for ($i = 0; $i < 80; $i++) { |
||
541 | $temp = array( |
||
542 | $a->bitwise_rightRotate(28), |
||
543 | $a->bitwise_rightRotate(34), |
||
544 | $a->bitwise_rightRotate(39) |
||
545 | ); |
||
546 | $s0 = $temp[0]->bitwise_xor($temp[1]); |
||
547 | $s0 = $s0->bitwise_xor($temp[2]); |
||
548 | $temp = array( |
||
549 | $a->bitwise_and($b), |
||
550 | $a->bitwise_and($c), |
||
551 | $b->bitwise_and($c) |
||
552 | ); |
||
553 | $maj = $temp[0]->bitwise_xor($temp[1]); |
||
554 | $maj = $maj->bitwise_xor($temp[2]); |
||
555 | $t2 = $s0->add($maj); |
||
556 | |||
557 | $temp = array( |
||
558 | $e->bitwise_rightRotate(14), |
||
559 | $e->bitwise_rightRotate(18), |
||
560 | $e->bitwise_rightRotate(41) |
||
561 | ); |
||
562 | $s1 = $temp[0]->bitwise_xor($temp[1]); |
||
563 | $s1 = $s1->bitwise_xor($temp[2]); |
||
564 | $temp = array( |
||
565 | $e->bitwise_and($f), |
||
566 | $g->bitwise_and($e->bitwise_not()) |
||
567 | ); |
||
568 | $ch = $temp[0]->bitwise_xor($temp[1]); |
||
569 | $t1 = $h->add($s1); |
||
570 | $t1 = $t1->add($ch); |
||
571 | $t1 = $t1->add($k[$i]); |
||
572 | $t1 = $t1->add($w[$i]); |
||
573 | |||
574 | $h = $g->copy(); |
||
575 | $g = $f->copy(); |
||
576 | $f = $e->copy(); |
||
577 | $e = $d->add($t1); |
||
578 | $d = $c->copy(); |
||
579 | $c = $b->copy(); |
||
580 | $b = $a->copy(); |
||
581 | $a = $t1->add($t2); |
||
582 | } |
||
583 | |||
584 | // Add this chunk's hash to result so far |
||
585 | $hash = array( |
||
586 | $hash[0]->add($a), |
||
587 | $hash[1]->add($b), |
||
588 | $hash[2]->add($c), |
||
589 | $hash[3]->add($d), |
||
590 | $hash[4]->add($e), |
||
591 | $hash[5]->add($f), |
||
592 | $hash[6]->add($g), |
||
593 | $hash[7]->add($h) |
||
594 | ); |
||
595 | } |
||
596 | |||
597 | // Produce the final hash value (big-endian) |
||
598 | // (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) |
||
599 | $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . |
||
600 | $hash[4]->toBytes() . $hash[5]->toBytes(); |
||
601 | if ($this->l != 48) { |
||
602 | $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); |
||
603 | } |
||
604 | |||
605 | return $temp; |
||
606 | } |
||
607 | |||
608 | /** |
||
609 | * Right Rotate |
||
610 | * |
||
611 | * @access private |
||
612 | * @param int $int |
||
613 | * @param int $amt |
||
614 | * @see self::_sha256() |
||
615 | * @return int |
||
616 | */ |
||
617 | public function _rightRotate($int, $amt) |
||
622 | } |
||
623 | |||
624 | /** |
||
625 | * Right Shift |
||
626 | * |
||
627 | * @access private |
||
628 | * @param int $int |
||
629 | * @param int $amt |
||
630 | * @see self::_sha256() |
||
631 | * @return int |
||
632 | */ |
||
633 | public function _rightShift($int, $amt) |
||
634 | { |
||
635 | $mask = (1 << (32 - $amt)) - 1; |
||
636 | return ($int >> $amt) & $mask; |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * Not |
||
641 | * |
||
642 | * @access private |
||
643 | * @param int $int |
||
644 | * @see self::_sha256() |
||
645 | * @return int |
||
646 | */ |
||
647 | public function _not($int) |
||
648 | { |
||
649 | return ~$int & 0xFFFFFFFF; |
||
650 | } |
||
651 | |||
652 | /** |
||
653 | * Add |
||
654 | * |
||
655 | * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the |
||
656 | * possibility of overflow exists, care has to be taken. BigInteger could be used but this should be faster. |
||
657 | * |
||
658 | * @param int $... |
||
659 | * @return int |
||
660 | * @see self::_sha256() |
||
661 | * @access private |
||
662 | */ |
||
663 | public function _add() |
||
677 | } |
||
678 | |||
679 | /** |
||
680 | * String Shift |
||
681 | * |
||
682 | * Inspired by array_shift |
||
683 | * |
||
684 | * @param string $string |
||
685 | * @param int $index |
||
686 | * @return string |
||
687 | * @access private |
||
688 | */ |
||
689 | public function _string_shift(&$string, $index = 1) |
||
694 | } |
||
695 | } |
||
696 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.