PageRenderTime 552ms CodeModel.GetById 201ms app.highlight 192ms RepoModel.GetById 150ms app.codeStats 1ms

/php5-3/core/tools/secure/crypt/Hash.class.php

https://bitbucket.org/ronaldobrandini/framework
PHP | 814 lines | 472 code | 68 blank | 274 comment | 27 complexity | d66bf58278daefc836ba3af0fabbc210 MD5 | raw file
  1<?php
  2namespace core\tools\secure\crypt;
  3/**
  4 * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
  5 *
  6 * Uses hash() or mhash() if available and an internal implementation, otherwise.  Currently supports the following:
  7 *
  8 * md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
  9 *
 10 * If {@link Hash::setKey() setKey()} is called, {@link Hash::hash() hash()} will return the HMAC as opposed to
 11 * the hash.  If no valid algorithm is provided, sha1 will be used.
 12 *
 13 * PHP versions 4 and 5
 14 *
 15 * {@internal The variable names are the same as those in
 16 * {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
 17 *
 18 * Here's a short example of how to use this library:
 19 * <code>
 20 * <?php
 21 *    include 'Crypt/Hash.php';
 22 *
 23 *    $hash = new Hash('sha1');
 24 *
 25 *    $hash->setKey('abcdefg');
 26 *
 27 *    echo base64_encode($hash->hash('abcdefg'));
 28 * ?>
 29 * </code>
 30 *
 31 * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
 32 * of this software and associated documentation files (the "Software"), to deal
 33 * in the Software without restriction, including without limitation the rights
 34 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 35 * copies of the Software, and to permit persons to whom the Software is
 36 * furnished to do so, subject to the following conditions:
 37 *
 38 * The above copyright notice and this permission notice shall be included in
 39 * all copies or substantial portions of the Software.
 40 *
 41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 44 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 46 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 47 * THE SOFTWARE.
 48 *
 49 * @category  Crypt
 50 * @package   Hash
 51 * @author    Jim Wigginton <terrafrost@php.net>
 52 * @copyright MMVII Jim Wigginton
 53 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 54 * @link      http://phpseclib.sourceforge.net
 55 */
 56/* * #@+
 57 * @access private
 58 * @see Hash::Hash()
 59 */
 60
 61/**
 62 * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
 63 *
 64 * @package Hash
 65 * @author  Jim Wigginton <terrafrost@php.net>
 66 * @access  public
 67 */
 68class Hash{
 69
 70    /**
 71     * Hash Parameter
 72     *
 73     * @see Hash::setHash()
 74     * @var Integer
 75     * @access private
 76     */
 77    private $hashParam;
 78
 79    /**
 80     * Byte-length of compression blocks / key (Internal HMAC)
 81     *
 82     * @see Hash::setAlgorithm()
 83     * @var Integer
 84     * @access private
 85     */
 86    private $b;
 87
 88    /**
 89     * Byte-length of hash output (Internal HMAC)
 90     *
 91     * @see Hash::setHash()
 92     * @var Integer
 93     * @access private
 94     */
 95    private $l = false;
 96
 97    /**
 98     * Hash Algorithm
 99     *
100     * @see Hash::setHash()
101     * @var String
102     * @access private
103     */
104    private $hash;
105
106    /**
107     * Key
108     *
109     * @see Hash::setKey()
110     * @var String
111     * @access private
112     */
113    private $key = false;
114
115    /**
116     * Outer XOR (Internal HMAC)
117     *
118     * @see Hash::setKey()
119     * @var String
120     * @access private
121     */
122    private $opad;
123
124    /**
125     * Inner XOR (Internal HMAC)
126     *
127     * @see Hash::setKey()
128     * @var String
129     * @access private
130     */
131    private $ipad;
132
133    /**
134     * Default Constructor.
135     *
136     * @param optional String $hash
137     * @return Hash
138     * @access public
139     */
140    public function __construct($hash = 'sha1'){
141        if(!defined('CRYPT_HASH_MODE')){
142            switch(true){
143                case extension_loaded('hash'):
144                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
145                    break;
146                case extension_loaded('mhash'):
147                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
148                    break;
149                default:
150                    define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
151            }
152        }
153
154        $this->setHash($hash);
155    }
156
157    /**
158     * Sets the key for HMACs
159     *
160     * Keys can be of any length.
161     *
162     * @access public
163     * @param optional String $key
164     */
165    public function setKey($key = false){
166        $this->key = $key;
167    }
168
169    /**
170     * Gets the hash function.
171     *
172     * As set by the constructor or by the setHash() method.
173     *
174     * @access public
175     * @return String
176     */
177    public function getHash(){
178        return $this->hashParam;
179    }
180
181    /**
182     * Sets the hash function.
183     *
184     * @access public
185     * @param String $hash
186     */
187    public function setHash($hash){
188        $this->hashParam = $hash = strtolower($hash);
189        switch($hash){
190            case 'md5-96':
191            case 'sha1-96':
192                $this->l = 12; // 96 / 8 = 12
193                break;
194            case 'md2':
195            case 'md5':
196                $this->l = 16;
197                break;
198            case 'sha1':
199                $this->l = 20;
200                break;
201            case 'sha256':
202                $this->l = 32;
203                break;
204            case 'sha384':
205                $this->l = 48;
206                break;
207            case 'sha512':
208                $this->l = 64;
209        }
210
211        switch($hash){
212            case 'md2':
213                $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
214                        CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
215                break;
216            case 'sha384':
217            case 'sha512':
218                $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
219                break;
220            default:
221                $mode = CRYPT_HASH_MODE;
222        }
223
224        switch($mode){
225            case CRYPT_HASH_MODE_MHASH:
226                switch($hash){
227                    case 'md5':
228                    case 'md5-96':
229                        $this->hash = MHASH_MD5;
230                        break;
231                    case 'sha256':
232                        $this->hash = MHASH_SHA256;
233                        break;
234                    case 'sha1':
235                    case 'sha1-96':
236                    default:
237                        $this->hash = MHASH_SHA1;
238                }
239                return;
240            case CRYPT_HASH_MODE_HASH:
241                switch($hash){
242                    case 'md5':
243                    case 'md5-96':
244                        $this->hash = 'md5';
245                        return;
246                    case 'md2':
247                    case 'sha256':
248                    case 'sha384':
249                    case 'sha512':
250                        $this->hash = $hash;
251                        return;
252                    case 'sha1':
253                    case 'sha1-96':
254                    default:
255                        $this->hash = 'sha1';
256                }
257                return;
258        }
259
260        switch($hash){
261            case 'md2':
262                $this->b = 16;
263                $this->hash = array($this, '_md2');
264                break;
265            case 'md5':
266            case 'md5-96':
267                $this->b = 64;
268                $this->hash = array($this, '_md5');
269                break;
270            case 'sha256':
271                $this->b = 64;
272                $this->hash = array($this, '_sha256');
273                break;
274            case 'sha384':
275            case 'sha512':
276                $this->b = 128;
277                $this->hash = array($this, '_sha512');
278                break;
279            case 'sha1':
280            case 'sha1-96':
281            default:
282                $this->b = 64;
283                $this->hash = array($this, '_sha1');
284        }
285
286        $this->ipad = str_repeat(chr(0x36), $this->b);
287        $this->opad = str_repeat(chr(0x5C), $this->b);
288    }
289
290    /**
291     * Compute the HMAC.
292     *
293     * @access public
294     * @param String $text
295     * @return String
296     */
297    public function hash($text){
298        $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
299
300        if(!empty($this->key) || is_string($this->key)){
301            switch($mode){
302                case CRYPT_HASH_MODE_MHASH:
303                    $output = mhash($this->hash, $text, $this->key);
304                    break;
305                case CRYPT_HASH_MODE_HASH:
306                    $output = hash_hmac($this->hash, $text, $this->key, true);
307                    break;
308                case CRYPT_HASH_MODE_INTERNAL:
309                    /* "Applications that use keys longer than B bytes will first hash the key using H and then use the
310                      resultant L byte string as the actual key to HMAC."
311
312                      -- http://tools.ietf.org/html/rfc2104#section-2 */
313                    $key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
314
315                    $key = str_pad($key, $this->b, chr(0));      // step 1
316                    $temp = $this->ipad ^ $key;                   // step 2
317                    $temp .= $text;                                // step 3
318                    $temp = call_user_func($this->hash, $temp);   // step 4
319                    $output = $this->opad ^ $key;                   // step 5
320                    $output.= $temp;                                // step 6
321                    $output = call_user_func($this->hash, $output); // step 7
322            }
323        }else{
324            switch($mode){
325                case CRYPT_HASH_MODE_MHASH:
326                    $output = mhash($this->hash, $text);
327                    break;
328                case CRYPT_HASH_MODE_HASH:
329                    $output = hash($this->hash, $text, true);
330                    break;
331                case CRYPT_HASH_MODE_INTERNAL:
332                    $output = call_user_func($this->hash, $text);
333            }
334        }
335
336        return substr($output, 0, $this->l);
337    }
338
339    /**
340     * Returns the hash length (in bytes)
341     *
342     * @access public
343     * @return Integer
344     */
345    public function getLength(){
346        return $this->l;
347    }
348
349    /**
350     * Wrapper for MD5
351     *
352     * @access private
353     * @param String $m
354     */
355    private function _md5($m){
356        return pack('H*', md5($m));
357    }
358
359    /**
360     * Wrapper for SHA1
361     *
362     * @access private
363     * @param String $m
364     */
365    private function _sha1($m){
366        return pack('H*', sha1($m));
367    }
368
369    /**
370     * Pure-PHP implementation of MD2
371     *
372     * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
373     *
374     * @access private
375     * @param String $m
376     */
377    private function _md2($m){
378        static $s = array(
379            41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
380            19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
381            76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
382            138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
383            245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
384            148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
385            39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
386            181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
387            150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
388            112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
389            96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
390            85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
391            234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
392            129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
393            8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
394            203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
395            166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
396            31, 26, 219, 153, 141, 51, 159, 17, 131, 20
397        );
398
399        // Step 1. Append Padding Bytes
400        $pad = 16 - (strlen($m) & 0xF);
401        $m.= str_repeat(chr($pad), $pad);
402
403        $length = strlen($m);
404
405        // Step 2. Append Checksum
406        $c = str_repeat(chr(0), 16);
407        $l = chr(0);
408        for($i = 0; $i < $length; $i+= 16){
409            for($j = 0; $j < 16; $j++){
410                // RFC1319 incorrectly states that C[j] should be set to S[c xor L]
411                //$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
412                // per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
413                $c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
414                $l = $c[$j];
415            }
416        }
417        $m.= $c;
418
419        $length+= 16;
420
421        // Step 3. Initialize MD Buffer
422        $x = str_repeat(chr(0), 48);
423
424        // Step 4. Process Message in 16-Byte Blocks
425        for($i = 0; $i < $length; $i+= 16){
426            for($j = 0; $j < 16; $j++){
427                $x[$j + 16] = $m[$i + $j];
428                $x[$j + 32] = $x[$j + 16] ^ $x[$j];
429            }
430            $t = chr(0);
431            for($j = 0; $j < 18; $j++){
432                for($k = 0; $k < 48; $k++){
433                    $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
434                    //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
435                }
436                $t = chr(ord($t) + $j);
437            }
438        }
439
440        // Step 5. Output
441        return substr($x, 0, 16);
442    }
443
444    /**
445     * Pure-PHP implementation of SHA256
446     *
447     * 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}.
448     *
449     * @access private
450     * @param String $m
451     */
452    private function _sha256($m){
453        if(extension_loaded('suhosin')){
454            return pack('H*', sha256($m));
455        }
456
457        // Initialize variables
458        $hash = array(
459            0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
460        );
461        // Initialize table of round constants
462        // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
463        static $k = array(
464            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
465            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
466            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
467            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
468            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
469            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
470            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
471            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
472        );
473
474        // Pre-processing
475        $length = strlen($m);
476        // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
477        $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
478        $m[$length] = chr(0x80);
479        // we don't support hashing strings 512MB long
480        $m.= pack('N2', 0, $length << 3);
481
482        // Process the message in successive 512-bit chunks
483        $chunks = str_split($m, 64);
484        foreach($chunks as $chunk){
485            $w = array();
486            for($i = 0; $i < 16; $i++){
487                extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
488                $w[] = $temp;
489            }
490
491            // Extend the sixteen 32-bit words into sixty-four 32-bit words
492            for($i = 16; $i < 64; $i++){
493                $s0 = $this->_rightRotate($w[$i - 15], 7) ^
494                        $this->_rightRotate($w[$i - 15], 18) ^
495                        $this->_rightShift($w[$i - 15], 3);
496                $s1 = $this->_rightRotate($w[$i - 2], 17) ^
497                        $this->_rightRotate($w[$i - 2], 19) ^
498                        $this->_rightShift($w[$i - 2], 10);
499                $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
500            }
501
502            // Initialize hash value for this chunk
503            list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
504
505            // Main loop
506            for($i = 0; $i < 64; $i++){
507                $s0 = $this->_rightRotate($a, 2) ^
508                        $this->_rightRotate($a, 13) ^
509                        $this->_rightRotate($a, 22);
510                $maj = ($a & $b) ^
511                        ($a & $c) ^
512                        ($b & $c);
513                $t2 = $this->_add($s0, $maj);
514
515                $s1 = $this->_rightRotate($e, 6) ^
516                        $this->_rightRotate($e, 11) ^
517                        $this->_rightRotate($e, 25);
518                $ch = ($e & $f) ^
519                        ($this->_not($e) & $g);
520                $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
521
522                $h = $g;
523                $g = $f;
524                $f = $e;
525                $e = $this->_add($d, $t1);
526                $d = $c;
527                $c = $b;
528                $b = $a;
529                $a = $this->_add($t1, $t2);
530            }
531
532            // Add this chunk's hash to result so far
533            $hash = array(
534                $this->_add($hash[0], $a),
535                $this->_add($hash[1], $b),
536                $this->_add($hash[2], $c),
537                $this->_add($hash[3], $d),
538                $this->_add($hash[4], $e),
539                $this->_add($hash[5], $f),
540                $this->_add($hash[6], $g),
541                $this->_add($hash[7], $h)
542            );
543        }
544
545        // Produce the final hash value (big-endian)
546        return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
547    }
548
549    /**
550     * Pure-PHP implementation of SHA384 and SHA512
551     *
552     * @access private
553     * @param String $m
554     */
555    private function _sha512($m){
556        if(!class_exists('Math_BigInteger')){
557            include_once 'Math/BigInteger.php';
558        }
559
560        static $init384, $init512, $k;
561
562        if(!isset($k)){
563            // Initialize variables
564            $init384 = array(// initial values for SHA384
565                'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
566                '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
567            );
568            $init512 = array(// initial values for SHA512
569                '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
570                '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
571            );
572
573            for($i = 0; $i < 8; $i++){
574                $init384[$i] = new Math_BigInteger($init384[$i], 16);
575                $init384[$i]->setPrecision(64);
576                $init512[$i] = new Math_BigInteger($init512[$i], 16);
577                $init512[$i]->setPrecision(64);
578            }
579
580            // Initialize table of round constants
581            // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
582            $k = array(
583                '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
584                '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
585                'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
586                '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
587                'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
588                '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
589                '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
590                'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
591                '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
592                '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
593                'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
594                'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
595                '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
596                '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
597                '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
598                '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
599                'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
600                '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
601                '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
602                '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
603            );
604
605            for($i = 0; $i < 80; $i++){
606                $k[$i] = new Math_BigInteger($k[$i], 16);
607            }
608        }
609
610        $hash = $this->l == 48 ? $init384 : $init512;
611
612        // Pre-processing
613        $length = strlen($m);
614        // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
615        $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
616        $m[$length] = chr(0x80);
617        // we don't support hashing strings 512MB long
618        $m.= pack('N4', 0, 0, 0, $length << 3);
619
620        // Process the message in successive 1024-bit chunks
621        $chunks = str_split($m, 128);
622        foreach($chunks as $chunk){
623            $w = array();
624            for($i = 0; $i < 16; $i++){
625                $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
626                $temp->setPrecision(64);
627                $w[] = $temp;
628            }
629
630            // Extend the sixteen 32-bit words into eighty 32-bit words
631            for($i = 16; $i < 80; $i++){
632                $temp = array(
633                    $w[$i - 15]->bitwise_rightRotate(1),
634                    $w[$i - 15]->bitwise_rightRotate(8),
635                    $w[$i - 15]->bitwise_rightShift(7)
636                );
637                $s0 = $temp[0]->bitwise_xor($temp[1]);
638                $s0 = $s0->bitwise_xor($temp[2]);
639                $temp = array(
640                    $w[$i - 2]->bitwise_rightRotate(19),
641                    $w[$i - 2]->bitwise_rightRotate(61),
642                    $w[$i - 2]->bitwise_rightShift(6)
643                );
644                $s1 = $temp[0]->bitwise_xor($temp[1]);
645                $s1 = $s1->bitwise_xor($temp[2]);
646                $w[$i] = $w[$i - 16]->copy();
647                $w[$i] = $w[$i]->add($s0);
648                $w[$i] = $w[$i]->add($w[$i - 7]);
649                $w[$i] = $w[$i]->add($s1);
650            }
651
652            // Initialize hash value for this chunk
653            $a = $hash[0]->copy();
654            $b = $hash[1]->copy();
655            $c = $hash[2]->copy();
656            $d = $hash[3]->copy();
657            $e = $hash[4]->copy();
658            $f = $hash[5]->copy();
659            $g = $hash[6]->copy();
660            $h = $hash[7]->copy();
661
662            // Main loop
663            for($i = 0; $i < 80; $i++){
664                $temp = array(
665                    $a->bitwise_rightRotate(28),
666                    $a->bitwise_rightRotate(34),
667                    $a->bitwise_rightRotate(39)
668                );
669                $s0 = $temp[0]->bitwise_xor($temp[1]);
670                $s0 = $s0->bitwise_xor($temp[2]);
671                $temp = array(
672                    $a->bitwise_and($b),
673                    $a->bitwise_and($c),
674                    $b->bitwise_and($c)
675                );
676                $maj = $temp[0]->bitwise_xor($temp[1]);
677                $maj = $maj->bitwise_xor($temp[2]);
678                $t2 = $s0->add($maj);
679
680                $temp = array(
681                    $e->bitwise_rightRotate(14),
682                    $e->bitwise_rightRotate(18),
683                    $e->bitwise_rightRotate(41)
684                );
685                $s1 = $temp[0]->bitwise_xor($temp[1]);
686                $s1 = $s1->bitwise_xor($temp[2]);
687                $temp = array(
688                    $e->bitwise_and($f),
689                    $g->bitwise_and($e->bitwise_not())
690                );
691                $ch = $temp[0]->bitwise_xor($temp[1]);
692                $t1 = $h->add($s1);
693                $t1 = $t1->add($ch);
694                $t1 = $t1->add($k[$i]);
695                $t1 = $t1->add($w[$i]);
696
697                $h = $g->copy();
698                $g = $f->copy();
699                $f = $e->copy();
700                $e = $d->add($t1);
701                $d = $c->copy();
702                $c = $b->copy();
703                $b = $a->copy();
704                $a = $t1->add($t2);
705            }
706
707            // Add this chunk's hash to result so far
708            $hash = array(
709                $hash[0]->add($a),
710                $hash[1]->add($b),
711                $hash[2]->add($c),
712                $hash[3]->add($d),
713                $hash[4]->add($e),
714                $hash[5]->add($f),
715                $hash[6]->add($g),
716                $hash[7]->add($h)
717            );
718        }
719
720        // Produce the final hash value (big-endian)
721        // (Hash::hash() trims the output for hashes but not for HMACs.  as such, we trim the output here)
722        $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
723                $hash[4]->toBytes() . $hash[5]->toBytes();
724        if($this->l != 48){
725            $temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
726        }
727
728        return $temp;
729    }
730
731    /**
732     * Right Rotate
733     *
734     * @access private
735     * @param Integer $int
736     * @param Integer $amt
737     * @see _sha256()
738     * @return Integer
739     */
740    private function _rightRotate($int, $amt){
741        $invamt = 32 - $amt;
742        $mask = (1 << $invamt) - 1;
743        return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
744    }
745
746    /**
747     * Right Shift
748     *
749     * @access private
750     * @param Integer $int
751     * @param Integer $amt
752     * @see _sha256()
753     * @return Integer
754     */
755    private function _rightShift($int, $amt){
756        $mask = (1 << (32 - $amt)) - 1;
757        return ($int >> $amt) & $mask;
758    }
759
760    /**
761     * Not
762     *
763     * @access private
764     * @param Integer $int
765     * @see _sha256()
766     * @return Integer
767     */
768    private function _not($int){
769        return ~$int & 0xFFFFFFFF;
770    }
771
772    /**
773     * Add
774     *
775     * _sha256() adds multiple unsigned 32-bit integers.  Since PHP doesn't support unsigned integers and since the
776     * possibility of overflow exists, care has to be taken.  Math_BigInteger() could be used but this should be faster.
777     *
778     * @param Integer $...
779     * @return Integer
780     * @see _sha256()
781     * @access private
782     */
783    private function _add(){
784        static $mod;
785        if(!isset($mod)){
786            $mod = pow(2, 32);
787        }
788
789        $result = 0;
790        $arguments = func_get_args();
791        foreach($arguments as $argument){
792            $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
793        }
794
795        return fmod($result, $mod);
796    }
797
798    /**
799     * String Shift
800     *
801     * Inspired by array_shift
802     *
803     * @param String $string
804     * @param optional Integer $index
805     * @return String
806     * @access private
807     */
808    private function _string_shift(&$string, $index = 1){
809        $substr = substr($string, 0, $index);
810        $string = substr($string, $index);
811        return $substr;
812    }
813
814}