Php MCrypt rijndael-128到OpenSSL aes-128-ecb的转换

Php MCrypt rijndael-128到OpenSSL aes-128-ecb的转换,php,encryption,cryptography,mcrypt,php-openssl,Php,Encryption,Cryptography,Mcrypt,Php Openssl,由于Mcrypt已被弃用,我想在代码中使用OpenSSL,因为我们已经在服务器中使用了PHP7.0.17,而且不知道他们何时升级它 一些第三方API(托管在PHP5.x上,可能使用mcrypt)正在获取加密数据。他们提供了用于加密/解密字符串的方法 给你 $secret = 'a0a7e7997b6d5fcd55f4b5c32611b87c' ; public function encrypt128($str) { $block = mcrypt_get_block_s

由于Mcrypt已被弃用,我想在代码中使用OpenSSL,因为我们已经在服务器中使用了PHP7.0.17,而且不知道他们何时升级它

一些第三方API(托管在PHP5.x上,可能使用mcrypt)正在获取加密数据。他们提供了用于加密/解密字符串的方法

给你

$secret = 'a0a7e7997b6d5fcd55f4b5c32611b87c' ;

public function encrypt128($str)
    {
        $block = mcrypt_get_block_size("rijndael_128", "ecb");
        $pad   = $block - (strlen($str) % $block);
        $str .= str_repeat(chr($pad), $pad);

        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $secret, $str, MCRYPT_MODE_ECB));
    }

public function decrypt128($str)
    {
        $str = base64_decode($str);
        $str = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $secret, $str, MCRYPT_MODE_ECB);

        $len = strlen($str);
        $pad = ord($str[$len - 1]);

        return substr($str, 0, strlen($str) - $pad);
    }
使用这些方法字符串
small1
如果加密成为
v7ixp5vvafvxlt/MN8BVw==


我们希望在我们这边使用
openssl\u encrypt
,这样,如果我们用openssl加密相同的字符串,它必须给出与Mcrypt相同的结果。我已经研究过,使用rijndael-128模式ecb的mcrypt应该与OpenSSL
aes-128-ecb
兼容

在过去的几个小时里,我一直在尝试使用OpenSSL制作自己的方法来加密提供相同结果的字符串。到目前为止,我已经做到了这一点

public function sslEncrypt128($str)
{
    $secret = 'a0a7e7997b6d5fcd55f4b5c32611b87c';
    return base64_encode(openssl_encrypt($str, 'aes-128-ecb', $secret, OPENSSL_RAW_DATA));
}
但它为上述输入生成不同的字符串
SxJ3+EdaeItZx3/EwGTUbw==
。我不知道这是flag的问题还是padding的问题,欢迎任何指点

我在这里添加了在线测试的代码


提前感谢。

该键很可能被用作十六进制(它已经是十六进制格式)而不是要转换为十六进制的字符串


mcrypt:

mcrypt
不支持标准PKCS#7(née PKCS#5)填充,仅支持非标准空填充,但填充是在mcrypt之前显式添加的

加密
v7ixp5vvafxxlt/MN8BVw==
是基于PKCS#7填充的正确加密。ECB模式和键作为字符串

请参阅:

在十六进制中,请注意数据填充是清晰可见的:
键:613061376537393762366435666364356634623563333236313162383763

数据:736D616C6C310A0A0A

加密:BFB217A79BD56855575E5B7F30DF0157

在Base64中:
加密:v7ixp5vvafvxlt/MN8BVw==


OpenSSL:

请注意,密钥是256位,但带有“aes-128-ecb”的OpenSSL调用似乎意味着128位的密钥。所以钥匙不匹配

见:

在十六进制中,请注意数据填充是清晰可见的:
键:613061376537393762366435666364

数据:736D616C6C310A0A0A

加密:4B1277F8475A788B59C77FC4C064D46F

在Base64中:

encrypted:SxJ3+EdaeItZx3/EwGTUbw=
在您的具体示例中,我发现通过将
aes-128-ecb
更改为
aes-256-ecb
,它会产生与传统的
mcrypt\u encrypt
相同的输出

<?php

$str = 'Content';
if (strlen($str) % 16) {
    $str = str_pad($str, strlen($str) + 16 - strlen($str) % 16, "\0");
}

$key = 'KEY';
if (strlen($key) % 16) {
    $key = str_pad($key, strlen($key) + 16 - strlen($key) % 16, "\0");
}

$res1 = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB);
echo strToHex($res1) . ' | mcrypt_encrypt';

echo "<hr>";
echo strToHex(openssl_decrypt($res1, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING)) . ' | openssl_decrypt';

echo "<hr>";

$res2 = openssl_encrypt($str, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
echo strToHex($res2) . ' | openssl_encrypt';

echo "<hr>";
echo strToHex(openssl_decrypt($res2, "aes-128-ecb", $key, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING)) . ' | openssl_decrypt';


function strToHex($string) {
    $hex = '';
    for ($i = 0; $i < strlen($string); $i++) {
        $ord     = ord($string[$i]);
        $hexCode = dechex($ord);
        $hex     .= substr('0' . $hexCode, -2);
    }

    return strToUpper($hex);
}

ECB模式存在一些严重的安全问题。请确保它适合您的特定应用。通常CBC模式或CTR模式更安全。有关问题的说明,请参见。另请参见和,(它使用ECM模式)。注意:Base64数据对于计算机来说很好,但对于开发人员来说,从数据中理解任何内容都需要一个字节表示,十六进制满足这一需要,Base64没有。在您的代码示例中,通过将
aes-128-ecb
更改为
aes-256-ecb
,我能够在sslEncrypt128中生成相同的输出。谢谢@MichaelButler。它解决了我的问题
MCRYPT_RIJNDAEL_128
with
MCRYPT_MODE\u ECB
模式与开放式ssl
aes-256-ECB
相同。您可以将您的发现作为答案发布,我将接受它。我相信Mcrypt提供128、192和256位的块大小。AES仅提供128块大小。我的猜测是,
MCRYPT_RIJNDAEL_128
可能是指具有128位块大小的RIJNDAEL,即AES。密钥大小是一个不同的问题,这就是OpenSSL的
AES-256-CBC
中的
256
所表示的。如果使用标准加密算法名称(扫描),那么密码实例的Mcrypt算法名称将类似于
Rijndael-128(256)/CBC
。谢谢!数据和键上的填充使它与我从mcrypt方式得到的完全匹配。