计算出PHP创建的确切密钥';s mcrypt


Figuring out the exact key created by PHP's mcrypt

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

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

这似乎发生在mcrypt.c中第1186行的开头,并在第1213行修改密钥。

假设我们有$key = 'abcdefghijkm';,它太短了,但PHP对mcrypt的实现确保了在使用RIJNDAEL_256时它可以扩展到32个字符(或256位)。最后一把钥匙会是什么样子?

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

更新

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

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

我很想再次加密所有内容,但要用一个新密钥。这花了太多时间。

问题不在于键的填充,而是使用了两种不同的块大小。在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."

'''0'表示NULL,十六进制值为00!所以我测试了3个代码,结果都是一样的:)

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

代码:

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/>";
?>