PageRenderTime 8ms CodeModel.GetById 2ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 1ms

/sites/all/modules/aes/phpseclib/Crypt/Hash.php

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