没有 mcrypt 的 Sagepay 集成

Sagepay integration without mcrypt

我希望使用他们在此处的指导与 Sagepay/Opayo Form 集成: https://www.sagepay.co.uk/file/25041/download-document/FORM_Integration_and_Protocol_Guidelines_270815.pdf?token=Cfj49hcaD4kpE0zk7179ZLOaQx2RH_3oatPOrAV6MyM

Sagepay 现在已停止支持 SDK,这意味着我必须从这里找到 2013 实用程序集: https://github.com/ammaar23/sagepay-sdk-php/blob/master/lib/classes/util.php

我正在尝试从 mcrypt 迁移到 openssl_encrypt,但似乎无法复制所需的结果。

有 2 个函数在起作用:

static protected function addPKCS5Padding($input)
{
$blockSize = 16;
$padd = "";

// Pad input to an even block size boundary.
$length = $blockSize - (strlen($input) % $blockSize);
for ($i = 1; $i <= $length; $i++)
{
$padd .= chr($length);
}

return $input . $padd;
}

static public function encryptAes($string, $key)
{
// AES encryption, CBC blocking with PKCS5 padding then HEX encoding.
// Add PKCS5 padding to the text to be encypted.
$string = self::addPKCS5Padding($string);

// AH updated as mcrypt is now deprecated! 2020
$cipher = 'AES-128-CBC';
$ivsize = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivsize);

$crypt = openssl_encrypt($string,$cipher,$key,0,$iv);

// Perform hex encoding and return.
return "@" . strtoupper(bin2hex($crypt));
}

您可以看到我尝试实施 openssl_encrypt 但它不起作用。键是55a51621a6648525,输入字符串是VendorTxCode=TxCode-1310917599-223087284&Amount=36.95&Currency=GBP&Description=description&CustomerName=Fname Surname&CustomerEMail=customer@example.com&BillingSurname=Surname&BillingFirstnames=Fname&BillingAddress1=BillAddress Line 1&BillingCity=BillCity&BillingPostCode=W1A 1BL&BillingCountry=GB&BillingPhone=447933000000&DeliveryFirstnames=Fname&DeliverySurname=Surname&DeliveryAddress1=BillAddress Line 1&DeliveryCity=BillCity&DeliveryPostCode=W1A 1BL&DeliveryCountry=GB&DeliveryPhone=447933000000&SuccessURL=https://example.com/success&FailureURL=https://example.com/failure

输出结果为:

@2DCD27338114D4C39A14A855702FBAB2EF40BCAC2D76A3ABC0F660A07E9C1C921C2C755BA9B59C39F882FBF6DFED114F23141D94E50A01A665B1E31A86C07CA1CD1BB8EF5B6CF2C23D495CD 79F9C0F678D61773E7A1AA30AA5B23D56503FC0B52AC0694A8C341263D2C5FE1BAD93BDB94726761E155E900448F644AF1F67BE1AC77E852B9D90809A44F258EE9478B6D8C1C4ED58759263E7DBF 8871C6592287C0358F36F4EEC326CEDDD440DA2FED8AB35F1B630A5C6FA671E4D78CC8CACECF9DFDC31D6C5EC8270FB21E297E2C2E14F99A04223EFFD4F00062D440E78A3D2C7140EC8F123D24 7B75E7482AE98858DA34D37EDE6D7C69AA74391F559305CF675ADB3615244A107ABBB6AF26E29A2FFA059B12688D90FE09E0DE069325BFF3587A695F5DA36E4B809B69CC9A37034F166B63B5A62 B986F4DA34E9AC9516AFDE70642EC7DAD1AEBA93A1F347D6AC7046E967DCBFE7ACFCEE5DAFC0B29F1765032B3060EBE565CBD57D092075D15CF12725199C6881605B2E0F105698CE3ADD04361C A9D620C187B90E3F9849445B5C3C0FDF1768BFFD61F97E51316826F4F10E0E3E668F0A9F5ED9CCDA6F2C7CC957F12DB48F9041482E3D035E7A91852C404BFA325FED947E71F57B871DFAC6AF4FF2 9F4513A4A80B2D7ECC9D19D47ED04FA99CDFC881DFA771E1EA4F3F9B2C5AC673EF3DA2699A309CC8522993A63CB8D45D3CDF09B1DFDC573CD19679B250AD6721450B5042F201670B464505DCAE F59E2C67ABACC9AE2EEE793CE191FEBF66B8FAF4204EFFB359246B9C99FB52805C46375FF35140F74707FBC73C7731A28A2C883A

我如何从我的输入代码创建所需的输出,因为我生成的输出开头为:403444324634333730363535313636373136413432363737353332363133303644373736

  • openssl_encrypt 默认应用 PKCS7 填充,因此不再需要 addPKCS5Padding 方法。
  • mcrypt_encrypt 代码中使用了 iv = key,因此您不能为代码等价生成随机 IV。
  • openssl_encrypt中,标志OPENSSL_RAW_DATA必须作为第四个参数应用,否则数据将以Base64编码返回。

经过这些更改,openssl_encrypt 代码产生与 mcrypt_encrypt 代码相同的结果:

<?php
function encryptAes($string, $key)
{
    //$string = self::addPKCS5Padding($string);                                     // don't pad explicitly
 
    $cipher = 'AES-128-CBC';                                                        
    //$ivsize = openssl_cipher_iv_length($cipher);
    //$iv = openssl_random_pseudo_bytes($ivsize);                                   // mcrypt_encrypt code: iv = key

    $crypt = openssl_encrypt($string,$cipher,$key,OPENSSL_RAW_DATA,$key);           // use raw data

    return "@" . strtoupper(bin2hex($crypt));
}

$plain = "VendorTxCode=TxCode-1310917599-223087284&Amount=36.95&Currency=GBP&Description=description&CustomerName=Fname Surname&CustomerEMail=customer@example.com&BillingSurname=Surname&BillingFirstnames=Fname&BillingAddress1=BillAddress Line 1&BillingCity=BillCity&BillingPostCode=W1A 1BL&BillingCountry=GB&BillingPhone=447933000000&DeliveryFirstnames=Fname&DeliverySurname=Surname&DeliveryAddress1=BillAddress Line 1&DeliveryCity=BillCity&DeliveryPostCode=W1A 1BL&DeliveryCountry=GB&DeliveryPhone=447933000000&SuccessURL=https://example.com/success&FailureURL=https://example.com/failure";
$key = "55a51621a6648525";
print(encryptAes($plain, $key));
?>

对于选择 iv = key note 还有 this question 的答案。

@Topaco 回答得很好。这是一个附加位,(与问题无关),在进行 Sagepay 集成时,您还需要解密功能来验证 payment/callback。这是您可以使用的功能。

    function decrypytAES($string, $key) {
        $cipher = 'AES-128-CBC';
        $strIn = hex2bin(substr($strIn, 1));
        return openssl_decrypt($strIn, $cipher, $key, OPENSSL_RAW_DATA, $key);
    }