考虑以下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代码(适用于我的所有测试用例) - 我只是错过了正确的密钥字节集。
答案 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有很好的实现。