将Mcrypt升级为SagePay格式的OpenSSL加密

问题描述 投票:0回答:1

我有一个收集数据的表格,然后将其提交给SagePay,并传递数据。在我们需要更新到PHP 7.2之前,它一直工作良好,并且由于不再支持mcrypt,我们将切换到OpenSSL。

收集数据的形式工作正常,但传输数据未加密,交易失败。

功能文件中的代码:

$protx_encryption_password      = "my_password";
$protx_vendor                   = "my_vendor";

$data = "";
while(list($key,$value) = each($protx)) {
    $data .= $key."=".$value."&";
}
$data = trim($data," &");

$crypt = openssl_encrypt($data, $protx_encryption_password);

function openssl_encrypt($string, $key) {
    $iv = substr($value, 0, 16);
    $ciphertext = substr($value, 16);
    $key = hash('sha256', $key, true);
    $crypt = openssl_encrypt(
        $ciphertext, 'AES-256-CBC', $key, 
        OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, 
        $iv
    );
    return rtrim($crypt, "\0");
}

$ crypt数据像以前在mcrypt版本中一样在隐藏字段中发送,我只需要一些帮助才能使加密正常工作。

以前以mcrypt方式:

$crypt = encryptAes($data, $protx_encryption_password);

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

// Perform encryption with PHP's MCRYPT module.
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);

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

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;
}

这是我做过的第一个OpenSSL加密,因此,我很感谢您的协助。 SagePay需要使用PCKS#5(AES-128-CBC-PKCS#5)在CBC模式下使用128位块大小的AES-128加密进行加密。任何帮助都会真正有帮助。

encryption openssl mcrypt
1个回答
0
投票

首先,这是一个不好的方案。即使在可能的情况下,使用(真实)密码作为现代加密的密钥几乎总是不安全的。密码和密钥是不同的事物,它们的设计和指定是不同的。当然,有些人不知道自己在做什么[实际上是一个密钥,而且是密码,而且由于我不知道SagePay(当然,您也没有提供真正的价值),所以我不知道是不是这种情况。此外,将密钥(密码)用作IV完全是不标准的。对于给定密钥下的每次加密(或至少每个数据值),IV的全部要different,而给定密钥在定义上与其本身相同。这真是太可笑了,我不记得有任何分析过它会导致什么攻击以及发生什么攻击的分析,尽管一般而言,违反“安全合同”通常会导致问题。对IV使用any固定值,这是一个比较常见的错误,对于CBC模式仅是中等程度的不利,尽管对于其他某些模式则更糟。]但是,您显然没有选择更改此方案的选项,如果您这样做,它实际上不是编程Q,而是属于security.SX或crypto.SX依赖。

也仅供参考,说“具有128位块的AES-128”毫无意义。 AES

always

使用128位块;那是建立它的竞争规则的一部分。 Rijndael确实具有其他块大小的选项,这就是为什么实现Rijndael的mcrypt或多或少地指定了块大小,而OpenSSL却实现了AES,而AES并不需要指定块大小- -only密钥大小。第二,您建议的新代码是胡说八道。首先,您尝试重新定义不允许的标准功能,然后清楚地将您提出的逻辑设计为解密,不加密,一种完全不同的方案,而不是您提出的方案,然后进行修改。

mcrypt_encrypt对明文进行零填充,在旧版本中,根据需要对键和iv进行零填充。对于Rijndael,它还根据提供的密钥来选择密钥大小。因为您说要使用AES-128(即128位密钥),所以所谓的“密码”不得超过128位,但可以少于128位。您发布的代码对数据进行了显式的PKCS5填充,因此未使用mcrypt的零填充,并且正如Peter所言,openssl_encrypt(及其在下面使用的OpenSSL例程)默认情况下会进行PCKS5 / 7填充,因此您所需要的全部是:

function encryptAes_new ($string, $key) { $key = str_pad($key,16,"\0"); # if supplied key is, or may be, less than 16 bytes $crypt = openssl_encrypt($string, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $key); // Perform hex encoding and return. return "@" . strtoupper(bin2hex($crypt)); }

((注:原始PKCS5填充仅处理64位/ 8字节块,而PKCS7将其扩展为其他大小,但是2017年PKCS5v2.1也引用了CMS对其进行扩展,CMS是PKCS7的IETF版本,因此现在一样。)
© www.soinside.com 2019 - 2024. All rights reserved.