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