PageRenderTime 6ms CodeModel.GetById 2ms app.highlight 30ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/core/vendor/phpseclib/Crypt/Hash.php

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