12

我正在维护的 PHP 应用程序使用 Rijndael_256 和 EBC_MODE 加密和 mcrypt。有趣的是,密钥不是 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,我可以生成一个 \0 填充的密钥pack('a32', 'my secret key');(或Z32),length()将报告 32 并且Crypt::Rijndael模块接受该密钥。查看 PHP 的 mcrypt 的来源,这应该是正在生成的密钥(\0 填充),但它根本不会接受它。

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

我非常接近再次加密所有内容,但使用新密钥。这需要太多时间。

4

2 回答 2

12

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

blocksize
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

珀尔:

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."
于 2012-07-26T23:24:12.257 回答
4

'\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/>";

?>
于 2012-07-18T13:36:42.583 回答