Sagepay 2.22 to 3.00 form upgrade - PHP update to AES encryption -
i've been trying no avail understand how upgrade encryption used in code company's 3 ecommerce sites simplexor aes encryption. without doing this, cannot upgrade rest of code means after july won't able take payments online.
i've managed update crypt form codes in line upgrade 3.00.
i can identify encryption code , have looked through form integration demo download php sagepay can't find looks remotely similar encryption code?!
could point me in right direction finding suitable encryption code replace old 1 with!?
our sites based on jshop , have 1 file sending , response file.
this file sending info:
<?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 .= "¤cy=".@$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(protx_simplexor($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 protx_simplexor($instring, $key) { $outstring=""; $l=0; if (strlen($instring)!=0) { ($i = 0; $i < strlen($instring); $i++) { $outstring=$outstring . ($instring[$i]^$key[$l]); $l++; if ($l==strlen($key)) { $l=0; } } } return $outstring; } ?>
this response file:
<?php /*================ jshop server ================ = (c)2003-2010 whorl ltd. = = rights reserved = = redistribution of file prohibited. = = http://www.jshop.co.uk/ = ==============================================*/ ?><?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"); 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 * $tableordersheaders orderid=$orderid , randid='$randid'"); if ($dba->count($result) == 0 || $crypt=="") { doredirect_javascript($jssstorewebdirhttp."index.php"); exit; } $orderarray = $dba->fetch($result); $ccresult = $dba->query("select * $tablepaymentoptions paymentid=".$orderarray["paymentid"]); $porecord = $dba->fetch($ccresult); $paidstatus = $porecord["statusid"]; $crypt = str_replace(" ","+",$crypt); $crypt = protx_simplexor(base64_decode($crypt),$gatewayoptions["encryptionpassword"]); $namevalues = explode("&",$crypt); $resultcode = ""; ($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\" orderid=$orderid"); $orderarray["status"] = $paidstatus; //ok, should 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 rules".$authresponse; $dba->query("update $tableordersheaders set status=3, authinfo=\"$authresponse\", paymentdate=\"$dt\" 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\" 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 protx_simplexor($instring, $key) { $outstring=""; $l=0; if (strlen($instring)!=0) { ($i = 0; $i < strlen($instring); $i++) { $outstring=$outstring . ($instring[$i]^$key[$l]); $l++; if ($l==strlen($key)) { $l=0; } } } return $outstring; } ?>
it looks using old code. recommend try port/rewrite code using official sage pay integration libraries avoid strange bugs things escaping.
if you're in rush, here stripped down version of class need encryption/decryption part working.
<?php class sagepayutil { /** * php's mcrypt not have built in pkcs5 padding, use this. * * @param string $input input string. * * @return string string padding. */ static protected function addpkcs5padding($input) { $blocksize = 16; $padd = ""; // pad input block size boundary. $length = $blocksize - (strlen($input) % $blocksize); ($i = 1; $i <= $length; $i++) { $padd .= chr($length); } return $input . $padd; } /** * remove pkcs5 padding string. * * @param string $input decrypted string. * * @return string string without padding. * @throws sagepayapiexception */ static protected function removepkcs5padding($input) { $blocksize = 16; $padchar = ord($input[strlen($input) - 1]); /* check padchar less block size */ if ($padchar > $blocksize) { throw new sagepayapiexception('invalid encryption string'); } /* check padding character mask */ if (strspn($input, chr($padchar), strlen($input) - $padchar) != $padchar) { throw new sagepayapiexception('invalid encryption string'); } $unpadded = substr($input, 0, (-1) * $padchar); /* chech result printable characters */ if (preg_match('/[[:^print:]]/', $unpadded)) { throw new sagepayapiexception('invalid encryption string'); } return $unpadded; } /** * encrypt string ready send sagepay using encryption key. * * @param string $string unencrypyted string. * @param string $key encryption key. * * @return string encrypted string. */ static public function encryptaes($string, $key) { // aes encryption, cbc blocking pkcs5 padding hex encoding. // add pkcs5 padding text encypted. $string = self::addpkcs5padding($string); // perform encryption php's mcrypt module. $crypt = mcrypt_encrypt(mcrypt_rijndael_128, $key, $string, mcrypt_mode_cbc, $key); // perform hex encoding , return. return "@" . strtoupper(bin2hex($crypt)); } /** * decode returned string sagepay. * * @param string $strin encrypted string. * @param string $password encyption password used encrypt string. * * @return string unecrypted string. * @throws sagepayapiexception */ static public function decryptaes($strin, $password) { // hex decoding aes decryption, cbc blocking pkcs5 padding. // use initialization vector (iv) set $str_encryption_password. $strinitvector = $password; // remove first char @ flag aes encrypted , hex decoding. $hex = substr($strin, 1); // throw exception if string malformed if (!preg_match('/^[0-9a-fa-f]+$/', $hex)) { throw new sagepayapiexception('invalid encryption string'); } $strin = pack('h*', $hex); // perform decryption php's mcrypt module. $string = mcrypt_decrypt(mcrypt_rijndael_128, $password, $strin, mcrypt_mode_cbc, $strinitvector); return self::removepkcs5padding($string); } }
setup variables now.
$gatewayoptions["encryptionpassword"] = "passwordpassword"; $crypt = "your=sagepay&query=string";
then encryption (sending sagepay) use this
//$crypt = base64_encode(protx_simplexor($crypt,$myencryptionpassword)); $crypt = sagepayutil::encryptaes($crypt, $gatewayoptions["encryptionpassword"]); var_dump($crypt); //@714dcf7fe82fada4b9f8cf53982d56ffc8f2021a5fc10481409ed1fd7bf6880e
and decryption (receiving sagepay) use this
//$crypt = protx_simplexor(base64_decode($crypt),$gatewayoptions["encryptionpassword"]); $crypt = sagepayutil::decryptaes($crypt, $gatewayoptions["encryptionpassword"]); var_dump($crypt); //your=sagepay&query=string
edit: removed base64encoding layer. protx assume base64 encoded string using old xor method must not use base64 encoding. instead necessary use hex encoding , start string "@" character.
Comments
Post a Comment