-->

Sagepay error 5068: encryption method not supporte

2019-09-10 09:58发布

问题:

I've already looked through answers to other questions on the Sagepay protocol upgrade from 2.22 to 3.00, including the answer on my own previous question.

I am trying to update the encryption method from Xor to AES so the 3.00 protocol will work but have thus far got stuck on the Sagepay error 5068: the encryption method is not supported by this protocol. My company's three websites that need to be updated are based on the JShop e-commerce platform which is very outdated and no longer offers support.

I have implemented two solutions given as answers, one of which is taken from the Sagepay php documents available on their website but am still receiving this error.

I'd appreciate some input into where I am going wrong.

Have contacted Sagepay but they're not much help and have previously directed me here or to their partners page.

Protx (Sagepay) file:

    <?php


    function startProcessor($orderNumber) {

        global $dbA,$orderArray,$jssStoreWebDirHTTP,$jssStoreWebDirHTTPS,$cartMain;



        $callBack = "$jssStoreWebDirHTTPS"."gateways/response/protx.php";



        $cDetails = returnCurrencyDetails($orderArray["currencyID"]);



        $gatewayOptions = retrieveGatewayOptions("PROTX");

        switch ($gatewayOptions["testMode"]) {

            case "S":

                $myAction = "https://test.sagepay.com/Simulator/VSPFormGateway.asp";

                break;

            case "Y":

                $myAction = "https://test.sagepay.com/gateway/service/vspform-register.vsp";

                break;

            case "N":

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

                break;

        }

        $myVendor = $gatewayOptions["vendor"];

        $myEncryptionPassword = $gatewayOptions["encryptionPassword"];



        $billingAddress  = $orderArray["address1"]."\n";

        if ($orderArray["address2"] != "") {

            $billingAddress .= $orderArray["address2"]."\n";

        }

        $billingAddress .= $orderArray["town"]."\n";

        $billingAddress .= $orderArray["county"]."\n";

        $billingAddress .= $orderArray["country"];



        $deliveryAddress  = $orderArray["deliveryAddress1"]."\n";

        if ($orderArray["deliveryAddress2"] != "") {

            $deliveryAddress .= $orderArray["deliveryAddress2"]."\n";

        }

        $deliveryAddress .= $orderArray["deliveryTown"]."\n";

        $deliveryAddress .= $orderArray["deliveryCounty"]."\n";

        $deliveryAddress .= $orderArray["deliveryCountry"];





        $crypt = "VendorTxCode=$orderNumber";

        $crypt .= "&Amount=".number_format($orderArray["orderTotal"],$cDetails["decimals"],'.','');

        $crypt .= "&Currency=".@$cDetails["code"];

        $crypt .= "&Description=".$gatewayOptions["description"];

        $crypt .= "&SuccessURL=$callBack?xOid=$orderNumber&xRn=".$orderArray["randID"];

        $crypt .= "&FailureURL=$callBack?xOid=$orderNumber&xRn=".$orderArray["randID"];

        $crypt .= "&BillingSurname=".$orderArray["surname"];

        $crypt .= "&BillingFirstnames=".$orderArray["forename"];

        $crypt .= "&BillingAddress1=".$orderArray["address1"];

        $crypt .= "&BillingCity=".$orderArray["town"];

        $crypt .= "&BillingPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["postcode"]);

        $crypt .= "&BillingCountry=".$orderArray["country"];

        $crypt .= "&DeliverySurname=".$orderArray["surname"];

        $crypt .= "&DeliveryFirstnames=".$orderArray["forename"];

    if ($orderArray["deliveryPostcode"] != "") {
        $crypt .= "&DeliveryAddress1=".$orderArray["deliveryAddress1"];

        $crypt .= "&DeliveryCity=".$orderArray["deliveryTown"];

        $crypt .= "&DeliveryPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["deliveryPostcode"]);

        $crypt .= "&DeliveryCountry=".$orderArray["deliveryCountry"]; }

    else {
        $crypt .= "&DeliveryAddress1=".$orderArray["address1"];

        $crypt .= "&DeliveryCity=".$orderArray["town"];

        $crypt .= "&DeliveryPostCode=".preg_replace("/[^\s\-a-zA-Z0-9]/", "", $orderArray["postcode"]);

        $crypt .= "&DeliveryCountry=".$orderArray["country"]; }

        $crypt .= "&BillingPhone=".preg_replace("/[^\sa-zA-Z0-9]/", "", $orderArray["telephone"]);

        if ($gatewayOptions["sendEmail"] == 1) {
        $crypt .= "&CustomerEmail=".$orderArray["email"]; }


        $crypt .= "&VendorEmail=".$gatewayOptions["vendorEmail"];

        $crypt .= "&ApplyAVSCV2=".$gatewayOptions["cvvCheck"];
        $crypt .= "&Apply3dSecure=".$gatewayOptions["3DSecure"];




        $crypt = base64_encode(encryptAes($crypt, $myEncryptionPassword));

        $tpl = createTSysObject(templatesCreatePath($cartMain["templateSet"]),"gatewaytransfer.html",$requiredVars,0);



        $gArray["method"] = "POST";

        $gArray["action"] = $myAction;

        $gArray["fields"][] = array("name"=>"VPSProtocol","value"=>"3.00");

        $gArray["fields"][] = array("name"=>"Vendor","value"=>$myVendor);

        $gArray["fields"][] = array("name"=>"TxType","value"=>$gatewayOptions["txType"]);

        $gArray["fields"][] = array("name"=>"Crypt","value"=>$crypt);



        $mArray = $gArray;



        $gArray["process"] = "document.automaticForm.submit();";



        $tpl->addVariable("shop",templateVarsShopRetrieve());

        $tpl->addVariable("labels",templateVarsLabelsRetrieve());



        $tpl->addVariable("automaticForm",$gArray);

        $tpl->addVariable("manualForm",$mArray);

        $tpl->showPage();

    }

    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, $myEncryptionPassword)
    {

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

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

?>

Response file:

 <?php

    define("IN_JSHOP", TRUE);

    include("../../static/config.php");

    include("../../routines/dbAccess_".$databaseType.".php");

    include("../../routines/tSys.php");

    include("../../routines/general.php");

    include("../../routines/stockControl.php");

    include("../../routines/emailOutput.php");

    require_once 'SagepayUtil.php';



    dbConnect($dbA);



    $orderID = makeSafe(getFORM("xOid"));

    $newOrderID = $orderID;

    $randID = makeSafe(getFORM("xRn"));

    $crypt = makeSafe(getFORM("crypt"));



    $gatewayOptions = retrieveGatewayOptions("PROTX");



    $orderID = makeInteger($orderID) - retrieveOption("orderNumberOffset");



    $result =  $dbA->query("select * from $tableOrdersHeaders where orderID=$orderID and randID='$randID'");

    if ($dbA->count($result) == 0 || $crypt=="") {

        doRedirect_JavaScript($jssStoreWebDirHTTP."index.php");

        exit;

    }

    $orderArray = $dbA->fetch($result);

    $ccResult = $dbA->query("select * from $tablePaymentOptions where paymentID=".$orderArray["paymentID"]);

    $poRecord = $dbA->fetch($ccResult);

    $paidStatus = $poRecord["statusID"];



    $crypt = str_replace(" ","+",$crypt);

    //$crypt = protx_simpleXor(base64_decode($crypt),$gatewayOptions["encryptionPassword"]);

    $crypt = decryptAes(base64_decode($crypt), $gatewayOptions["encryptionPassword"]);



    $nameValues = explode("&",$crypt);

    $resultCode = "";

    for ($f = 0; $f < count($nameValues); $f++) {

        $thisCode = explode("=",$nameValues[$f]);

        $resultCode[$thisCode[0]] = $thisCode[1];

    }



    if ($resultCode["VendorTxCode"] != $newOrderID) {

        doRedirect_JavaScript($jssStoreWebDirHTTP."index.php");

        exit;

    }



    $authResponse = "&Status Result=".$resultCode["Status"]."&AVS/CV2 Check=".@$resultCode["AVSCV2"]."&Address Result=".@$resultCode["AddressResult"]."&Postcode Result=".@$resultCode["PostCodeResult"]."&CV2 Result=".@$resultCode["CV2Result"]."&3d Secure Status=".@$resultCode["3DSecureStatus"];



    $randID = $orderArray["randID"];

    if ($orderArray["status"] != $paidStatus) {

            $dt=date("YmdHis",createOffsetTime());

            switch ($resultCode["Status"]) {

                case "OK":

                case "AUTHENTICATED":

                case "REGISTERED":

                    $authResponse="Gateway=Sage Pay&Authorisation Code=".$resultCode["TxAuthNo"]."&Sage Pay Transaction ID=".$resultCode["VPSTxId"]."&Status=Payment Confirmed".$authResponse;

                    $dbA->query("update $tableOrdersHeaders set status=$paidStatus, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");

                    $orderArray["status"] = $paidStatus;

                    //ok, this is where we should do the stock control then.

                    include("process/paidProcessList.php");

                    doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");

                    break;

                case "REJECTED":

                    $authResponse="Gateway=Sage Pay&Status=Payment Rejected Due To Rules".$authResponse;

                    $dbA->query("update $tableOrdersHeaders set status=3, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");

                    include("process/failProcessList.php");

                    doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");

                    break;

                default:

                    if ($orderArray["status"] == 1) {

                        $authResponse="Gateway=Sage Pay&Status=Payment Failed".$authResponse;

                        $dbA->query("update $tableOrdersHeaders set status=3, authInfo=\"$authResponse\", paymentDate=\"$dt\" where orderID=$orderID");

                        include("process/failProcessList.php");

                }

                    doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");

                    break;

            }

    } else {

            doRedirect_JavaScript($jssStoreWebDirHTTPS."process.php?xOid=$newOrderID&xRn=$randID");

    }



    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, $myEncryptionPassword)
    {

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

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

?>

回答1:

Make sure you back up the files first, then change this line:

$crypt =base64_encode(encryptAes($crypt, $myEncryptionPassword));

to

$crypt = "@".encryptAes($crypt, $myEncryptionPassword);

And:

$crypt = decryptAes(base64_decode($crypt), $gatewayOptions["encryptionPassword"]);

To:

$crypt = decryptAes($crypt, $gatewayOptions["encryptionPassword"]);

Having looked at the decrypt bit, the removal of the '@' is already there. I'm not a PHP guy, so this may not be perfect!



回答2:

Give it a go without the base64 encryption, and make sure you add '@' to the beginning of the crypt when encoding (and remove it from the crypt when decrypting the transaction result).