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

/trustly/phpseclib/Crypt/Hash.php

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