Skip to content

Commit

Permalink
GMP is not required anymore
Browse files Browse the repository at this point in the history
  • Loading branch information
baibaratsky committed Mar 27, 2015
1 parent 092301e commit c5fd2bd
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 26 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
WebMoney Signer
===============
Provides a convenient way to sign your requests to WebMoney API in PHP with no need to run executables. You may also use [WebMoney API PHP Library](https://github.com/baibaratsky/php-webmoney) for more transparent object-oriented code.
Provides a convenient way to sign your requests to WebMoney API in PHP with no need to run executables.
You may also use [WebMoney API PHP Library](https://github.com/baibaratsky/php-webmoney) for more transparent object-oriented code.


Requirements
------------
WebMoney Signer requires PHP 5.3 compiled with [BCMath](http://www.php.net/manual/en/book.bc.php) and [GMP](http://www.php.net/manual/en/book.gmp.php) support.
WebMoney Signer requires PHP 5.3 compiled with [BCMath](http://www.php.net/manual/en/book.bc.php) support.
[GMP](http://www.php.net/manual/en/book.gmp.php) can increase the performance, but is not required.


Installation
Expand All @@ -19,7 +21,7 @@ Installation
0. Add the php-wmsigner dependency:
```
php composer.phar require baibaratsky/php-wmsigner:1.0.*
php composer.phar require baibaratsky/php-wmsigner:1.1.*
```
Usage
Expand Down
113 changes: 92 additions & 21 deletions Signer.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public function __construct($wmid, $keyFileName, $keyPassword)
}

$keyData = unpack('vreserved/vsignFlag/a16hash/Vlength/a*buffer', $key);
$keyData['buffer'] = $this->encryptKey($keyData['buffer'], $wmid, $keyPassword);
$keyData['buffer'] = self::encryptKey($keyData['buffer'], $wmid, $keyPassword);

if (!$this->verifyHash($keyData)) {
if (!self::verifyHash($keyData)) {
throw new \Exception('Hash check failed. Key file seems to be corrupted.');
}

Expand Down Expand Up @@ -62,10 +62,10 @@ public function sign($data)
$base = pack('v', strlen($base)) . $base;

// Modular exponentiation
$dec = bcpowmod($this->reverseToDecimal($base), $this->power, $this->modulus);
$dec = bcpowmod(self::reverseToDecimal($base), $this->power, $this->modulus);

// Convert result to hexadecimal
$hex = gmp_strval($dec, 16);
$hex = self::dec2hex($dec);

// Fill empty bytes with zeros
$hex = str_repeat('0', 132 - strlen($hex)) . $hex;
Expand All @@ -79,6 +79,21 @@ public function sign($data)
return strtolower($hexReversed);
}

/**
* Initialize power and modulus
*
* @param string $keyBuffer
*/
private function initSignVariables($keyBuffer)
{
$data = unpack('Vreserved/vpowerLength', $keyBuffer);
$data = unpack('Vreserved/vpowerLength/a' . $data['powerLength'] . 'power/vmodulusLength', $keyBuffer);
$data = unpack('Vreserved/vpowerLength/a' . $data['powerLength'] . 'power/vmodulusLength/a'
. $data['modulusLength'] . 'modulus', $keyBuffer);
$this->power = self::reverseToDecimal($data['power']);
$this->modulus = self::reverseToDecimal($data['modulus']);
}

/**
* Encrypt key using hash of WMID and key password
*
Expand All @@ -88,11 +103,11 @@ public function sign($data)
*
* @return string
*/
private function encryptKey($keyBuffer, $wmid, $keyPassword)
private static function encryptKey($keyBuffer, $wmid, $keyPassword)
{
$hash = hash('md4', $wmid . $keyPassword, true);

return $this->xorStrings($keyBuffer, $hash, 6);
return self::xorStrings($keyBuffer, $hash, 6);
}

/**
Expand All @@ -104,7 +119,7 @@ private function encryptKey($keyBuffer, $wmid, $keyPassword)
*
* @return string
*/
private function xorStrings($subject, $modifier, $shift = 0)
private static function xorStrings($subject, $modifier, $shift = 0)
{
$modifierLength = strlen($modifier);
$i = $shift;
Expand All @@ -127,7 +142,7 @@ private function xorStrings($subject, $modifier, $shift = 0)
*
* @return bool
*/
private function verifyHash($keyData)
private static function verifyHash($keyData)
{
$verificationString = pack('v', $keyData['reserved'])
. pack('v', 0)
Expand All @@ -140,29 +155,85 @@ private function verifyHash($keyData)
}

/**
* Initialize power and modulus
* Reverse byte order and convert binary data to decimal string
*
* @param string $keyBuffer
* @param string $binaryData
*
* @return string
*/
private function initSignVariables($keyBuffer)
private static function reverseToDecimal($binaryData)
{
$data = unpack('Vreserved/vpowerLength', $keyBuffer);
$data = unpack('Vreserved/vpowerLength/a' . $data['powerLength'] . 'power/vmodulusLength', $keyBuffer);
$data = unpack('Vreserved/vpowerLength/a' . $data['powerLength'] . 'power/vmodulusLength/a'
. $data['modulusLength'] . 'modulus', $keyBuffer);
$this->power = $this->reverseToDecimal($data['power']);
$this->modulus = $this->reverseToDecimal($data['modulus']);
return self::hex2dec(bin2hex(strrev($binaryData)));
}

/**
* Reverse byte order and convert binary data to decimal string
* Convert hexadecimal string to decimal string
*
* @param string $binaryData
* @param $hex
*
* @return string
*/
private static function hex2dec($hex)
{
if (extension_loaded('gmp')) {
return gmp_strval('0x' . $hex);
}

return self::hex2decBC($hex);
}

/**
* Convert hexadecimal string to decimal string using BCMath
*
* @param $hex
*
* @return string
*/
private function reverseToDecimal($binaryData)
private static function hex2decBC($hex) {
if (strlen($hex) == 1) {
return (string)hexdec($hex);
}

$last = substr($hex, -1);
$rest = substr($hex, 0, -1);

return bcadd(
(string)hexdec($last),
bcmul('16', self::hex2decBC($rest))
);
}

/**
* Convert decimal string to hexadecimal string
*
* @param string $dec
*
* @return string
*/
private static function dec2hex($dec)
{
return gmp_strval('0x' . bin2hex(strrev($binaryData)));
if (extension_loaded('gmp')) {
return gmp_strval($dec, 16);
}

return self::dec2hexBC($dec);
}

/**
* Convert decimal string to hexadecimal string using BCMath
*
* @param string $dec
*
* @return string
*/
private static function dec2hexBC($dec) {
$remainder = bcmod($dec, '16');
$quotient = bcdiv(bcsub($dec, $remainder), '16');

if ($quotient == 0) {
return dechex($remainder);
}

return self::dec2hexBC($quotient) . dechex($remainder);
}
}
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
],
"require": {
"php": ">=5.3",
"ext-bcmath": "*",
"ext-gmp": "*"
"ext-bcmath": "*"
},
"autoload": {
"psr-4": {
Expand Down

0 comments on commit c5fd2bd

Please sign in to comment.