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