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

时间:2010-10-29 14:06:18

标签: php c++ aes mcrypt crypto++

之前我设法将一些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可能有点过分 - 我需要的最小值是“对字节进行良好的加扰”,这样数据中各个字节的功能就不明显了。

3 个答案:

答案 0 :(得分:4)

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

我的解决方案是自己使用nOFB。根据{{​​3}} MCRYPT_MODE_NOFB强制反馈链等于算法的块大小,在这种情况下为AES128(Rijndael)的128位块/反馈,它与PHP mcrypt library reference的匹配mcrypt模块说明了nOFB。这很好,因为我发现nOFB反馈与块大小同步。因此,nOFB中的mcrypt和OpenSSL现在都是AES128的128位密钥/ iv /块/反馈大小,一切正常。

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

这不是一个很好的答案,但几年前基于非常业余的加密技术进行了最好的答案。

答案 1 :(得分:2)

查看phpseclib:

http://phpseclib.sourceforge.net/

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

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

答案 2 :(得分:1)

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

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

编写aes_cfb_128兼容PHP的完整详细信息在此安全堆栈交换问题中:aes cfb 128 decryption /encryption problem between Erlang and PHP。缺点是(来自Tom Leek):

  

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