代码之家  ›  专栏  ›  技术社区  ›  winwaed

将crypto++aes加密移植到php的mcrypt时密钥大小不正确

  •  2
  • winwaed  · 技术社区  · 14 年前

    早些时候,我设法将一些C++Cultopp RijnDael128 CBC代码移植到McLIPPT 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_key g_encrypt_iv 都是16字节长,字节与C++和PHP版本匹配。对于PHP版本,它是一个由字节构成的二进制字符串(是的,我已经检查过这些是相同的)。

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

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

    我正在使用cfb模式,因为我想最小化结果加密数据的长度。填充将引入的几个字节在这个应用程序中很重要。

    我需要能够在C++中进行加密/解密,但只能在PHP中进行加密。对于我的应用程序来说,AES无疑是杀伤力过大——我最起码需要的是“对字节进行良好的加扰”,这样数据中单个字节的功能就不明显了。

    3 回复  |  直到 8 年前
        1
  •  4
  •   DrPerdix    14 年前

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

    对我来说,解决办法就是像你一样使用NOFB。根据 PHP mcrypt library reference MCRYPT_MODE_NOFB 强制反馈链等于算法的块大小,在本例中,AES128(Rijndael)的128位块/反馈与 manpage 对于mcrypt模块,说明nofb。这是很好的,因为我所发现的,nofb反馈和块大小是同步的。因此,nofb中的mcrypt和opensl现在都是针对aes128的128位key/iv/block/feedback大小,并且一切正常。

    至于报告256bit keysizes(32字节)的php,返回当前密码算法密钥大小的函数实际上返回最大密钥大小,文档中没有明确说明。我知道这一点是因为我的小类一直在各种项目中使用,它与OpenSSL以及CBC或NOFB中的任何其他AES库完美结合。如果mcrypt在我的128位(16个字符)密钥中再加上一个128位的空字符串,或者其他什么东西,无论如何技术上都不正确,那么情况就不是这样了。

    不是一个很好的答案,但我得到的最好的答案是几年前我对密码学的一次非常业余的探索。

        2
  •  2
  •   user437265    14 年前

    查看phpseclib:

    http://phpseclib.sourceforge.net/

    可以将键大小和块大小设置为所需的任何值。

    例如,$aes->setkeylength(128)或$aes->setkeylength(256);

        3
  •  1
  •   Community CDub    8 年前

    我有这个问题-几点。默认情况下,php-rijndael模式将反馈循环设置为8bits-to-be-aes需要与iv/key的长度相同。

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

    有关编写兼容aes-cfb-128的php的完整详细信息,请参阅此安全堆栈交换问题: aes cfb 128 decryption /encryption problem between Erlang and PHP . 短的是(来自汤姆·利克):

    …对于cfb和ofb(它们彼此不同,不能互换使用),您必须担心“反馈长度”,这在不同的加密库中不一定以高清晰度记录。加密和解密必须使用相同的反馈长度进行互操作。

    推荐文章