7

I have a problem reproducing the same result generated in PHP vs Coldfusion.

In PHP encrypting this way:

<?php
    $key = "$224455@";
    $Valor = "TESTE";

    $base = chop(base64_encode(mcrypt_encrypt(MCRYPT_DES, $key, $Valor, MCRYPT_MODE_ECB)));     
?>

I have the result:

TzwRx5Bxoa0=

In Coldfusion did so:

<cfset Valor = "TESTE">
<cfset Key = "$224455@">
<cfset base = Encrypt(Valor,ToBase64(Key),"DES/ECB/PKCS5Padding","BASE64")>

Result:

qOQnhdxiIKs=

What isn't ColdFusion yielding the same value as PHP?

Thank you very much

Dan
  • 5,153
  • 4
  • 31
  • 42

2 Answers2

5

The problem is the padding. The mcrypt extension of PHP only uses ZeroPadding. It means that the plaintext is filled up with 0x00 bytes until the multiple of the block size is reached.

PKCS#5/PKCS#7 padding on the other hand fills it up with bytes that denote the number of bytes missing until the next multiple of the block size. The block size for DES is 8 bytes.

So you either need to pad the plaintext in php (See this drop-in code: A: How to add/remove PKCS7 padding from an AES encrypted string?) or use a different cipher in ColdFusion such as "DES/ECB/NoPadding". I recommend the former, because if you use NoPadding, the plaintext must already be a multiple of the block size.

$key = "$224455@";
$Valor = "TESTE";
function pkcs7pad($plaintext, $blocksize)
{
    $padsize = $blocksize - (strlen($plaintext) % $blocksize);
    return $plaintext . str_repeat(chr($padsize), $padsize);
}

$base = chop(base64_encode(mcrypt_encrypt(MCRYPT_DES, $key, pkcs7pad($Valor, 8), MCRYPT_MODE_ECB)));

Result:

qOQnhdxiIKs=

Don't forget to unpad the recovered plaintext if you are decrypting in PHP.

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • If not encode the key with the error Base64 An error occurred while trying to encrypt or decrypt your input string: '' Can not decode string "$224455@".. – Hilso Vasques Junior Mar 07 '15 at 18:28
  • I found the problem. Took me long enough. – Artjom B. Mar 07 '15 at 18:51
  • (Edit) @ArtjomB. - How are the plain text string and key decoded in php? CF [*always* treats the plain as UTF8 encoded and the key as base64](https://helpx.adobe.com/coldfusion/kb/strong-encryption-coldfusion-mx-7.html). So the asker will probably need to adjust the key depending on how the php function interprets the value. – Leigh Mar 07 '15 at 19:15
  • @Leigh PHP uses binary strings. So the encoding of the input depends on the php file encoding which is probably UTF-8. The output is explicitly Base64 encoded to match the ColdFusion encoding. I don't know ColdFusion at all to say why `ToBase64(Key)` is necessary and why it then produces the same output as the php code in my answer. – Artjom B. Mar 07 '15 at 19:20
  • *why ToBase64(Key) is necessary* I am not very familiar with php, but CF assumes the key is already base64 encoded (see link above). So it always decodes the key string as base64 to get the key bytes. Assuming that matches the binary php is getting, that is probably why it works. (Edit) Good find about the padding +1 – Leigh Mar 07 '15 at 19:27
  • @Leigh That's good to know. I tried to find a proper documentation for ColdFusion's Encrypt through my favorite search engine during research for this answer and failed miserably. – Artjom B. Mar 07 '15 at 19:29
  • @ArtjomB. - Yeah, the [regular docs on encrypt](https://wikidocs.adobe.com/wiki/display/coldfusionen/Encrypt) do not give enough detail IMO on the internal workings. The other link above is much more helpful IMO, but it took me a while to find it too. – Leigh Mar 07 '15 at 19:36
  • Artjom, worked really modifying the function in PHP, but the problem is I can not modify it. I could not play in CF. Unfortunately I can only modify the CF – Hilso Vasques Junior Mar 07 '15 at 19:41
  • @HilsoVasquesJunior I can't help you with that as I don't know anything about ColdFusion. – Artjom B. Mar 07 '15 at 19:44
  • @Leigh Maybe you can provide an answer where `Valor` is filled up with 0x00 (`\0`) to next multiple of 8 like PHP does it. If the plaintext is already a multiple of 8, it shouldn't be changed. – Artjom B. Mar 07 '15 at 19:46
  • @HilsoVasquesJunior - The problem is CF uses java's core encryption libraries internally, and based on what I have read [it may not support null padding](http://stackoverflow.com/questions/10301041/php-coldfusion9-aes-encryption-different-results/10309883#10309883) (Ignore the AES part). That is why the usual suggestion is to modify the PHP. – Leigh Mar 07 '15 at 19:51
  • Leigh managed to do in PHP, but I'll be trying in CF. If somebody else can help me, thank you, not ta not easy. – Hilso Vasques Junior Mar 07 '15 at 21:53
  • Guys, I think I found something that works from CF. [See my post below](http://stackoverflow.com/a/28923156/104223). – Leigh Mar 08 '15 at 04:41
5

(Too long for comments)

Artjom B. already provided the answer above. Artjom B. wrote

The problem is the padding. The mcrypt extension of PHP only uses ZeroPadding [...] you either need to pad the plaintext in php [...] or use a different cipher in ColdFusion such as "DES/ECB/NoPadding". I recommend the former, because if you use NoPadding, the plaintext must already be a multiple of the block size.

Unfortunately, it is difficult to produce a null character in CF. AFAIK, the only technique that works is to use URLDecode("%00"). If you cannot modify the PHP code as @Artjom B. suggested, you could try using the function below to pad the text in CF. Disclaimer: It is only lightly tested (CF10), but seemed to produce the same result as above.

Update: Since the CF encrypt() function always interprets the plain text input as a UTF-8 string, you can also use charsetEncode(bytes, "utf-8") to create a null character from a single element byte array, ie charsetEncode( javacast("byte[]", [0] ), "utf-8")


Example:

Valor = nullPad("TESTE", 8);
Key = "$224455@";
result = Encrypt(Valor, ToBase64(Key), "DES/ECB/NoPadding", "BASE64");
// Result: TzwRx5Bxoa0=
WriteDump( "Encrypted Text = "& Result ); 

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;
}
Community
  • 1
  • 1
Leigh
  • 28,765
  • 10
  • 55
  • 103
  • Personal, now worked perfectly in the initial test, I will do several tests later, but I believe the solution is the same. Thank you for the help and promptness. Helped me a lot. Thanks – Hilso Vasques Junior Mar 08 '15 at 14:08
  • ArtjomB. figured out the real issue, but glad the above helped :) – Leigh Mar 08 '15 at 18:31