弄清楚PHP的mcrypt创建的确切密钥

时间:2012-07-18 12:03:08

标签: php mcrypt rijndael

我正在维护的PHP应用程序使用带有Ecry_MODE加密的Rijndael_256和mcrypt。有趣的是,密钥不是256位长,而是只有160位。根据mcrypt_encrypt文档,密钥用\ 0填充,以获得所需的大小,如果它太小。

  

用于加密数据的密钥。如果它小于   所需的密钥大小,用'\ 0'填充。最好不要使用   键的ASCII字符串。

这似乎发生在line 1186 in mcrypt.c的开头附近,并在第1213行修改了密钥。

所以我们说$key = 'abcdefghijkm';太短了,但PHP的mcrypt实现确保在使用RIJNDAEL_256时它扩展到32个字符(或256位)。最终的关键是什么样的?

我问这个是因为正在构建另一个使用相同加密数据的应用程序,但是使用另一种语言。 Perl确切地说我正在使用Crypto::Rijndael。对于给定的示例密钥,为了能够再次解密数据,我必须向Crypto::Rijndael(或其他任何其他内容)提供的确切密钥是什么?

更新

使用Perl,我可以生成一个键,其中\ 0填充pack('a32', 'my secret key');(或Z32),length()将报告32,Crypt::Rijndael模块接受密钥。看看PHP的mcrypt的来源,这应该是生成的密钥(\ 0填充),但它根本不会接受它。

理论上,PHP pack('a32', 'my secret key');应该生成与PHP的mcrypt生成的相同的\ 0填充密钥,但事实并非如此。

我非常接近只用新密钥加密所有东西。这花费了太多时间。

2 个答案:

答案 0 :(得分:12)

问题不在于密钥的填充,而在于您使用的是两种不同的块大小。在PHP中,使用MCRYPT_RIJNDAEL_256使用的块大小为... 256位。但是,在使用Crypt::Rijndael的perl中,他们会注意到:

  

<强>块大小
  Rijndael的块大小是16字节(128位),尽管算法实际上支持任何块数,这是我们字节的任何倍数。然而, 128位是AES指定的块大小,所以我们支持

因此没有密钥可以在这些不同的算法之间进行转换。您可以在PHP中切换到128位:

<?
$key = "abcdefghijklmnopqrstuvwxyz";
$data = "Meet me at 11 o'clock behind the monument.";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_ECB, nil);
echo bin2hex($crypttext) . "\n";
// prints c613d1804f52f535cb4740242270b1bcbf85151ce4c874848fd1fc2add06e0cc2d26b6403feef4a8df18f7dd7f8ac67d
?>

哪个Perl可以使用Crypt :: Rijndael解密而没有问题:

use Crypt::Rijndael;
$key = "abcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0";
$crypttext = "c613d1804f52f535cb4740242270b1bcbf85151ce4c874848fd1fc2add06e0cc2d26b6403feef4a8df18f7dd7f8ac67d";
$cipher = Crypt::Rijndael->new($key, Crypt::Rijndael::MODE_ECB());
print $cipher->decrypt(pack('H*', $crypttext));
# prints "Meet me at 11 o'clock behind the monument."

或者您可以切换到支持更多块大小的其他Perl模块,例如Crypt::Rijndael_PP

# Same PHP code except using MCRYPT_RIJNDAEL_256
# prints f38469ec9deaadbbf49bb25fd7fc8b76462ebfbcf149a667306c8d1c033232322ee5b83fa87d49e4e927437647dbf7193e6d734242d583157b492347a2b1514c

的Perl:

use Crypt::Rijndael_PP ':all';
$key = "abcdefghijklmnopqrstuvwxyz\0\0\0\0\0\0";
$crypttext = "f38469ec9deaadbbf49bb25fd7fc8b76462ebfbcf149a667306c8d1c033232322ee5b83fa87d49e4e927437647dbf7193e6d734242d583157b492347a2b1514c";
print rijndael_decrypt(unpack('H*', $key), MODE_ECB, pack('H*', $crypttext), 256, 256);
# prints "Meet me at 11 o'clock behind the monument."

答案 1 :(得分:4)

'\ 0'表示NULL,它的十六进制值为00! 所以我测试了3个代码,他们返回了所有相同的内容:)

  1. 让mcrypt_encrypt执行'\ 0'填充
  2. 添加了PHP NULL值
  3. 添加了PHP转换的0十六进制值
  4. 代码:     

    function encryptThis($text,$key){
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
        return ($crypttext);
    }
    
    echo bin2hex(encryptThis("Meet me at 11 o'clock behind the monument.", "abcdefghijklmnopqrstuvwxyz"))."<br/>";
    
    echo bin2hex(encryptThis("Meet me at 11 o'clock behind the monument.", "abcdefghijklmnopqrstuvwxyz" . NULL . NULL . NULL . NULL . NULL . NULL))."<br/>";
    
    echo bin2hex(encryptThis("Meet me at 11 o'clock behind the monument.", "abcdefghijklmnopqrstuvwxyz" . hex2bin(0) . hex2bin(0) . hex2bin(0) . hex2bin(0) . hex2bin(0) . hex2bin(0)))."<br/>";
    
    ?>