1

We're running a server app to activate our software, the web app and database itself works fine in php 5.4+ but the activation within the software causes an internal server error if we're running anything higher than php 5.3 (test with 5.4, 5.5 and 5.6) - i'd like to install 5.6 to be future proof and up to date on the server.

I guess the problem lies within the activation php file, can anyone spot any code here which wouldn' tbe compatible with php54+

<?PHP

ini_set('display_errors',1);
error_reporting(E_ALL);

require 'includes/master.inc.php';

$post = trim(file_get_contents('php://input'));
//$post = base64_decode($post);
//$dict = json_decode($post);

$a = new Activation();
$a->app_id        = 373; // $dict->app_id;
$a->name          = $_REQUEST["nameOrEmail"]; //$dict->email;
$a->serial_number = $_REQUEST["activationCode"]; //$dict->serial;
$a->guid        = $_REQUEST["guid"];
$a->dt            = dater();
$a->ip            = $_REQUEST["ip_overwrite"];
if($a->ip == "")  $a->ip = $_SERVER['REMOTE_ADDR'];

if($a->serial_number == null || $a->guid == null) {
    header("HTTP/1.0 400 Activation Code or more arguments required");
    exit();
}
$a->insert();

$app = new Application($a->app_id);
if(!$app->ok()) {
    header("HTTP/1.0 412 Invalid Application");
    exit();
}
$o = new Order();
$o->select($a->serial_number, 'serial_number');
if(!$o->ok()) {
    header("HTTP/1.0 406 Invalid activation code");
    exit();
}

// Because we die before the activation is updated with the found order id,
// this has the added benefit of highlighting the activation as "fraudulent"
// in the activations list. It's not fraudulent obviously, but it does let
// us quickly see if deactivated licenses are still being used.
if($o->deactivated == 1) {
    header("HTTP/1.0 409 Activation Code is disabled.");
    exit();
}

if($o->license_name != null && $o->license_name != $a->guid)  {
    header("HTTP/1.0 410 Activation Code has been already claimed.");
    exit();
}
$a->order_id = $o->id;
$a->update();

//$o->downloadLicense();


//header("Cache-Control: public");
//header("Cache-Control: no-store, no-cache, must-revalidate");
//header("Cache-Control: post-check=0, pre-check=0", false);
//header("Pragma: no-cache");
//header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
//header("Content-Type: application/x-download"); // Stupid fix for Safari not honoring content-disposition
//header("Content-Length: " . strlen($this->order->license));
//header("Content-Disposition: attachment; filename={$this->application->license_filename}");
//header("Content-Transfer-Encoding: binary");
//echo $this->order->license;
//exit;

/**
  * hex2bin
  * Converts a hexadecimal string to binary
  * @param string Hex string
  * @return string Binary string
  */
function hex2bin($hex) {
if (strlen($hex) % 2)
    $hex = "0".$hex;
$bin = '';
for ($i = 0; $i < strlen($hex); $i += 2) { 
    $bin .= chr(hexdec(substr($hex, $i, 2))); 
}

   return $bin; 
} 

/**
  * dec2hex
  * Converts a decimal string to a hexadecimal string
  * @param string Decimal string
  * @return string Hex string
  */
function dec2hex($number)
{
$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);
}
return $hexval;
}

/**
  * hex2dec
  * Converts a hexadecimal string to decimal string
  * @param string Hex string
  * @return string Decimal string
  */
function hex2dec($number)
{
$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', 'a' => '10', 'b' => '11',
                   'c' => '12', 'd' => '13', 'e' => '14',
                   'f' => '15');
$decval = '0';

$number = array_pop(explode("0x", $number, 2));

$number = strrev($number);
for($i = 0; $i < strlen($number); $i++)
{
        $decval = bcadd(bcmul(bcpow('16',$i,0),$decvalues[$number{$i}]), $decval);
}
return $decval;
}

/**
  * powmod
  * Raise a number to a power mod n
  * This could probably be made faster with some Montgomery trickery, but it's just fallback for now
  * @param string Decimal string to be raised
  * @param string Decimal string of the power to raise to
  * @param string Decimal string the modulus
  * @return string Decimal string
  */
function powmod($num, $pow, $mod)
{
if (function_exists('bcpowmod')) {
    // bcpowmod is only available under PHP5
    return bcpowmod($num, $pow, $mod);
}

// emulate bcpowmod
$result = '1';
do {
    if (!bccomp(bcmod($pow, '2'), '1')) {
        $result = bcmod(bcmul($result, $num), $mod);
    }
    $num = bcmod(bcpow($num, '2'), $mod);
    $pow = bcdiv($pow, '2');
} while (bccomp($pow, '0'));
return $result;
}

/**
  * getSignature
  * Get the base64 signature of a dictionary
  * @param array Associative array (i.e. dictionary) of key-value pairs
  * @param string Hexadecimal string of public key
  * @param string Hexadecimal string the private key
  * @return string Base64 encoded signature
  */
function getSignature($dict, $key, $privKey)
{
// Sort keys alphabetically
uksort($dict, "strcasecmp");

// Concatenate all values
$total = '';
foreach ($dict as $value)
    $total .= $value;

// Get the hash
$hash = sha1(utf8_encode($total));

// OpenSSL-compatible PKCS1 Padding
// 128 bytes - 20 bytes hash - 3 bytes extra padding = 105 bytes '0xff'
$paddedHash = '0001';
for ($i = 0; $i < 105; $i++)
{
    $paddedHash .= 'ff';
}
$paddedHash .= '00'.$hash;

$decryptedSig = hex2dec($paddedHash);

// Encrypt into a signature
$sig = powmod($decryptedSig, hex2dec($privKey), hex2dec($key));
$sig = base64_encode(hex2bin(dec2hex($sig)));
return $sig;
}

$activationResponse =  getSignature(array("activationCode"=>$a->serial_number, "guid"=>$a-     >guid), "BE6749000DA18D2D21F1D09455DB1E6C354E0B",    "7EEF860009165E1E164517CBDDF6D66A6F5D176C03883EC3E7BB643D84B0E17A41E68A57AE09670A943042F50AE9E41633E  E64A88639DA4691C3A11778839AAEB");
echo $activationResponse;

 $o->license_name = $a->guid;
 $o->license = $activationResponse;
$o->update();

exit();

Here is the hex error from log

2014/12/02 13:05:22 [error] 22848#0: *280 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Cannot redeclare hex2bin() in /var/www/html/aurora/aurora-inapp.php on line 85" while reading response header from upstream, client: 141.101.00.22, server: test.com, request: "POST /aurora/aurora-inapp.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm.sock:", host: "test.com"
NikiC
  • 100,734
  • 37
  • 191
  • 225
realdannys
  • 1,383
  • 1
  • 12
  • 18
  • 2
    `error_log` content is ...? – Aleksei Matiushkin Dec 02 '14 at 13:27
  • 1
    Sounds to me like you're trying to use a feature deprecated in PHP 5.4 that is available in 5.3. Please provide the relevant entries from your `error_log`. – AStopher Dec 02 '14 at 13:30
  • The contents of `includes/master.inc.php` could be causing this but we don't know. Also, I don't trust if() statements without curly braces. Please use curly braces and kittens will be spared. – MonkeyZeus Dec 02 '14 at 13:32
  • I got `Fatal error: Cannot redeclare hex2bin() in [...][...] on line 83
    – AStopher Dec 02 '14 at 13:32
  • You really need to check both your Apache error logs and PHP error logs. – MonkeyZeus Dec 02 '14 at 13:33
  • 1
    Added the error code, as @cybermonkey found it is the hex2bin which seems to no longer work - i'm not sure how to update this to 5.4+ compatible code though. – realdannys Dec 02 '14 at 13:41

1 Answers1

3

Your code is failing as since PHP 5.4, PHP has had its own hex2bin function. To resolve this you need to remove the hex2bin function that you are using.

You might want to do a simple version check in an if statement before the function is declared using phpversion():

if (!function_exists('hex2bin')) 
{
    function hex2bin($hex) {
    if (strlen($hex) % 2)
        $hex = "0".$hex;
    $bin = '';
    for ($i = 0; $i < strlen($hex); $i += 2) { 
        $bin .= chr(hexdec(substr($hex, $i, 2))); 
    }

       return $bin; 
    } 
}

From Github:

Since PHP 5.4 PHP provides its own hex2bin function, which causes the hex2bin declaration in ykksm-util.php to fail, causing the error below:

PHP Fatal error: Cannot redeclare hex2bin()

Cheers to Ryan P for useful comment:

This code won't work - it calls phpinfo() with an invalid argument, and calling phpversion("tidy") will return the version of the tidy extension (2.0). A better way is to just check for existence of the function - i.e. if (!function_exists('hex2bin')) {

Community
  • 1
  • 1
AStopher
  • 4,207
  • 11
  • 50
  • 75
  • Thanks @cybermonkey I managed to figure out and I just renamed it so instead its function aug_hex2bin($hex) – realdannys Dec 02 '14 at 13:51
  • @realdannys No problem, I'm glad to help. That's what we're here for, after all :-). – AStopher Dec 02 '14 at 13:53
  • 1
    This code won't work - it calls `phpinfo()` with an invalid argument, and calling `phpversion("tidy")` will return the version of the tidy extension (2.0). A better way is to just check for existence of the function - i.e. `if (!function_exists('hex2bin')) {` – kitti May 24 '16 at 16:16
  • @RyanP Edited and attributed. – AStopher May 24 '16 at 17:28