PageRenderTime 81ms CodeModel.GetById 52ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/OStatus/extlib/phpseclib/Crypt/Hash.php

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