Sage Pay v3.00 Integration

扶醉桌前 提交于 2019-12-03 18:07:58

问题


Can anyone help me incorporate the Sagepay v3.00 AES/CBC/PKCS#5 algorithm (encryption) into the following file. I'm really struggling to understand how to include so that customer data is encrypted to the new standard and then decrypted on the way back. Using Sagepay Form with a very old version of cs-cart, though have successfully managed to upgrade from version 2.22 to 2.23, but Sagepay are pulling all support from July.

Not sure how much of this script is relevant to the encryption:

<?php

if ( !defined('IN_CSCART') ) { die('Access denied'); }

if (defined('PAYMENT_NOTIFICATION')) {  

// Get the password
$payment_id=db_get_field("SELECT $db_tables[payments].payment_id FROM $db_tables[payments] LEFT JOIN $db_tables[payment_processors] ON $db_tables[payment_processors].processor_id = $db_tables[payments].processor_id WHERE $db_tables[payment_processors].processor_script='protx_form.php'");
$processor_data = fn_get_payment_method_data($payment_id);

$result = "&".simpleXor(base64Decode($_REQUEST['crypt']), $processor_data["params"]["password"])."&";

preg_match("/Status=(.+)&/U", $result, $a);
if(trim($a[1]) == "OK") {
    $pp_response['order_status'] = ($processor_data["params"]["transaction_type"] == 'PAYMENT') ? 'P' : 'O';
    preg_match("/TxAuthNo=(.+)&/U", $result, $authno);
    $pp_response["reason_text"] = "AuthNo: ".$authno[1];
    preg_match("/VPSTxID={(.+)}/U", $result, $transaction_id);
    $pp_response["transaction_id"] = @$transaction_id[1];
} else {
    $pp_response['order_status'] = 'F';
    preg_match("/StatusDetail=(.+)&/U", $result, $stat);
    $pp_response["reason_text"] = "Status: ".trim($stat[1])." (".trim($a[1]).") ";
}
preg_match("/AVSCV2=(.*)&/U", $result, $avs);
if(!empty($avs[1])) {
    $pp_response['descr_avs'] = $avs[1];
}
include $payment_files_dir.'payment_cc_complete.php';
fn_order_placement_routines($order_id);

}
else
{
    global $http_location, $b_order, $_total_back;

    $post_address = ($processor_data['params']['testmode'] != "N") ? "https://test.sagepay.com/gateway/service/vspform-register.vsp" : "https://live.sagepay.com/gateway/service/vspform-register.vsp";

    $post["VPSProtocol"] = "2.23";
    $post["TxType"] = $processor_data["params"]["transaction_type"];
    $post["Vendor"] = htmlspecialchars($processor_data["params"]["vendor"]);

    // Form Cart products
    $strings = 0;
    if (is_array($cart['products'])) {
        $strings += count($cart['products']);
    }

    if (!empty($cart['products'])) {
        foreach ($cart['products'] as $v) {
            $_product = db_get_field("SELECT product FROM $db_tables[product_descriptions] WHERE product_id='$v[product_id]' AND lang_code='$cart_language'");
            $products_string .= ":".str_replace(":", " ", $_product).":".$v['amount'].":".fn_format_price($v['subtotal']/$v['amount']).":::".fn_format_price($v['subtotal']);
        }
    }
    if (!empty($cart['payment_surcharge'])) {
        $products_string .= ":Payment surcharge:---:---:---:---:".fn_format_price($cart['payment_surcharge']);
        $strings ++;
    }
    if (!empty($cart['shipping_cost'])) {
        $products_string .= ":Shipping cost:---:---:---:---:".fn_format_price($cart['shipping_cost']);
        $strings ++;
    }
    $post_encrypted .= "Basket=".$strings.$products_string;

    $post["Crypt"] = base64_encode(simpleXor($post_encrypted, $processor_data["params"]["password"]));
    $post["Crypt"] = htmlspecialchars($post["Crypt"]);

    $msg = fn_get_lang_var('text_cc_processor_connection');
    $msg = str_replace('[processor]', 'Protx Server', $msg);

echo <<<EOT
<html>
<body onLoad="document.process.submit();">
<form action="{$post_address}" method="POST" name="process">
<INPUT type=hidden name="VPSProtocol" value="{$post['VPSProtocol']}">
<INPUT type=hidden name="Vendor" value="{$post['Vendor']}">
<INPUT type=hidden name="TxType" value="{$post['TxType']}">
<INPUT type=hidden name="Crypt" value="{$post['Crypt']}">
<p>
<div align=center>{$msg}</div>
</p>
</body>
</html>
EOT;
}

exit;

//
// ---------------- Additional functions ------------
//
function simpleXor($InString, $Key) {
$KeyList = array();
$output = "";

for($i = 0; $i < strlen($Key); $i++){
    $KeyList[$i] = ord(substr($Key, $i, 1));
}
for($i = 0; $i < strlen($InString); $i++) {
    $output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
}

return $output;
}

function base64Decode($scrambled) {
// Initialise output variable
$output = "";
// Fix plus to space conversion issue
$scrambled = str_replace(" ","+",$scrambled);
// Do encoding
$output = base64_decode($scrambled);
// Return the result
return $output;
}
?>

回答1:


You could try dropping the following functions into the script, then swapping out simpleXor for encryptAes. Make sure that you also add an '@' symbol as the first character of the crypt string (and strip it off when decoding the response from Sage Pay).

function addPKCS5Padding($input)
{
     $blockSize = 16;
     $padd = "";
     $length = $blockSize - (strlen($input) % $blockSize);
     for ($i = 1; $i <= $length; $i++)
{
     $padd .= chr($length);
}
     return $input . $padd;
}

function removePKCS5Padding($input)
{
    $blockSize = 16;
    $padChar = ord($input[strlen($input) - 1]);
    $unpadded = substr($input, 0, (-1) * $padChar);
    return $unpadded;
}


function encryptAes($string, $key)
{
    $string = addPKCS5Padding($string);
    $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
    return  strtoupper(bin2hex($crypt));
}


function decryptAes($strIn, $password)
{
    $strInitVector = $password;
    $strIn = pack('H*', $hex);
    $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC,$strInitVector);
    return removePKCS5Padding($string);
}



回答2:


You could try this. I can't test it, so let me know how you get on.

<?php

    if ( !defined('IN_CSCART') ) { die('Access denied'); }

    if (defined('PAYMENT_NOTIFICATION')) {  

    // Get the password
    $payment_id=db_get_field("SELECT $db_tables[payments].payment_id FROM $db_tables[payments] LEFT JOIN $db_tables[payment_processors] ON $db_tables

    [payment_processors].processor_id = $db_tables[payments].processor_id WHERE $db_tables[payment_processors].processor_script='protx_form.php'");
    $processor_data = fn_get_payment_method_data($payment_id);


    #Rik added:
    $result = "&".decryptAes($_REQUEST['crypt'], $processor_data["params"]["password"])."&";

    #$result = "&".simpleXor(base64Decode($_REQUEST['crypt']), $processor_data["params"]["password"])."&";

    preg_match("/Status=(.+)&/U", $result, $a);
    if(trim($a[1]) == "OK") {
        $pp_response['order_status'] = ($processor_data["params"]["transaction_type"] == 'PAYMENT') ? 'P' : 'O';
        preg_match("/TxAuthNo=(.+)&/U", $result, $authno);
        $pp_response["reason_text"] = "AuthNo: ".$authno[1];
        preg_match("/VPSTxID={(.+)}/U", $result, $transaction_id);
        $pp_response["transaction_id"] = @$transaction_id[1];
    } else {
        $pp_response['order_status'] = 'F';
        preg_match("/StatusDetail=(.+)&/U", $result, $stat);
        $pp_response["reason_text"] = "Status: ".trim($stat[1])." (".trim($a[1]).") ";
    }
    preg_match("/AVSCV2=(.*)&/U", $result, $avs);
    if(!empty($avs[1])) {
        $pp_response['descr_avs'] = $avs[1];
    }
    include $payment_files_dir.'payment_cc_complete.php';
    fn_order_placement_routines($order_id);

    }
    else
    {
        global $http_location, $b_order, $_total_back;

        $post_address = ($processor_data['params']['testmode'] != "N") ? "https://test.sagepay.com/gateway/service/vspform-register.vsp" : 

    "https://live.sagepay.com/gateway/service/vspform-register.vsp";

        $post["VPSProtocol"] = "2.23";
        $post["TxType"] = $processor_data["params"]["transaction_type"];
        $post["Vendor"] = htmlspecialchars($processor_data["params"]["vendor"]);

        // Form Cart products
        $strings = 0;
        if (is_array($cart['products'])) {
            $strings += count($cart['products']);
        }

        if (!empty($cart['products'])) {
            foreach ($cart['products'] as $v) {
                $_product = db_get_field("SELECT product FROM $db_tables[product_descriptions] WHERE product_id='$v[product_id]' AND lang_code='$cart_language'");
                $products_string .= ":".str_replace(":", " ", $_product).":".$v['amount'].":".fn_format_price($v['subtotal']/$v['amount']).":::".fn_format_price($v

    ['subtotal']);
            }
        }
        if (!empty($cart['payment_surcharge'])) {
            $products_string .= ":Payment surcharge:---:---:---:---:".fn_format_price($cart['payment_surcharge']);
            $strings ++;
        }
        if (!empty($cart['shipping_cost'])) {
            $products_string .= ":Shipping cost:---:---:---:---:".fn_format_price($cart['shipping_cost']);
            $strings ++;
        }
        $post_encrypted .= "Basket=".$strings.$products_string;


    #Rik added:

     $post["Crypt"] = "@".encryptAes($post_encrypted, $processor_data["params"]["password"]);

    #    $post["Crypt"] = base64_encode(simpleXor($post_encrypted, $processor_data["params"]["password"]));
    #    $post["Crypt"] = htmlspecialchars($post["Crypt"]);

        $msg = fn_get_lang_var('text_cc_processor_connection');
        $msg = str_replace('[processor]', 'Protx Server', $msg);

    echo <<<EOT
    <html>
    <body onLoad="document.process.submit();">
    <form action="{$post_address}" method="POST" name="process">
    <INPUT type=hidden name="VPSProtocol" value="{$post['VPSProtocol']}">
    <INPUT type=hidden name="Vendor" value="{$post['Vendor']}">
    <INPUT type=hidden name="TxType" value="{$post['TxType']}">
    <INPUT type=hidden name="Crypt" value="{$post['Crypt']}">
    <p>
    <div align=center>{$msg}</div>
    </p>
    </body>
    </html>
    EOT;
    }

    exit;

    //
    // ---------------- Additional functions ------------
    //
    function simpleXor($InString, $Key) {
    $KeyList = array();
    $output = "";

    for($i = 0; $i < strlen($Key); $i++){
        $KeyList[$i] = ord(substr($Key, $i, 1));
    }
    for($i = 0; $i < strlen($InString); $i++) {
        $output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)]));
    }

    return $output;
    }

    function base64Decode($scrambled) {
    // Initialise output variable
    $output = "";
    // Fix plus to space conversion issue
    $scrambled = str_replace(" ","+",$scrambled);
    // Do encoding
    $output = base64_decode($scrambled);
    // Return the result
    return $output;
    }


    #added by Rik

    function addPKCS5Padding($input)
    {
         $blockSize = 16;
         $padd = "";
         $length = $blockSize - (strlen($input) % $blockSize);
         for ($i = 1; $i <= $length; $i++)
    {
         $padd .= chr($length);
    }
         return $input . $padd;
    }

    function removePKCS5Padding($input)
    {
        $blockSize = 16;
        $padChar = ord($input[strlen($input) - 1]);
        $unpadded = substr($input, 0, (-1) * $padChar);
        return $unpadded;
    }


    function encryptAes($string, $key)
    {
        $string = addPKCS5Padding($string);
        $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
        return  strtoupper(bin2hex($crypt));
    }


    function decryptAes($strIn, $password)
    {

    #Sagepay specific - remove the '@'
    $strIn = substr($strIn,1)

        $strInitVector = $password;
        $strIn = pack('H*', $hex);
        $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC,$strInitVector);
        return removePKCS5Padding($string);
    }

    ?>



回答3:


/*First build your data. */

$data = 'variableA='.$this->variableA;
$data .= '&variableB='.$this->variableB;
...
$data .= '&variableZ='.$this->variableZ;

/** Encript data */
$dataEncrip = $this->encData($data);


/** function to Encrypt *//
public function encData($data){
  $data = $this->pkcs5_pad( $data, 16);
  $dataEnc = "@".bin2hex( mcrypt_encrypt( MCRYPT_RIJNDAEL_128,
                                          $this->passwordToEncript,
                                          $data,
                                          MCRYPT_MODE_CBC,
                                          $this->getPasswordToEncrypt()));
  return $dataEnc;                                                           
}

 /** Pkcs5_pad */
public function pkcs5_pad( $data, $blocksize ){
    $pad = $blocksize - (strlen( $data ) % $blocksize);
    return $data . str_repeat( chr( $pad ), $pad );
}


来源:https://stackoverflow.com/questions/28525026/sage-pay-v3-00-integration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!