首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以OpenSSL格式将mcrypt升级为SagePay加密

以OpenSSL格式将mcrypt升级为SagePay加密
EN

Stack Overflow用户
提问于 2019-12-19 20:29:46
回答 1查看 561关注 0票数 0

我有一个表单,它收集数据,然后将它提交给SagePay,传递数据。这很好,直到我们需要更新到PHP7.2,并且由于mcrypt不再支持,我们切换到OpenSSL。

收集数据的表单工作良好,但传输数据不加密,事务失败。

函数文件中的代码:

代码语言:javascript
复制
$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的方式:

代码语言:javascript
复制
$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需要使用AES-128加密,在CBC模式下使用PCKS#5 (AES-128-CBC-PKCS#5),其块大小为128位。任何帮助都会很有帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-21 07:55:46

首先,这是一个糟糕的计划。使用(真实的)密码作为现代密码学的关键,即使在可能的情况下,也几乎总是不安全的。密码和密钥是不同设计和不同指定的东西。当然,一些不知道自己在做什么的人把实际上是密钥的东西称为密码,而且由于我不知道SagePay (当然你也不给出真正的值),我不知道这里是否存在这种情况。此外,使用密钥(或密码)作为IV是非常不标准的。对于给定密钥下的每个加密(或至少每个数据值),IV的全部要点是不同的,而根据定义,给定密钥与其本身相同。这是如此愚蠢,我不记得看到任何分析它是否和什么攻击,虽然一般情况下,违反‘安全合同’通常会导致问题。对IV使用任何固定值,这是一个更常见的错误,对于CBC模式来说,这只是中等程度的错误,尽管对于其他一些模式来说,情况要糟糕得多。

但是,显然您没有选择改变这个方案,如果您这样做了,它将不是真正的编程Q,而是属于security.SX或可能的crypto.SX依赖。

另外,说"AES-128和128位块“也是没有意思的。AES总是使用128位块,这是建立它的竞争规则的一部分。Rijndael确实有其他块大小的选项,这就是为什么或多或少实现Rijndael的mcrypt指定块大小,但OpenSSL实现的是AES,它不需要也不指定块大小--只指定键大小。

第二,你提议的新代码是胡说八道。首先,您尝试重新定义一个不允许的标准函数,然后您提出的逻辑被明确地设计为解密,而不是加密,一个完全不同的方案,而不是您所呈现的方案,然后被破坏。

mcrypt_encrypt为纯文本提供零页,在旧版本中则根据需要使用键和iv。对于Rijndael,它还根据提供的密钥选择密钥大小;因为您说要AES-128 (即128位密钥),所以所谓的“密码”不能超过128位,但可能更少。您发布的代码对数据进行显式的PKCS5填充,因此不使用mcrypt的零填充,正如彼得评论的那样,默认情况下,openssl_encrypt (以及它在下面使用的OpenSSL例程)可以填充PCKS5 5/7,所以您只需要:

代码语言:javascript
复制
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将其扩展到其他大小,但PKCS5v2.1在2017年也扩展了引用PKCS7版本的CMS,因此它们现在是一样的。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59416539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档