|
1 <?php |
|
2 |
|
3 /* |
|
4 * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between |
|
5 * Version 1.1.2 (Caoineag alpha 2) |
|
6 * Copyright (C) 2006-2007 Dan Fuhry |
|
7 * diffiehellman.php - Diffie Hellman key exchange and supporting functions |
|
8 * |
|
9 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License |
|
10 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. |
|
14 */ |
|
15 |
|
16 /** |
|
17 * Class to handle math operations that require the use of >32-bit integers. |
|
18 */ |
|
19 |
|
20 class EnanoMath |
|
21 { |
|
22 |
|
23 var $api = 'gmp'; |
|
24 var $limb = 16; |
|
25 |
|
26 function __construct() |
|
27 { |
|
28 /* |
|
29 // big_int support is untested. |
|
30 if ( extension_loaded('big_int') ) |
|
31 { |
|
32 $this->api = 'bigint'; |
|
33 } |
|
34 else |
|
35 */ |
|
36 if ( function_exists('gmp_init') ) |
|
37 { |
|
38 $this->api = 'gmp'; |
|
39 } |
|
40 else if ( function_exists('bcpow') ) |
|
41 { |
|
42 $this->api = 'bcmath'; |
|
43 } |
|
44 else |
|
45 { |
|
46 throw new Exception('dh_err_not_supported'); |
|
47 } |
|
48 } |
|
49 |
|
50 function powmod($base, $pow, $mod) |
|
51 { |
|
52 switch($this->api) |
|
53 { |
|
54 case 'bigint': |
|
55 return ( pow($base, $pow) % $mod ); |
|
56 break; |
|
57 case 'gmp': |
|
58 return ( function_exists('gmp_powm') ) ? gmp_powm($base, $pow, $mod) : gmp_mod(gmp_pow($base, $pow), $mod); |
|
59 break; |
|
60 case 'bcmath': |
|
61 return ( function_exists('bcpowmod') ) ? bcpowmod($base, $pow, $mod) : bcmod( bcpow($base, $pow), $mod ); |
|
62 break; |
|
63 } |
|
64 } |
|
65 |
|
66 function random($len) |
|
67 { |
|
68 switch($this->api) |
|
69 { |
|
70 case 'gmp': |
|
71 return gmp_random($len); |
|
72 break; |
|
73 case 'bcmath': |
|
74 return $this->_bcmath_random($len); |
|
75 break; |
|
76 case 'bigint': |
|
77 return $this->_bigint_random($len); |
|
78 break; |
|
79 } |
|
80 } |
|
81 |
|
82 function _bcmath_random($len) |
|
83 { |
|
84 $len = ( $this->limb / 2 ) * $len; |
|
85 $chars = '0123456789abcdef'; |
|
86 $ret = ''; |
|
87 for ( $i = 0; $i < $len; $i++ ) |
|
88 { |
|
89 $chid = mt_rand ( 0, strlen($chars) - 1 ); |
|
90 $chr = $chars{$chid}; |
|
91 $ret .= $chr; |
|
92 } |
|
93 return $this->basecon($ret, 16, 10); |
|
94 } |
|
95 |
|
96 function _bigint_random($len) |
|
97 { |
|
98 $len = ( $this->limb / 2 ) * $len; |
|
99 $chars = '0123456789abcdef'; |
|
100 $ret = ''; |
|
101 for ( $i = 0; $i < $len; $i++ ) |
|
102 { |
|
103 $chid = mt_rand ( 0, strlen($chars) - 1 ); |
|
104 $chr = $chars{$chid}; |
|
105 $ret .= $chr; |
|
106 } |
|
107 return $this->basecon($ret, 16, 10); |
|
108 } |
|
109 |
|
110 function basecon($int, $from, $to) |
|
111 { |
|
112 switch($this->api) |
|
113 { |
|
114 case 'gmp': |
|
115 return gmp_strval(gmp_init($int, $from), $to); |
|
116 break; |
|
117 case 'bcmath': |
|
118 return $this->_bcmath_baseconv($int, $from, $to); |
|
119 break; |
|
120 case 'bigint': |
|
121 return base_convert($int, $from, $to); |
|
122 break; |
|
123 } |
|
124 } |
|
125 |
|
126 function str($res, $base = 10) |
|
127 { |
|
128 switch($this->api) |
|
129 { |
|
130 case 'bigint': |
|
131 case 'bcmath': |
|
132 return strval($this->basecon($res, 10, $base)); |
|
133 break; |
|
134 case 'gmp': |
|
135 return gmp_strval($res, $base); |
|
136 break; |
|
137 } |
|
138 } |
|
139 |
|
140 function compare($v1, $v2) |
|
141 { |
|
142 switch($this->api) |
|
143 { |
|
144 case 'bigint': |
|
145 return ( $v1 === $v2 ); |
|
146 break; |
|
147 case 'bcmath': |
|
148 return ( bccomp($v1, $v2) === 0 ); |
|
149 break; |
|
150 case 'gmp': |
|
151 return ( gmp_cmp($v1, $v2) === 0 ); |
|
152 break; |
|
153 } |
|
154 } |
|
155 |
|
156 function _bcmath_baseconv($int, $from, $to) |
|
157 { |
|
158 if ( $from != 10 ) |
|
159 $int = $this->_bcmath_base2dec($int, $from); |
|
160 if ( $to != 10 ) |
|
161 $int = $this->_bcmath_dec2base($int, $to); |
|
162 return $int; |
|
163 } |
|
164 |
|
165 // from us.php.net/bc: |
|
166 // convert a decimal value to any other base value |
|
167 function _bcmath_dec2base($dec,$base,$digits=FALSE) { |
|
168 if($base<2 or $base>256) die("Invalid Base: ".$base); |
|
169 bcscale(0); |
|
170 $value=""; |
|
171 if(!$digits) $digits=$this->_bcmath_digits($base); |
|
172 while($dec>$base-1) { |
|
173 $rest=bcmod($dec,$base); |
|
174 $dec=bcdiv($dec,$base); |
|
175 $value=$digits[$rest].$value; |
|
176 } |
|
177 $value=$digits[intval($dec)].$value; |
|
178 return (string) $value; |
|
179 } |
|
180 |
|
181 // convert another base value to its decimal value |
|
182 function _bcmath_base2dec($value,$base,$digits=FALSE) { |
|
183 if($base<2 or $base>256) die("Invalid Base: ".$base); |
|
184 bcscale(0); |
|
185 if($base<37) $value=strtolower($value); |
|
186 if(!$digits) $digits=$this->_bcmath_digits($base); |
|
187 $size=strlen($value); |
|
188 $dec="0"; |
|
189 for($loop=0;$loop<$size;$loop++) { |
|
190 $element=strpos($digits,$value[$loop]); |
|
191 $power=bcpow($base,$size-$loop-1); |
|
192 $dec=bcadd($dec,bcmul($element,$power)); |
|
193 } |
|
194 return (string) $dec; |
|
195 } |
|
196 |
|
197 function _bcmath_digits($base) { |
|
198 if($base>64) { |
|
199 $digits=""; |
|
200 for($loop=0;$loop<256;$loop++) { |
|
201 $digits.=chr($loop); |
|
202 } |
|
203 } else { |
|
204 $digits ="0123456789abcdefghijklmnopqrstuvwxyz"; |
|
205 $digits.="ABCDEFGHIJKLMNOPQRSTUVWXYZ-_"; |
|
206 } |
|
207 $digits=substr($digits,0,$base); |
|
208 return (string) $digits; |
|
209 } |
|
210 } |
|
211 |
|
212 /** |
|
213 * The Diffie-Hellman key exchange protocol |
|
214 */ |
|
215 |
|
216 $GLOBALS['_math'] = new EnanoMath(); |
|
217 // Our prime number as a base for operations. |
|
218 $GLOBALS['dh_prime'] = '82818079787776757473727170696867666564636261605958575655545352515049484746454443424140393837363534333231302928272625242322212019181716151413121110987654321'; |
|
219 |
|
220 // g, a primitive root used as an exponent |
|
221 // (2 and 5 are acceptable, but BigInt is faster with odd numbers) |
|
222 $GLOBALS['dh_g'] = '5'; |
|
223 |
|
224 /** |
|
225 * Generates a Diffie-Hellman private key |
|
226 * @return string(BigInt) |
|
227 */ |
|
228 |
|
229 function dh_gen_private() |
|
230 { |
|
231 global $_math; |
|
232 return $_math->random(256); |
|
233 } |
|
234 |
|
235 /** |
|
236 * Calculates the public key from the private key |
|
237 * @param string(BigInt) |
|
238 * @return string(BigInt) |
|
239 */ |
|
240 |
|
241 function dh_gen_public($b) |
|
242 { |
|
243 global $_math, $dh_g, $dh_prime; |
|
244 return $_math->powmod($dh_g, $b, $dh_prime); |
|
245 } |
|
246 |
|
247 /** |
|
248 * Calculates the shared secret. |
|
249 * @param string(BigInt) Our private key |
|
250 * @param string(BigInt) Remote party's public key |
|
251 * @return string(BigInt) |
|
252 */ |
|
253 |
|
254 function dh_gen_shared_secret($a, $B) |
|
255 { |
|
256 global $_math, $dh_g, $dh_prime; |
|
257 return $_math->powmod($B, $a, $dh_prime); |
|
258 } |
|
259 |
|
260 /* |
|
261 SHA-256 algorithm - ported from Javascript |
|
262 |
|
263 Copyright (c) 2003-2004, Angel Marin |
|
264 All rights reserved. |
|
265 Portions copyright (c) 2008 Dan Fuhry. |
|
266 |
|
267 Redistribution and use in source and binary forms, with or without modification, |
|
268 are permitted provided that the following conditions are met: |
|
269 |
|
270 * Redistributions of source code must retain the above copyright notice, this |
|
271 list of conditions and the following disclaimer. |
|
272 * Redistributions in binary form must reproduce the above copyright notice, |
|
273 this list of conditions and the following disclaimer in the documentation |
|
274 and/or other materials provided with the distribution. |
|
275 * Neither the name of the <ORGANIZATION> nor the names of its contributors may |
|
276 be used to endorse or promote products derived from this software without |
|
277 specific prior written permission. |
|
278 |
|
279 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
280 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
281 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
282 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
|
283 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
284 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
285 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
286 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
287 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
|
288 OF THE POSSIBILITY OF SUCH DAMAGE. |
|
289 */ |
|
290 class SHA256 |
|
291 { |
|
292 var $chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ |
|
293 |
|
294 function safe_add ($x, $y) { |
|
295 $lsw = ($x & 0xFFFF) + ($y & 0xFFFF); |
|
296 $msw = ($x >> 16) + ($y >> 16) + ($lsw >> 16); |
|
297 return ($msw << 16) | ($lsw & 0xFFFF); |
|
298 } |
|
299 function rshz($X, $n) |
|
300 { |
|
301 // equivalent to $X >>> $n in javascript |
|
302 // pulled from http://www.tapouillo.com/firefox_extension/sourcecode.txt, public domain |
|
303 $z = hexdec(80000000); |
|
304 if ($z & $X) |
|
305 { |
|
306 $X = ($X>>1); |
|
307 $X &= (~$z); |
|
308 $X |= 0x40000000; |
|
309 $X = ($X>>($n-1)); |
|
310 } |
|
311 else |
|
312 { |
|
313 $X = ($X>>$n); |
|
314 } |
|
315 return $X; |
|
316 } |
|
317 function S ($X, $n) {return ( $this->rshz($X, $n) ) | ($X << (32 - $n));} |
|
318 function R ($X, $n) {return ( $this->rshz($X, $n) );} |
|
319 function Ch($x, $y, $z) {return (($x & $y) ^ ((~$x) & $z));} |
|
320 function Maj($x, $y, $z) {return (($x & $y) ^ ($x & $z) ^ ($y & $z));} |
|
321 function Sigma0256($x) {return ($this->S($x, 2) ^ $this->S($x, 13) ^ $this->S($x, 22));} |
|
322 function Sigma1256($x) {return ($this->S($x, 6) ^ $this->S($x, 11) ^ $this->S($x, 25));} |
|
323 function Gamma0256($x) {return ($this->S($x, 7) ^ $this->S($x, 18) ^ $this->R($x, 3));} |
|
324 function Gamma1256($x) {return ($this->S($x, 17) ^ $this->S($x, 19) ^ $this->R($x, 10));} |
|
325 function core_sha256 ($m, $l) { |
|
326 $K = Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2); |
|
327 $HASH = Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19); |
|
328 $W = Array(64); |
|
329 /* append padding */ |
|
330 $m[$l >> 5] |= 0x80 << (24 - $l % 32); |
|
331 $m[(($l + 64 >> 9) << 4) + 15] = $l; |
|
332 for ( $i = 0; $i<count($m); $i+=16 ) { |
|
333 $a = $HASH[0]; |
|
334 $b = $HASH[1]; |
|
335 $c = $HASH[2]; |
|
336 $d = $HASH[3]; |
|
337 $e = $HASH[4]; |
|
338 $f = $HASH[5]; |
|
339 $g = $HASH[6]; |
|
340 $h = $HASH[7]; |
|
341 for ( $j = 0; $j<64; $j++) |
|
342 { |
|
343 if ( $j < 16 ) |
|
344 { |
|
345 $W[$j] = ( isset($m[$j + $i]) ) ? $m[$j + $i] : 0; |
|
346 } |
|
347 else |
|
348 { |
|
349 $W[$j] = $this->safe_add( |
|
350 $this->safe_add( |
|
351 $this->safe_add( |
|
352 $this->Gamma1256($W[$j - 2]), $W[$j - 7]), |
|
353 $this->Gamma0256($W[$j - 15])), |
|
354 $W[$j - 16]); |
|
355 } |
|
356 $T1 = $this->safe_add( |
|
357 $this->safe_add( |
|
358 $this->safe_add( |
|
359 $this->safe_add($h, $this->Sigma1256($e) |
|
360 ), |
|
361 $this->Ch($e, $f, $g)), |
|
362 $K[$j]), |
|
363 $W[$j]); |
|
364 $T2 = $this->safe_add($this->Sigma0256($a), $this->Maj($a, $b, $c)); |
|
365 $h = $g; |
|
366 $g = $f; |
|
367 $f = $e; |
|
368 $e = $this->safe_add($d, $T1); |
|
369 $d = $c; |
|
370 $c = $b; |
|
371 $b = $a; |
|
372 $a = $this->safe_add($T1, $T2); |
|
373 } |
|
374 $HASH[0] = $this->safe_add($a, $HASH[0]); |
|
375 $HASH[1] = $this->safe_add($b, $HASH[1]); |
|
376 $HASH[2] = $this->safe_add($c, $HASH[2]); |
|
377 $HASH[3] = $this->safe_add($d, $HASH[3]); |
|
378 $HASH[4] = $this->safe_add($e, $HASH[4]); |
|
379 $HASH[5] = $this->safe_add($f, $HASH[5]); |
|
380 $HASH[6] = $this->safe_add($g, $HASH[6]); |
|
381 $HASH[7] = $this->safe_add($h, $HASH[7]); |
|
382 } |
|
383 return $HASH; |
|
384 } |
|
385 function str2binb ($str) { |
|
386 $bin = Array(); |
|
387 for ( $i = 0; $i < strlen($str); $i++ ) |
|
388 { |
|
389 $byte = ord($str{$i}); |
|
390 $block = floor($i / 4); |
|
391 $stage = $i % 4; |
|
392 if ( $stage == 0 ) |
|
393 { |
|
394 $bin[$block] = $byte; |
|
395 } |
|
396 else |
|
397 { |
|
398 $bin[$block] <<= 8; |
|
399 $bin[$block] |= $byte; |
|
400 } |
|
401 } |
|
402 while ( $stage < 3 ) |
|
403 { |
|
404 $stage++; |
|
405 $bin[$block] <<= 8; |
|
406 } |
|
407 return $bin; |
|
408 } |
|
409 function byte2hex($byte) |
|
410 { |
|
411 $b = dechex(ord($byte)); |
|
412 return ( strlen($b) < 2 ) ? "0$b" : $b; |
|
413 } |
|
414 function binb2hex ($binarray) { |
|
415 $hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ |
|
416 $hex_tab = $hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; |
|
417 $str = ""; |
|
418 foreach ( $binarray as $bytes ) |
|
419 { |
|
420 $str .= implode('', array( |
|
421 $this->byte2hex(chr(( $bytes >> 24 ) & 0xFF)), |
|
422 $this->byte2hex(chr(( $bytes >> 16 ) & 0xFF)), |
|
423 $this->byte2hex(chr(( $bytes >> 8 ) & 0xFF)), |
|
424 $this->byte2hex(chr($bytes & 0xFF)) |
|
425 )); |
|
426 } |
|
427 return $str; |
|
428 } |
|
429 function hex_sha256 ( $s ) |
|
430 { |
|
431 return $this->binb2hex( |
|
432 $this->core_sha256( |
|
433 $this->str2binb($s), |
|
434 strlen($s) * $this->chrsz) |
|
435 ); |
|
436 } |
|
437 } |
|
438 |
|
439 if ( !function_exists('sha256') ) |
|
440 { |
|
441 function sha256($text) |
|
442 { |
|
443 static $sha_obj = false; |
|
444 if ( !is_object($sha_obj) ) |
|
445 $sha_obj = new SHA256(); |
|
446 return $sha_obj->hex_sha256($text); |
|
447 } |
|
448 } |
|
449 |
|
450 ?> |