以SagePay网关形式将mcrypt升级为OpenSSL加密

以SagePay网关形式将mcrypt升级为OpenSSL加密,openssl,opayo,Openssl,Opayo,目前,我们的SagePay网关表单中有mcyrpt加密,这在PHP7.4中不可用或不受支持 有人知道如何将下面的代码从mcyrpt更改为OpenSSL吗 // AES encryption, CBC blocking with PKCS5 padding then HEX encoding. // Add PKCS5 padding to the text to be encypted. $string = self::addPKCS5Padding($string);

目前,我们的SagePay网关表单中有mcyrpt加密,这在PHP7.4中不可用或不受支持

有人知道如何将下面的代码从mcyrpt更改为OpenSSL吗

    // AES encryption, CBC blocking with PKCS5 padding then HEX encoding.
    // Add PKCS5 padding to the text to be encypted.
    $string = self::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));
}

/**
 * Decode a returned string from SagePay.
 *
 * @param string $strIn         The encrypted String.
 * @param string $password      The encyption password used to encrypt the string.
 *
 * @return string The unecrypted string.
 * @throws SagepayApiException
 */
static public function decryptAes($strIn, $password)
{
    // HEX decoding then AES decryption, CBC blocking with PKCS5 padding.
    // Use initialization vector (IV) set from $str_encryption_password.
    $strInitVector = $password;

    // Remove the first char which is @ to flag this is AES encrypted and HEX decoding.
    $hex = substr($strIn, 1);

    // Throw exception if string is malformed
    if (!preg_match('/^[0-9a-fA-F]+$/', $hex))
    {
        throw new SagepayApiException('Invalid encryption string');
    }
    $strIn = pack('H*', $hex);

    // Perform decryption with PHP's MCRYPT module.
    $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC, $strInitVector);
    return self::removePKCS5Padding($string);
}
下面是我们正在尝试的OpenSSL代码,但它需要一些调整,任何关于我们需要更改什么以获得OpenSSL代码来取代上述mcyrpt的建议都将不胜感激

发布的openssl代码有效,即使用
encrypt\u openssl
加密的明文可以使用
decrypt\u openssl
解密。但是,openssl代码在功能上与mcrypt代码不同,即使用mcrypt代码加密的数据不能使用openssl代码解密,反之亦然

我不太清楚工作流程,但我怀疑mcrypt代码的加密和解密逻辑也被SagePay网关使用,因此通信时必须确保
openssl
代码在功能上与
mcrypt
代码相同(尽管
openssl
代码的实现比mcrypt代码更安全)

不幸的是,代码的重要部分没有发布,例如加密方法不完整,
addPKCS5Padding
removePKCS5Padding
完全缺失,因此必须处理部分假设

关于mcrypt规范,适用于:

  • AES-128用于CBC模式。AES-128需要16字节的密钥
  • 由于IV使用了密钥。请注意,这通常是不安全的
  • mcrypt本身隐式地在变量中应用零填充,即如果明文的长度已经对应于块大小的整数倍,则不执行填充。因为使用PKCS5(实际上是PKCS7)自定义填充首先完成,mcrypt填充不会生效,因此有效地应用了PKCS5填充。不幸的是,addPKCS5Padding和removePKCS5Padding的实现未发布,因此无法检查它们是否都符合标准。解密后,PKCS5填充将被删除(与mcrypt内置的零填充不同)
  • 加密使用大写字母对密文执行十六进制编码,并在其前面加上
    @
关于openssl,必须考虑以下事项:

  • openssl默认使用PKCS7填充(在解密过程中默认删除),这在功能上与mcrypt代码中使用的填充相同(至少在mcrypt代码中使用的自定义PKCS5填充与标准匹配的情况下)
  • openssl\u encrypt
    返回默认编码的密文Base64(openssl\u decrypt也需要此编码)。标志
    openssl\u RAW\u DATA
    导致openssl\u encrypt将数据作为原始数据返回(openssl\u decrypt也需要原始数据)
在假设范围内,以下openssl实现在功能上与mcrypt实现相同。必须使用16字节的密钥:

function encrypt_openssl($msg, $key, $iv) { 
    $encryptedMessage = openssl_encrypt($msg, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); 
    return '@' . strtoupper(bin2hex($encryptedMessage));
} 

function decrypt_openssl($encMsg, $key, $iv) { 
    $encMsg = substr($encMsg, 1);
    // your validation stuff
    $encMsg = hex2bin($encMsg);
    return openssl_decrypt($encMsg, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); 
} 
编辑:

这两种方法
addPKCS5Padding
removePKCS5Padding
符合PKCS7标准。无需修改。这些函数不得在openssl函数中使用,因为openssl隐式使用PKCS7填充,因此将填充两次,这将导致不同的密文

SagePay代码的加密与我发布的openssl函数的加密相匹配,这一点很容易测试:

使用SagePay代码进行加密(可执行代码,例如选择V7.0.x或更低版本):

使用openssl函数进行加密(例如,可以执行代码):

加密和解密都匹配。

发布的openssl代码有效,即使用
encrypt\u openssl
加密的明文可以使用
decrypt\u openssl
进行解密。但是,openssl代码在功能上与mcrypt代码不同,即使用mcrypt代码加密的数据无法使用openssl co进行解密德,反之亦然

我不太清楚工作流程,但我怀疑mcrypt代码的加密和解密逻辑也被SagePay网关使用,因此通信时必须确保
openssl
代码在功能上与
mcrypt
代码相同(尽管
openssl
代码的实现比mcrypt代码更安全)

不幸的是,代码的重要部分没有发布,例如加密方法不完整,
addPKCS5Padding
removePKCS5Padding
完全缺失,因此必须处理部分假设

关于mcrypt规范,适用于:

  • AES-128用于CBC模式。AES-128需要16字节的密钥
  • 由于IV使用了密钥。请注意,这通常是不安全的
  • mcrypt本身隐式地在变量中应用零填充,即如果明文的长度已经对应于块大小的整数倍,则不执行填充。因为使用PKCS5(实际上是PKCS7)自定义填充首先完成,mcrypt填充不会生效,因此有效地应用了PKCS5填充。不幸的是,addPKCS5Padding和removePKCS5Padding的实现未发布,因此无法检查它们是否都符合标准。解密后,PKCS5填充将被删除(与mcrypt内置的零填充不同)
  • 加密使用大写字母对密文执行十六进制编码,并在其前面加上
    @
关于openssl,必须考虑以下事项:

  • openssl默认使用PKCS7填充(在解密过程中默认删除),这在功能上与mcrypt代码中使用的填充相同(在
    <?php
    class SagepayApiException extends Exception {}
    
    class SagePayTest {
    
        static public function encryptAes($string, $key)
        {
            $string = self::addPKCS5Padding($string);
            $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key);
            return "@" . strtoupper(bin2hex($crypt));
        }
        
        static public function decryptAes($strIn, $password)
        {
            $strInitVector = $password;
            $hex = substr($strIn, 1);
            if (!preg_match('/^[0-9a-fA-F]+$/', $hex))
            {
                throw new SagepayApiException('Invalid encryption string');
            }
            $strIn = pack('H*', $hex);
            $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC, $strInitVector);
            return self::removePKCS5Padding($string);
        }
        static protected function addPKCS5Padding($input)
        {
            $blockSize = 16;
            $padd = "";
            $length = $blockSize - (strlen($input) % $blockSize);
            for ($i = 1; $i <= $length; $i++)
            {
                $padd .= chr($length);
            }
            return $input . $padd;
        }
        static protected function removePKCS5Padding($input)
        {
            $blockSize = 16;
            $padChar = ord($input[strlen($input) - 1]);
            if ($padChar > $blockSize)
            {
                throw new SagepayApiException('Invalid encryption string');
            }
            if (strspn($input, chr($padChar), strlen($input) - $padChar) != $padChar)
            {
                throw new SagepayApiException('Invalid encryption string');
            }
            $unpadded = substr($input, 0, (-1) * $padChar);
            if (preg_match('/[[:^print:]]/', $unpadded))
            {
                throw new SagepayApiException('Invalid encryption string');
            }
            return $unpadded;
        }
    }
    
    $plaintext = "The quick brown fox jumps over the lazy dog";
    $testkey = "95tjbs763khd9zh7";
    $encrypted = SagePayTest::encryptAes($plaintext, $testkey);
    $decrypted = SagePayTest::decryptAes($encrypted, $testkey);
    print("Ciphertext (hex): " . $encrypted . PHP_EOL);
    print("Decrypted  (hex):  " . bin2hex($decrypted) . PHP_EOL);
    print("Decrypted       :  " . $decrypted . PHP_EOL);
    ?>
    
    Ciphertext (hex): @67D4D4E0019BA7D0E75CC92C41488EF13613C1ED8A95B60E56347D1514AC5D7AF780F4314CA047A487AB67DF2D94174A
    Decrypted  (hex):  54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67
    Decrypted       :  The quick brown fox jumps over the lazy dog
    
    <?php
    function encrypt_openssl($msg, $key, $iv) { 
        $encryptedMessage = openssl_encrypt($msg, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); 
        return '@' . strtoupper(bin2hex($encryptedMessage));
    } 
    
    function decrypt_openssl($encMsg, $key, $iv) { 
        $encMsg = substr($encMsg, 1);
        // your validation stuff
        $encMsg = hex2bin($encMsg);
        return openssl_decrypt($encMsg, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv); 
    }
    
    $plaintext = "The quick brown fox jumps over the lazy dog";
    $testkey = "95tjbs763khd9zh7";
    $encrypted = encrypt_openssl($plaintext, $testkey, $testkey);
    $decrypted = decrypt_openssl($encrypted, $testkey, $testkey);
    print("Ciphertext (hex): " . $encrypted . PHP_EOL);
    print("Decrypted  (hex):  " . bin2hex($decrypted) . PHP_EOL);
    print("Decrypted       :  " . $decrypted . PHP_EOL);
    ?>
    
    Ciphertext (hex): @67D4D4E0019BA7D0E75CC92C41488EF13613C1ED8A95B60E56347D1514AC5D7AF780F4314CA047A487AB67DF2D94174A
    Decrypted  (hex):  54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67
    Decrypted       :  The quick brown fox jumps over the lazy dog