Reputation: 585
AES Encryption in PHP and ColdFusion9 is producing different results. Could somebody please help me?
The below PHP Code
$key = "12345678123456781234567812345678";
$iv = "1234567812345678";
$data = "This is a plain string.";
echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
gives me G+tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY=
While the below ColdFusion Code
<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) />
gives me KLt55n5/T3ee6xVq9VGFbyCacJznkHEqC/RDRhL+4nw=
Any idea where I am wrong? Thanks in advance.
Upvotes: 2
Views: 1548
Reputation: 28873
I know this is an old thread, but a similar question came up recently.
While not supported natively, it turns out there is a way to produce null padding in CF. This answer by Artjom B. agrees it may be simpler to adjust the padding in PHP, but points out you could achieve the same result padding the plain text with 0x00, to a multiple of the algorithm's block size and using the "NoPadding" scheme.
Producing null characters in CF is a little tricky, but can be done using URLDecode("%00"). Since encrypt() always treats input as UTF-8 encoded, you can also use charsetEncode() to create a null character from a single element byte array, ie charsetEncode( javacast("byte[]", [0] ), "utf-8")
.
Not highly tested, but something like this should produce the same result in CF10:
Code:
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);
Result:
G+tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY=
Function:
/*
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;
}
Upvotes: 0
Reputation: 865
Unfortunately there is a slight incompatibility between the ColdFusion and PHP implementations regarding the plaintext padding style used. AES requires a plaintext block size divisible by 128. To achieve this, PHP will pad the plaintext input with NULL characters to get the proper block size. ColdFusion can use a variety of padding techniques that are supported by Java. Unfortunately, ColdFusion nor Java support a NULL padding schema which makes interoperability more difficult. ColdFusion's string handling does not support NULL characters, so you will need to implement a PKCS5Padding schema within PHP instead to get them to inter-operate properly.
Also, as mentioned in the comments, ColdFusion will expect the key to be base64 encoded, so you'd need the key setting to look like:
<cfset theKey = toBase64("12345678123456781234567812345678") />
Further, Java by default (and ColdFusion by extension) only supports key sizes up to 128 bits. Here you're using a 256 bit key which would require the Java Unlimited Strength extension (for those trying to test the code and getting an illegal key size error).
The resulting PHP code looks like:
// Function from https://www.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));
The resulting ColdFusion code looks like:
<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>
Both output the same base64 encoded string:
G+tdEOfQTtVCQGxW3N5uzlu0mGabRKNxuIdAXArQE80=
Upvotes: 6