PageRenderTime 522ms CodeModel.GetById 181ms app.highlight 182ms RepoModel.GetById 150ms app.codeStats 0ms

/phpseclib/Crypt/Hash.php

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