PHP和ColdFusion9中的AES加密产生了不同的结果。有人可以帮帮我吗?
以下PHP代码
$key = "12345678123456781234567812345678";
$iv = "1234567812345678";
$data = "This is a plain string.";
echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
给我G + tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY =
以下ColdFusion代码
<cfset thePlainData = "This is a plain string." />
<cfset theKey = "12345678123456781234567812345678" />
<cfset theAlgorithm = "AES/CBC/PKCS5Padding" />
<cfset theEncoding = "base64" />
<cfset theIV = "1234567812345678" />
<cfset encryptedString = encrypt(thePlainData, theKey, theAlgorithm, theEncoding, theIV) />
给我KLt55n5 / T3ee6xVq9VGFbyCacJznkHEqC / RDRhL + 4nw =
知道我错了吗?提前谢谢。
答案 0 :(得分:6)
不幸的是,关于所使用的纯文本填充样式,ColdFusion和PHP实现之间存在轻微的不兼容性。 AES要求明文块大小可被128整除。为实现此目的,PHP will pad the plaintext input with NULL characters可获得正确的块大小。 ColdFusion可以使用各种padding techniques that are supported by Java。不幸的是,ColdFusion和Java支持NULL填充模式,这使得互操作性更加困难。 ColdFusion的字符串处理不支持NULL字符,因此您需要implement a PKCS5Padding schema within PHP来使它们正常运行。
另外,正如评论中所提到的,ColdFusion希望密钥是base64编码的,因此您需要将密钥设置看起来像:
<cfset theKey = toBase64("12345678123456781234567812345678") />
此外,默认情况下Java(扩展名为ColdFusion)仅支持最大128位的密钥大小。这里你使用的是一个256位的密钥,require the Java Unlimited Strength extension(对于那些试图测试代码并获得非法密钥大小错误的人)。
生成的PHP代码如下所示:
// Function from http://us3.php.net/manual/en/ref.mcrypt.php#69782
function pkcs5_pad ($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
$key = "12345678123456781234567812345678";
$iv = "1234567812345678";
// Pad data with PKCS #5 to prevent PHP from using NULL padding.
$data = pkcs5_pad("This is a plain string.", 16);
echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
生成的ColdFusion代码如下所示:
<cfset thePlainData = "This is a plain string." />
<cfset theKey = toBase64("12345678123456781234567812345678") />
<cfset theAlgorithm = "AES/CBC/PKCS5Padding" />
<cfset theEncoding = "base64" />
<cfset theIV = "1234567812345678" />
<cfset encryptedString = encrypt(thePlainData, theKey, theAlgorithm, theEncoding, theIV) />
<cfoutput>#encryptedString#</cfoutput>
两者都输出相同的base64编码字符串:
G+tdEOfQTtVCQGxW3N5uzlu0mGabRKNxuIdAXArQE80=
答案 1 :(得分:0)
我知道这是一个老话题,但最近出现了类似的问题。
虽然本身不支持,但事实证明有一种方法可以在CF中生成空填充。 This answer by Artjom B.同意在PHP中调整填充可能更简单,但指出您可以使用0x00将纯文本填充到algorithm's block size 和使用“NoPadding”方案。
在CF中生成空字符有点棘手,但可以完成using URLDecode("%00")。由于encrypt()始终将输入视为UTF-8编码,因此您还可以使用charsetEncode()从单个元素字节数组创建空字符,即charsetEncode( javacast("byte[]", [0] ), "utf-8")
。
没有经过高度测试,但是这样的事情应该在CF10中产生相同的结果:
<强>代码:强>
thePlainData = nullPad("This is a plain string.", 16);
// NB: JCE unlimited policy files required for 256 bit keys
theKey = toBase64("12345678123456781234567812345678");
theIV = "1234567812345678";
encryptedString = encrypt(thePlainData, theKey, "AES/CBC/NoPadding", "base64", theIV);
<强>结果:强>
G+tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY=
<强>功能:强>
/*
Pads a string, with null bytes, to a multiple of the given block size
@param plainText - string to pad
@param blockSize - pad string so it is a multiple of this size
@param encoding - charset encoding of text
*/
string function nullPad( string plainText, numeric blockSize, string encoding="UTF-8")
{
local.newText = arguments.plainText;
local.bytes = charsetDecode(arguments.plainText, arguments.encoding);
local.remain = arrayLen( local.bytes ) % arguments.blockSize;
if (local.remain neq 0)
{
local.padSize = arguments.blockSize - local.remain;
local.newText &= repeatString( urlDecode("%00"), local.padSize );
}
return local.newText;
}