The past while at work I’ve been working through some annoyingly overcomplicated encryption issues. The problem is not that Triple DES is all that complicated or annoying, it’s just that when you have 2 different technologies (one doing the encrypting and one doing the decrypting) at work; it can be frustrating to get anything accomplished.

Below you can see two function for encrypt string, using the 3DES with PCSK7 and ECB.

Here the C# code:

public string Encrypt(string toEncrypt […])
{
    byte[] keyArray;
    byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
    […]
    string key =...
    MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
    keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
    hashmd5.Clear();
    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    tdes.Key = keyArray;
    tdes.Mode = CipherMode.ECB;
    tdes.Padding = PaddingMode.PKCS7;
    ICryptoTransform cTransform = tdes.CreateEncryptor();
    byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0,toEncryptArray.Length);
    tdes.Clear();
    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

My problem was the key: I was using a short key. I got this issue because Triple DES’s key size is 168 bits (21 bytes), but MD5 generates hashes that are only 16 bytes (128 bits) long.

This means the key will have to extended to 168 bits so Triple DES can work. It turns out that this derivation from 128 bits to 168 bits works differently in C# than it does in PHP, so the key that’s effectively used is different, resulting in different encrypted data. To solve this, the magic line code is “$key .= substr($key,0,8);”, as you can see in the php code. If you use 168 bits long key, you don’t have to use this line.

And this is the corresponding PHP code:

function apiEncode($data)
{    
  //Pad for PKCS7
  $blockSize = mcrypt_get_block_size('tripledes', 'ecb');
  $len = strlen($data);
  $pad = $blockSize - ($len % $blockSize);
  $data .= str_repeat(chr($pad), $pad);

  $key = "....";
  $key = md5($key,TRUE);
  $key .= substr($key,0,8); //comment this if you use 168 bits long key
  //Encrypt data
  $encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb'); 
  return base64_encode($encData);
}

 $crypt = apiEncode("00010");     
    echo "CRYPT: $crypt";
Advertisements