Вход Регистрация
Файл: public_html/lib/wmxi/WMSigner.php
Строк: 274
<?php
################################################################################
#                                                                              #
# Webmoney Signer PHP edition by DKameleon (http://dkameleon.com)              #
#                                                                              #
# Updates and new versions: http://my-tools.net/wmxi/                          #
#                                                                              #
# Server requirements:                                                         #
# - BCMath or GMP                                                              #
# - MD4 or MHash or Hash                                                       #
#                                                                              #
################################################################################


# including classes
if (!defined('__DIR__')) { define('__DIR__', dirname(__FILE__)); }
require_once(
__DIR__ . DIRECTORY_SEPARATOR . 'WMXILogger.php');
if (
file_exists(__DIR__ . DIRECTORY_SEPARATOR . 'MD4.php')) { include_once(__DIR__ . DIRECTORY_SEPARATOR . 'MD4.php'); }


# WMSigner class
class WMSigner {

    private 
$wmid = '';

    private 
$ekey = '';
    private 
$nkey = '';

    private 
$md4_use  = '';
    private 
$math_use = '';
    
    private 
$md4     = null;

    
# debug switch
    
private $debug = false;

    
# constructor
    
public function __construct($wmid, $key) {
        
$this->debug = defined('WMXI_LOG');
    
        
$this->math_use = $this->InitMath();
        
$this->md4_use  = $this->InitMD4();
        
WMXILogger::Append("$this->math_use = ".$this->math_use.";");
        
WMXILogger::Append("$this->md4_use = ".$this->md4_use.";");
    
        
$this->wmid = $wmid;

        
# loading e-n-key
        
if (isset($key['ekey']) && isset($key['nkey'])) {
            
$this->ekey = $key['ekey'];
            
$this->nkey = $key['nkey'];
            return 
true;
        }

        
$pass = isset($key['pass']) ? $key['pass'] : '';
        if (isset(
$key['file'])) {
            if (!
file_exists($key['file'])) { die('Key file not found: ' . $key['file']); }
            
$data = file_get_contents($key['file']);
        }
        if (isset(
$key['data'])) { $data = $key['data']; }
        
# seems can be another size (162 bytes)
#        if ($this->_strlen($data) != 164) { die('Key data has invalid size: ' . $this->_strlen($data)); }

        // extracting n & e from data
        
$key_data = unpack('vreserved/vsignflag/a16crc/Vlen/a*buf', $data);
        
$key_test = $this->SecureKeyByIDPW($wmid, $pass, $key_data);
        
$sign_keys = $this->InitKeys($key_test);
        
$this->ekey = $this->_hex2dec(bin2hex(strrev($sign_keys['ekey'])));
        
$this->nkey = $this->_hex2dec(bin2hex(strrev($sign_keys['nkey'])));
    }


    
# export keys for feature usage
    
public function ExportKeys() {
        return array(
'ekey' => $this->ekey, 'nkey' => $this->nkey);
    }


    
# Math init
    
private function InitMath() {
        if (
defined('WMXI_MATH')) {
            switch (
WMXI_MATH) {
                case 
'gmp': if (extension_loaded('gmp')) { return WMXI_MATH; } break;
                case 
'bcmath5': if (function_exists('bcpowmod')) { return WMXI_MATH; } break;
                case 
'bcmath4': if (extension_loaded('bcmath')) { return WMXI_MATH; } break;
            }
            die(
'Can not use WMXI_MATH = '. WMXI_MATH);
        } else {
            if (
extension_loaded('gmp')) { return 'gmp'; } 
            if (
function_exists('bcpowmod')) { return 'bcmath5'; } 
            if (
extension_loaded('bcmath')) { return 'bcmath4'; } 
            die(
'Supported math implementations not found.');
        }
    }

    
    
# MD4 init
    
private function InitMD4() {
        if (
defined('WMXI_MD4')) {
            switch (
WMXI_MD4) {
                case 
'mhash': if (function_exists('mhash')) { return WMXI_MD4; } break;
                case 
'hash':  if (function_exists('hash')) { return WMXI_MD4; } break;
                case 
'class': if (class_exists('MD4')) { $this->md4 = new MD4(true); return WMXI_MD4; } break;
            }
            die(
'Can not use WMXI_MD4 = '. WMXI_MD4);
        } else {
            if (
function_exists('mhash')) { return 'mhash'; }
            if (
function_exists('hash')) { return 'hash'; }
            if (
class_exists('MD4')) {
                
$this->md4 = new MD4(true);
                return 
'class';
            }
            die(
'Supported MD4 implementations not found.');
        }
    }

    private function 
_strlen($data) {
        return 
mb_strlen($data, 'windows-1251');
    }
    
    
# md4 wrapper
    
private function _md4($data) {
        if (
$this->md4_use == 'mhash') { return mhash(MHASH_MD4, $data); }
        if (
$this->md4_use == 'hash' ) { return hash('md4', $data, true); }
        if (
$this->md4_use == 'class') { return $this->md4->Calc($data, true); }
        die(
'MD4 implementations not found for _md4.');
    }


    
# bcpowmod wrapper for old PHP
    
private function _bcpowmod($m, $e, $n) {
        if (
$this->math_use == 'gmp') { return gmp_strval(gmp_powm($m, $e, $n)); }
        if (
$this->math_use == 'bcmath5') { return bcpowmod($m, $e, $n); }
        if (
$this->math_use == 'bcmath4') {
            
$r = '';
            while (
$e != '0') {
                
$t = bcmod($e, '4096');
                
$r = substr('000000000000'.decbin(intval($t)), -12).$r;
                
$e = bcdiv($e, '4096', 0);
                
WMXILogger::Append("$t = $t; $e = $e;");
            }
            
$r = preg_replace('!^0+!', '', $r);
            if (
$r == '') $r = '0';
            
$m = bcmod($m, $n);
            
WMXILogger::Append("$m = $m;");
            
$erb = strrev($r);
            
WMXILogger::Append("$erb = $erb;");
            
$result = '1';
            
$a[0] = $m;
            for (
$i = 1; $i < $this->_strlen($erb); $i++) {
                
$a[$i] = bcmod(bcmul($a[$i-1], $a[$i-1], 0), $n);
            }
            
WMXILogger::Append("$a = $a;");
            for (
$i = 0; $i < $this->_strlen($erb); $i++) {
                if (
$erb[$i] == '1') {
                    
$result = bcmod(bcmul($result, $a[$i], 0), $n);
                }
            }
            
WMXILogger::Append("$result = $result;");
            return 
$result;
        }
        die(
'Math implementations not found for _bcpowmod.');
    }


    
# convert decimal to hexadecimal
    
private function _dec2hex($number) {
        if (
$this->math_use == 'gmp') {
            
$hexval = gmp_strval($number, 16);
            if (
$this->_strlen($hexval) % 2) { $hexval = '0'.$hexval; }
            
WMXILogger::Append("$hexval = $hexval;");
            return 
$hexval;
        }
        if (
$this->math_use == 'bcmath4' || $this->math_use == 'bcmath5') {
            
$hexvalues = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
            
$hexval = '';
            while(
$number != '0') {
                
$hexval = $hexvalues[bcmod($number, '16')].$hexval;
                
$number = bcdiv($number, '16', 0);
            }
            if (
$this->_strlen($hexval) % 2) { $hexval = '0'.$hexval; }
            
WMXILogger::Append("$hexval = $hexval;");
            return 
$hexval;
        }
        die(
'Math implementations not found for _dec2hex.');
    }


    
# convert hexadecimal to decimal
    
private function _hex2dec($number) {
        if (
$this->math_use == 'gmp') { return gmp_strval("0x$number", 10); }

        if (
$this->math_use == 'bcmath4' || $this->math_use == 'bcmath5') {
            
$decvalues = array(
                
'0' => '0', '1' => '1', '2' => '2', '3' => '3',
                
'4' => '4', '5' => '5', '6' => '6', '7' => '7',
                
'8' => '8', '9' => '9', 'A' => '10', 'B' => '11',
                
'C' => '12', 'D' => '13', 'E' => '14', 'F' => '15');
            
$decval = '0';
            
$number = strrev(strtoupper($number));
            
WMXILogger::Append("$number = $number;");
            for(
$i = 0; $i < $this->_strlen($number); $i++) {
                
$decval = bcadd(bcmul(bcpow('16', $i, 0), $decvalues[$number[$i]], 0), $decval, 0);
            }
            
WMXILogger::Append("$decval = $decval;");
            return 
$decval;
        }
        die(
'Math implementations not found for _hex2dec.');
    }


    
# swap hexadecimal string
    
private function _shortunswap($hex_str) {
        
$result = '';
        while(
$this->_strlen($hex_str) < 132) { $hex_str = '00'.$hex_str; }
        for(
$i = 0; $i < $this->_strlen($hex_str) / 4; $i++) {
            
$result = substr($hex_str, $i * 4, 4).$result;
        }
        return 
$result;
    }


    
# XOR two strings
    
private function _XOR($str, $xor_str, $shift = 0) {
        
$str_len = $this->_strlen($str);
        
$xor_len = $this->_strlen($xor_str);
        
$i = $shift;
        
$k = 0;
        while (
$i < $str_len) {
            
$str[$i] = chr(ord($str[$i]) ^ ord($xor_str[$k]));
            
$i++;
            
$k++;
            if (
$k >= $xor_len) { $k = 0; }
        }
        return 
$str;
    }


    
# both of SecureKeyByIDPW
    
private function SecureKeyByIDPW($wmid, $pass, $key_data) {
        
$digest = $this->_md4($wmid . $pass);
        
$result = $key_data;
        
$result['buf'] = $this->_XOR($result['buf'], $digest, 6);
        return 
$result;
    }


    
# initializing E and N
    
private function InitKeys($key_data) {
        
$crc_cont = '';
        
$crc_cont .= pack('v', $key_data['reserved']);
        
$crc_cont .= pack('v', 0);
        
$crc_cont .= pack('V4', 0, 0, 0, 0);
        
$crc_cont .= pack('V', $key_data['len']);
        
$crc_cont .= $key_data['buf'];
        
$digest = $this->_md4($crc_cont);
        if (
strcmp($digest, $key_data['crc'])) { die('Checksum failed. KWM seems corrupted.'); }

        
$keys = unpack('Vreserved/ve_len', $key_data['buf']);
        
$keys = unpack('Vreserved/ve_len/a'.$keys['e_len'].'ekey/vn_len', $key_data['buf']);
        
$keys = unpack('Vreserved/ve_len/a'.$keys['e_len'].'ekey/vn_len/a'.$keys['n_len'].'nkey', $key_data['buf']);
        return 
$keys;
    }


    
# sign data
    
public function Sign($data) {
        if (
$this->ekey == '' || $this->nkey == '') { die('Key is not loaded.'); }
        
WMXILogger::Append("$ekey = ".$this->ekey.";");
        
WMXILogger::Append("$nkey = ".$this->nkey.";");

        
$result = '';
        
$plain = $this->_md4($data);
        for(
$i = 0; $i < 10; ++$i) { $plain .= pack('V', $this->debug ? 0 : mt_rand()); }
        
$plain = pack('v', $this->_strlen($plain)).$plain;
        
$m = $this->_hex2dec(bin2hex(strrev($plain)));
        
WMXILogger::Append("$m = $m;");
        
$a = $this->_bcpowmod($m, $this->ekey, $this->nkey);
        
WMXILogger::Append("$a = $a;");
        
$result = strtolower($this->_shortunswap($this->_dec2hex($a)));
        
WMXILogger::Append("$result = $result;");
        return 
$result;
    }


}


?>
Онлайн: 0
Реклама