Link to home
Start Free TrialLog in
Avatar of DADITWebGroup
DADITWebGroupFlag for United States of America

asked on

encryption issues

Hello,
I'm working with a 3rd party vendor trying to send them an encrypted URL string with encode to preserve any spaces ect..  They are requiring a DESEDE encryption in ECB mode with PKCS5 padding using Base64 and the string should not be encoded again after the Base64 encoding.  

They have provided with me a username, password, and key they are expecting.  The code should be straight forward.  When put the code in, I get the following error:  

The key specified is not a valid key for this encryption: Wrong key algorithm, expected DESede.

Here is the code:

<cfset myKey = toBase64(BinaryDecode("xxxxxx[24bit key]xxxxxxx", "Base64"))>
<cfset myDate = dateformat(dateconvert( "local2Utc", now()), "YYYYMMDDHHMMSS")>
<cfset uid = "MyUserId">
<cfset pw = "MyPassword">
<cfset stmt = URLEncodedFormat("User_Id=#variables.uid#&User_Password=#Variables.pw#&User_TimeStamp=#variables.myDate#")>
<cfset encryptedUrl = encrypt(stmt, myKey, "DESEDE/ECB/PKCS5Padding", "Base64")>

I've taken out the actual username and password in this sample.  I've tried setting the the myKey to xxxxxx[24bit key]xxxxxxx (which is the key they are expecting), hashing the key, and taking out the ECB/PKCS5Padding.  

Any help would be greatly appreciated.  I'm not sure if I've overlooked anything, or exactly what I'm missing.  I'm not sure why CF keeps asking for the generateSecretKey method.  As soon as I do that, everything works great.   We are running CF 8.  Thank you in advance for your help.
Avatar of ahoffmann
ahoffmann
Flag of Germany image

I'm no CF expert, but I assume that your encrypt() expects the key in binary format while you pass it base64 encoded
Sorry this is a PHP example, but it shows the principles of what needs to be done.
<?php // RAY_encrypt_decrypt.php
error_reporting(E_ALL);

// MAN PAGE: http://us.php.net/manual/en/ref.mcrypt.php

class Encryption
{
    protected $key;
    protected $eot;
    protected $ivs;
    protected $iv;

    public function __construct()
    {
        // SET KEY, DELIMITER, INITIALIZATION VECTOR - MUST BE KNOWN TO BOTH PARTS OF THE ALGORITHM
        $this->key = 'quay';
        $this->eot = '___EOT';
        $this->ivs = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
        $this->iv  = mcrypt_create_iv($this->ivs);
    }

    public function encrypt($text)
    {
        // APPEND END OF TEXT DELIMITER
        $text .= $this->eot;

        // ENCRYPT THE DATA
        $data = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->key, $text, MCRYPT_MODE_ECB, $this->iv);

        // MAKE IT base64() STRING SAFE FOR STORAGE AND TRANSMISSION
        return base64_encode($data);
    }

    public function decrypt($text)
    {
        // DECODE THE DATA INTO THE BINARY ENCRYPTED STRING
        $text = base64_decode($text);

        // DECRYPT THE STRING
        $data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $this->key, $text, MCRYPT_MODE_ECB, $this->iv);

        // REMOVE END OF TEXT DELIMITER
        $data = explode($this->eot, $data);
        return $data[0];
    }
}

// INSTANTIATE THE CLASS
$c = new Encryption();

// INITIALIZE VARS FOR LATER USE IN THE HTML FORM
$encoded = '';
$decoded = '';

// IF ANYTHING WAS POSTED
if (!empty($_POST["clearstring"]))
{
    $encoded = $c->encrypt($_POST["clearstring"]);
    echo "<br/>{$_POST["clearstring"]} YIELDS ";
    var_dump($encoded);
}

if (!empty($_POST["cryptstring"]))
{
    $decoded = $c->decrypt($_POST["cryptstring"]);
    echo "<br/>{$_POST["cryptstring"]} YIELDS ";
    var_dump($decoded);
}

// END OF PHP - PUT UP THE FORM
?>
<form method="post">
<input name="clearstring" value="<?php echo $decoded; ?>" />
<input type="submit" value="ENCRYPT" />
<br/>
<input name="cryptstring" value="<?php echo $encoded; ?>" />
<input type="submit" value="DECRYPT" />
</form>

Open in new window

Everything inside the Encryption class is assumed to be unsigned binary data.  You only use base64 encoding to make the data into a string that is safe for transport over HTTP.   In my development I found that it was necessary to add an end-of-string delimiter to the original input strings.  The encode/decode process had a way of adding some shmutz to the end of the original string.
Avatar of DADITWebGroup

ASKER

Correct.  Their exact instructions are:  "Encrypt the Query String using DES3 and encode it using Base64 (Note that the string should NOT be URL-encoded again after the Base64 encoding.)  Then append the encrypted Query String to the URL."
Avatar of _agx_
I'm not sure why CF keeps asking for the generateSecretKey

That just means it doesn't see your key as valid for DESEDE. I noticed your key is shorter than what's returned by generateSecretKey.  Since CF only uses the 1st 24 bytes, try padding yours with 8 zeroes:

ie
<cfset myKey = "xxxxxx[24bit key]xxxxxxx"& "00000000">
<cfset encryptedUrl = encrypt(stmt, myKey, "DESEDE/ECB/PKCS5Padding", "Base64")>

<cfset myKey = toBase64(BinaryDecode("xxxxxx[24bit key]xxxxxxx", "Base64"))>

Fyi, that isn't needed if the key is in base64 to begin with.
Thank you.  I've tried the padding of the 0's to get me the 32 bytes.  The encryptions goes through the way I expect it too, but when the 3rd party goes to decrypt it, they are unable to decrypt it because of the padding of 0's.  The last <cfset> was the very last thing I tried because I was out of ideas.  

<cfset myKey = toBase64(BinaryDecode("xxxxxx[24bit key]xxxxxxx", "Base64"))>

I've even tried to give not have any padding on the DESEDE, which becomes different issues.  
<cfset encryptedUrl = encrypt(stmt, myKey, "DESEDE/ECB/nopadding", "Base64")>
They are unable to decrypt it because of the padding of 0's.


I believe you, but it shouldn't make a difference because the docs say CF only uses the 1st 24 bytes. Do you know what the other side is using -java, c#, php?

For grins, try padding it with the 1st 8 characters of the key instead of 0's. Test it with a very simple input like "abc"
I've requested that this question be deleted for the following reason:

Found my own solution and it was mandatory I delete it because it unknowingly contained sensitive data that I did not want referenced later.<br /><br />Thank you
What was the actual solution?
ASKER CERTIFIED SOLUTION
Avatar of DADITWebGroup
DADITWebGroup
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Close request can be canceled as there was resolution to our issue.
The Base64 around the key itself must be specified here because of the way Coldfusion is handling the encryption function I suspect, but am not 100% sure on that. I just know that it does not work if set in variable definition instead.

Weird, I've never experienced that one myself, but .. encryption's sensitive so that's entirely possible. Anyway, glad you found a solution .. and thanks for posting the complete details for the archives.
This is the only resolution that worked. (Supervisor had solution)