【问题标题】:PHP ColdFusion9 AES Encryption - Different resultsPHP ColdFusion9 AES 加密 - 不同的结果
【发布时间】:2016-01-08 11:16:57
【问题描述】:

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=

知道我哪里错了吗?提前致谢。

【问题讨论】:

  • 上面的 PHP 为我运行,但上面的 CF 抛出错误:“指定的密钥不是此加密的有效密钥:非法密钥大小”...是 真的 确切的 CF 代码?这是 CF9 企业版吗?
  • 非常感谢您的快速回复。我正在使用 ColdFusion9 试用版。
  • CF 期望 theKey 在 base64 中。将 theKey 转换为 base64 可以让您更接近,但并非一直如此。所以这可能是编码差异。你能用十六进制或base64打印出theKey/iv吗?

标签: php encryption coldfusion aes


【解决方案1】:

不幸的是,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 来让它们正确互操作。

此外,如 cmets 中所述,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=

【讨论】:

  • 非常感谢贾斯汀的详细回答。它解决了这个问题。
  • 是否可以使用 MCRYPT_RIJNDAEL_256 而不是 MCRYPT_RIJNDAEL_128 在 PHP 中加密数据,然后使用 AES 解密在 ColdFusion 或 Ruby 中解密。
  • 不是开箱即用的,没有。 AES 基于 Rijndael,但对块大小和密钥长度有更多限制。 AES 仅支持 128 位的明文块大小,因此如果您同时使用 Rijndael 和 AES,则必须在 Rijndael 端使用 128 位块大小才能使其兼容。 (回想一下,“MCRYPT_RIJNDAEL_128”中的“128”指定了块大小,而不是密钥长度。)
  • 话虽如此,ColdFusion 运行在上面并可以访问 Java,因此您可以使用基于 Java 的 Rijndael 库来获得更大的灵活性。这个 StackOverflow 答案 (stackoverflow.com/questions/5808107/…) 讨论了如何使用 Java 的 Bouncy Castle 库并在 ColdFusion 中使用它以获得更大的灵活性和与其他 Rijndael 密码的兼容性。
  • 啊,这就是填充方案。很好的解释贾斯汀! +1
【解决方案2】:

我知道这是一个旧线程,但最近出现了类似的问题。

虽然本机不支持,但事实证明有一种方法可以在 CF 中生成空填充。 This answer by Artjom B. 同意在 PHP 中调整填充可能更简单,但指出您可以使用 " 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;
}

【讨论】:

    猜你喜欢
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多