includes/diffiehellman.php
changeset 436 242353360e37
child 467 e4bbd6fb8df3
equal deleted inserted replaced
435:a434d60e525d 436:242353360e37
       
     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 ?>