PageRenderTime 3ms CodeModel.GetById 41ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/phpseclib/Crypt/Hash.php

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