1

因此,在 node.js 中,我有一个使用 aes128 且不通过 IV 的加密方案。一个例子如下

 var cipher = require('crypto').createCipher('aes128','password');
 cipher.update('test','utf8','base64')+cipher.final('base64');

哪个输出CjZ3R/tW8jiyLvg+/TE6bA==。问题是即使我尝试了一堆实现和变体,我也无法在 PHP 中重现这一点。

然后当我尝试通过 openssl 运行它时,我运行以下命令:

 echo "test" | openssl enc -e -aes128 -a -k password

它输出 U2FsdGVkX19Ccfv3SWvuzuZWeov9GDuwx1RMK2HWa/s= 也不匹配。我也尝试过使用-md所有可能的选项,但也不匹配(它们甚至不是相同的块大小)。在 PHP 中运行时,我尝试过对键/非散列进行散列,使用填充,在输入上使用计算的填充,其中填充字符是所需的填充字符数(在网上看到一些东西说这是 nodejs 使用的)。我已经尝试将 IV 设置为密码和空字节,但我仍然无法匹配。

这里有什么建议/想法吗?

编辑:

所以我刚刚在 php 中发现了函数 openssl_encrypt 并通过它尝试了相同的测试,并再次得到了完全不同的输出(这个现在与 node.js 采用完全相同的 args 并且据说它们都使用 openssl):

 openssl_encrypt ( "test" , 'aes128' , "password")

哪个输出(已经在base64中)JleA91MvYHdEdnj3KYHmog==至少现在在块数上匹配但仍然不是相同的密文。

我还应该提到,是的,将 IV 传递给 nodejs 是一种选择,可能会解决差异,但是 php 中的这个方案将替换 nodejs 中已经存在的旧方案,因此它必须能够解密已经创建的密文

4

1 回答 1

5

所以我想出了解决方案。浏览了node.js的c++源码后发现key和iv是使用openssl函数EVP_BytesToKey生成的。在搜索了这个函数的实现之后,我发现这个堆栈溢出帖子在 Cocoa 中加密数据,在 PHP 中解码(反之亦然),其中包含这个函数的一个版本。修改它并添加openssl版本用等于填充所需字节数的ascii字符填充数据的事实,我想出了以下完全匹配nodejs加密方案的函数:

function aes128Encrypt($key, $data) {
    $padding = 16 - (strlen($data) % 16);
    $data .= str_repeat(chr($padding), $padding);

    $keySize   = 16;
    $ivSize    = 16;

    $rawKey = $key;
    $genKeyData = '';
    do
    {
        $genKeyData = $genKeyData.md5( $genKeyData.$rawKey, true );
    } while( strlen( $genKeyData ) < ($keySize + $ivSize) );

    $generatedKey = substr( $genKeyData, 0, $keySize );
    $generatedIV  = substr( $genKeyData, $keySize, $ivSize );

    print($generatedIV);
    print($generatedKey);

    return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $generatedKey, $data, MCRYPT_MODE_CBC, $generatedIV);
}

与 node.js 函数完全匹配:

 function aes128Encrypt(key,data) {
      var cipher = require('crypto').createCipher('aes128',key);
      return cipher.update(data,'utf8','binary')+cipher.final('binary');
 }
于 2012-11-15T20:08:47.233 回答