移植 Crypto++ 时密钥大小不正确AES 加密到 PHP 的 mcrypt

发布于 2024-09-29 23:18:56 字数 1469 浏览 2 评论 0 原文

早些时候,我设法将一些 C++ CryptoPP Rijndael_128 CBC 代码移植到 MCrypt PHP,但现在我遇到了 CFB 模式的问题。 C++ 和 PHP 结果不匹配(第一个字节匹配,但这可能是巧合,其他一切都不是)。通过一些诊断,PHP 的 mcrypt 似乎没有正确设置密钥长度?

这是 C++(为了简单起见,删除了诊断和杂项):

CFB_Mode<AES>::Encryption encryptor(g_encrypt_key, AES::DEFAULT_KEYLENGTH, g_encrypt_iv);

StringSource ss( sInput.c_str(), true, 
        new StreamTransformationFilter( encryptor, 
            new HexEncoder( new StringSink( sEncryptedOut ) )
        ));

这是 PHP:

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CFB, '')
mcrypt_generic_init($cipher, $g_encrypt_key, $g_encrypt_iv);

$sEncryptedOutput = mcrypt_generic( $cipher, $sInput);
mcrypt_generic_deinit($cipher);
mcrypt_module_close($cipher);

g_encrypt_keyg_encrypt_iv 都是 16 个字节长,并且字节与 C++ 和 PHP 版本匹配。对于 PHP 版本,它是由字节构造的二进制字符串(是的,我已经检查过它们是相同的)。

我添加了对 PHP 版本的调用来检查 $cipher 的块大小、密钥大小等。 块大小和iv大小均为16;支持的密钥大小报告为 16、24 和 32 - 全部符合预期。

我认为问题在于密钥大小被报告为 32 字节。查看 mcrypt 文档,设置密钥大小的唯一方法是提供所需大小的密钥。但我传递的是 16 字节密钥!那么为什么它报告存在 32 字节密钥呢?如果CFB模式必须使用32字节密钥,那么为什么CryptoPP会接受它?解决办法是什么?我可以强制 PHP 使用已提供的 16 字节密钥吗?或者我是否缺少一个参数,该参数默认为 CryptoPP 中的设置与 MCrypt 中的设置不同?

我使用 CFB 模式是因为我想最小化生成的加密数据的长度。填充将引入的几个字节在此应用程序中确实很重要。

我需要能够在 C++ 中加密/解密,但只能在 PHP 中加密。 AES 对于我的应用程序来说可以说是杀伤力过大 - 我需要的最低限度是“对字节进行良好的加扰”,以便数据中各个字节的功能不明显。

Earlier I managed to port some C++ CryptoPP Rijndael_128 CBC code to MCrypt PHP, but now I'm having problems with CFB mode. The C++ and PHP results do not match (well the first byte matches but this could be coincidence, everything else doesn't). With some diagnostics, it looks like PHP's mcrypt is not setting the key length correctly?

Here's the C++ (diagnostics and sundries removed for simplicity):

CFB_Mode<AES>::Encryption encryptor(g_encrypt_key, AES::DEFAULT_KEYLENGTH, g_encrypt_iv);

StringSource ss( sInput.c_str(), true, 
        new StreamTransformationFilter( encryptor, 
            new HexEncoder( new StringSink( sEncryptedOut ) )
        ));

And here's the PHP:

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CFB, '')
mcrypt_generic_init($cipher, $g_encrypt_key, $g_encrypt_iv);

$sEncryptedOutput = mcrypt_generic( $cipher, $sInput);
mcrypt_generic_deinit($cipher);
mcrypt_module_close($cipher);

g_encrypt_key and g_encrypt_iv are both 16 bytes long, and the bytes match for the C++ and PHP versions. For the PHP version it is a binary string constructed from the bytes (yes I have checked these are identical).

I have added calls to the PHP version to check $cipher's block size, key size, etc.
The block size and iv size are both 16; supported key sizes are reported as 16, 24, and 32 - all as expected.

Where I think the problem is, is that the keysize is being reported as 32 bytes. Looking at the mcrypt docs, the only way of setting the keysize is by supplying a key of the required size. But I'm passing a 16 byte key! So why is it reporting the presence of a 32 byte key? If CFB mode must use a 32 byte key, then why does CryptoPP accept it as okay? What is the solution? Can I force PHP to use the 16 byte key that has been provided? Or is there a parameter that I'm missing which is defaulting to a different setting in CryptoPP than in MCrypt?

I am using the CFB mode because I want to minimize the length of the resulting encrypted data. The few bytes that padding would introduce, do matter in this application.

I need to be able to encrypt/decrypt in C++ but only encrypt in PHP. AES is arguably overkill for my application - the minimum I need is "a good scrambling of the bytes" so that the function of individual bytes in the data are not obvious.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情感失落者 2024-10-06 23:18:56

已经有一段时间了,但几年前我在使用 CFB 的 mcrypt 和 openSSL 方面遇到了一些类似的问题。最后,我发现 mcrypt 在 CFB 模式下使用了与 openssl 不同的默认反馈链大小。也就是说,我相信CFB中的openSSL AES128使用了128位的块大小和反馈大小,而mcrypt使用了128位的块大小和8位的反馈大小。我无法证实这一点,这只是当时基于阅读一些旧论坛帖子的猜测。不管这个理论的真实性如何,我并不是唯一一个或第一个遇到这个特殊问题的人。

对我来说,解决方案是像你自己一样使用 nOFB。根据 PHP mcrypt 库参考 MCRYPT_MODE_NOFB 强制反馈链等于算法的块大小,在本例中为 AES128 (Rijndael) 的 128 位块/反馈,它与 手册页说明了有关 nOFB 的信息。这很好,因为我发现 nO​​FB 反馈与块大小同步。因此,nOFB 中的 mcrypt 和 OpenSSL 现在都是 AES128 的 128 位密钥/iv/块/反馈大小,并且一切正常。

就 PHP 报告 256 位密钥大小(32 字节)而言,返回当前密码算法密钥大小的函数实际上返回最大密钥大小,文档中没有明确说明。我知道这一点是因为我现在一直在各种项目中使用的小类与 openSSL 以及 CBC 或 nOFB 中的任何其他 AES 库完美配合。如果 mcrypt 用额外的 128 位空字符串或其他内容填充我的 128 位(16 个字符)密钥,则情况不会如此,并且无论如何在技术上都是不正确的。

这并不是一个很好的答案,但我在几年前对密码学的一次非常业余的尝试中得到了最好的答案。

It's been awhile, but I had some similar problems with mcrypt and openSSL using CFB a couple years ago. In the end, I discovered mcrypt used a different default feedback chain size than openssl in CFB mode. That is to say, I believe an openSSL AES128 in CFB used a block size and feedback size of 128 bits, while mcrypt used a block size of 128bits and a feedback size of 8 bits. I have no way to confirm this, it was just speculation at the time based on reading some old forum posts. Regardless of the truth of that theory, I was not the only person or first to have this particular issue.

The solution for me was to use nOFB as yourself. According to the PHP mcrypt library reference MCRYPT_MODE_NOFB forces the feedback-chain to equal the algorithm's block size, in this case a 128bit block/feedback for AES128 (Rijndael), which matches with what the manpage for the mcrypt module states about nOFB. This is good as everything I found said nOFB feedback is synchronous to the block size. Thus, both mcrypt and OpenSSL in nOFB were now 128 bit key/iv/block/feedback sizes for AES128 and everything worked fine.

As far as PHP reporting 256bit keysizes (32 bytes), the function that returns the current cipher-algorithm key size actually returns the maximum key size, which isn't clearly stated in the documentation. I know this because my little class I use all the time now for various projects works perfectly fine with openSSL and any other AES libraries in CBC or nOFB . This wouldn't be the case if mcrypt was padding my 128bit(16 char) key with an additional 128bits of null string, or whatever, and wouldn't be technically correct anyhow.

Not really a good answer, but the best I got based on a very amateurish foray into cryptography several years ago.

装纯掩盖桑 2024-10-06 23:18:56

查看 phpseclib:

http://phpseclib.sourceforge.net/

您可以将密钥大小和块大小设置为任何你想要的。

例如。 $aes->setKeyLength(128) 或 $aes->setKeyLength(256);

Check out phpseclib:

http://phpseclib.sourceforge.net/

You can set the key size and block size to whatever you want.

eg. $aes->setKeyLength(128) or $aes->setKeyLength(256);

神也荒唐 2024-10-06 23:18:56

我遇到了这个问题 - 有几点。默认情况下,PHP Rijndael 模式将反馈循环设置为 8 位 - AES 需要与 IV/Key 的长度相同。

您可以使用模式“ncfb”而不是“cfb”或 MCRYPT_MODE_CFB 来完成此操作。

有关编写 aes_cfb_128 兼容 PHP 的完整详细信息,请参见以下 Security Stackexchange 问题:Erlang 和 PHP 之间的 aes cfb 128 解密/加密问题。它的缺点是(来自汤姆·利克):

...对于 CFB 和 OFB(它们彼此不同并且不能互换使用),您必须担心“反馈长度”,它不一定在各种加密库中得到清晰的记录。加密和解密都必须使用相同的反馈长度才能互操作。

I had this problem - couple of points. By default the PHP Rijndael mode sets the feedback loop to 8bits - to be AES is needs to be the same length as the IV/Key.

You can do this by using the mode 'ncfb' instead of 'cfb' or MCRYPT_MODE_CFB.

Full details of writing aes_cfb_128 compatible PHP are at this Security Stackexchange question: aes cfb 128 decryption /encryption problem between Erlang and PHP. The short of it is (from Tom Leek):

... for both CFB and OFB (which are distinct from each other and cannot be used interchangeably), you have to worry about the "feedback length" which is not necessarily documented with high clarity in various crypto libraries. Both encryption and decryption must use the same feedback length to interoperate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文