]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/extlib/phpseclib/Crypt/Hash.php
Latest phpseclib stuff and moved into its own dir.
[quix0rs-gnu-social.git] / plugins / OStatus / extlib / phpseclib / Crypt / Hash.php
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  */
65 define('CRYPT_HASH_MODE_INTERNAL', 1);
66 /**
67  * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
68  */
69 define('CRYPT_HASH_MODE_MHASH',    2);
70 /**
71  * Toggles the hash() implementation, which works on PHP 5.1.2+.
72  */
73 define('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  */
84 class 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 }