mcrypt_encrypt

时间:2015-06-09 21:44:15

标签: php encryption aes rijndael symmetric-key

考虑以下PHP代码:

<?php
$key = "1234567812345678";
$iv = "1234567812345678";
$data = "Test string";

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
                            $key,
                            $data,
                            MCRYPT_MODE_CBC,
                            $iv);

print "Encoded1: " . base64_encode($encrypted) . "\n";

$key = "12345678123456781234567812345678";

$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
                            $key,
                            $data,
                            MCRYPT_MODE_CBC,
                            $iv);

print "Encoded2: " . base64_encode($encrypted) . "\n";

运行时,会产生输出:

Encoded1: iz1qFlQJfs6Ycp+gcc2z4w==
Encoded2: n3D26h/m8CSH0CE+z6okkw==

请注意,我从PHP Java AES CBC Encryption Different Results

中窃取了第一部分代码

现在 - 问题在这里:

在第一种情况下,传入的密钥是一个16个字符的字符串。如果将每个单独的字符解释为8位数量,则会得到人们期望的128位密钥大小。实际上,我在上面引用的StackOverflow页面上的Java代码就是这样做的,并获得与PHP相同的结果。

在上面对mcrypt_encrypt的第二次调用中,我将密钥的长度加倍。 mcrypt_encrypt愉快地接受了这一点,但产生的加密输出与第一种情况不同。因此,显然,它认为这是一个不同的关键 - 它不会,例如只采用前128位并丢弃任何过去。

那么,mcrypt_encrypt如何处理输入密钥字符串以提出MCRYPT_RIJNDAEL_128算法所需的128位密钥?

如果它有任何区别,我特别感兴趣的情况是当我的第二个例子传入一个32个字符的字符串时 - 我必须创建一个匹配的解密例程(用Java),所以我需要弄清楚在这种情况下如何实际生成密钥。我引用的页面具有非常好的Java代码(适用于我的所有测试用例) - 我只是错过了正确的密钥字节集。

1 个答案:

答案 0 :(得分:3)

Rijndael算法有两个重要参数。有密钥大小(128位,192位和256位),然后有块大小(128位,192位和256位)位)。 128中的MCRYPT_RIJNDAEL_128指的是块大小。密钥大小是可变的。

当您将不同长度的密钥传递到MCrypt时,它会自动选择适当的密钥大小,因此您不能设置它。 MCRYPT_RIJNDAEL_128是AES(AES-128,AES-192,AES-256)。 <{1}}和MCRYPT_RIJNDAEL_192不再是AES。

如果Java代码产生了128位密钥的匹配结果,那么它也会产生256位密钥的匹配结果。

MCrypt有点奇怪。在PHP 5.6.0之前,它将占用任何密钥长度,而不仅仅是128位,192位或256位。密钥将填充0x00字节,直到下一个有效密钥长度。

由于Java不支持开箱即用的ZeroPadding,因此您应该使用适当的填充方案,例如PHP中的PKCS#5 / PKCS#7填充。 This answer有很好的实现。