关于openssl AES/ECB/PKCS5Padding加密 求助

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于openssl AES/ECB/PKCS5Padding加密 求助相关的知识,希望对你有一定的参考价值。

参考技术A ecb加密方式,其实底层是调用aes_encrypt接口,你可以去看源码。
下面的代码给你一个参考,只不过,我是在调用aes_encrypt外面,自己严格控制了in和out的长度,out的长度大于in,并且必须是大于等于16的整数倍。

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

【中文标题】MCrypt rijndael-128 到 OpenSSL aes-128-ecb 的转换【英文标题】:MCrypt rijndael-128 to OpenSSL aes-128-ecb conversion 【发布时间】:2017-12-26 08:56:19 【问题描述】:

由于不推荐使用 Mcrypt,我想在我的代码中使用 OpenSSL,因为我们已经在我们的服务器中使用 php 7.0.17 并且不知道他们何时升级它。

某些第三方 API(可能托管在 PHP 5.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如果加密变成v7IXp5vVaFVXXlt/MN8BVw==


我们想在我们这边使用openssl_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的问题,欢迎指点。

我这里添加了代码在线测试https://3v4l.org/v2J2N

提前致谢。

【问题讨论】:

ECB 模式存在一些严重的安全问题。 非常确保它适合您的特定应用。一般CBC模式或CTR模式会更安全。请参阅Electronic Codebook 以获取问题的说明(字面意思)。 另见Upgrading my encryption library from Mcrypt to OpenSSL、Replace Mcrypt with OpenSSL和Preparing for removal of Mcrypt in PHP 7.2、Use openssl_encrypt to replace Mcrypt for 3DES-ECB encryption(它使用ECM模式)。 注意:Base64 数据对计算机来说很好,但对于开发人员来说,从数据中理解任何东西都需要按字节表示,十六进制满足这种需求,而 Base64 则不然。 在您的代码示例中,通过将 aes-128-ecb 更改为 aes-256-ecb,我能够在 sslEncrypt128 中产生相同的输出。 谢谢@MichaelButler。它解决了我的问题。 MCRYPT_RIJNDAEL_128MCRYPT_MODE_ECB 模式与打开 ssl aes-256-ecb 相同。您可以将您的发现作为答案发布,我会接受。 【参考方案1】:

这对我有用:

<?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);

【讨论】:

老兄,谢谢!数据和密钥上的填充使它与我从 mcrypt 方式得到的完全匹配。【参考方案2】:

在您的具体示例中,我发现通过将 aes-128-ecb 更改为 aes-256-ecb,它会产生与旧版 mcrypt_encrypt 相同的输出。

【讨论】:

我相信 Mcrypt 提供了 128、192 和 256 位的 块大小。 AES 仅提供 128 块大小。我的猜测是,MCRYPT_RIJNDAEL_128 可能指的是具有 128 位块大小的 Rijndael,即 AES。密钥大小是另一回事,这就是 OpenSSL 的 AES-256-CBC 中的 256 所表示的内容。如果使用标准加密算法名称 (SCAN),则密码实例的 Mcrypt 算法名称将类似于 Rijndael-128(256)/CBC【参考方案3】:

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


mcrypt:

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

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

请参阅:mcrypt - AES CALCULATOR。

在十六进制中,注意数据填充清晰可见:key: 6130613765373939376236643566636435356634623563333236313162383763data: 736D616C6C310A0A0A0A0A0A0A0A0A0Aencrypted: BFB217A79BD56855575E5B7F30DF0157

在 Base64 中:encrypted: v7IXp5vVaFVXXlt/MN8BVw==


OpenSSL:

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

见:OpenSSL - AES CALCULATOR

在十六进制中,注意数据填充清晰可见:key: 61306137653739393762366435666364data: 736D616C6C310A0A0A0A0A0A0A0A0A0Aencrypted: 4B1277F8475A788B59C77FC4C064D46F

在 Base64 中:encrypted: SxJ3+EdaeItZx3/EwGTUbw==

【讨论】:

以上是关于关于openssl AES/ECB/PKCS5Padding加密 求助的主要内容,如果未能解决你的问题,请参考以下文章

python-aes(ECB)加解密-支持16/32位

Cipher.getInstance("AES/ECB/PKCS5Padding")怎么解决?

关于蓝牙通信的数据AES128 ECB加密解密

统一认证加密及签名参数校验

openSSL实现AES加密

iOS逆向之对称算法(下)