I've spent a couple hours now trying to figure this out, but I just can't get it to work. I've got a C# encryption routine that I need to match in php. I can't change the C# version, that's not an option (3rd party is firm on this).
Here's the C# code:
//In C#
// Console.WriteLine(ApiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl"));
// Results in:
// XvHbR/CsLTo=
public static string ApiEncode(string data, string secret)
{
byte[] clear;
var encoding = new UTF8Encoding();
var md5 = new MD5CryptoServiceProvider();
byte[] key = md5.ComputeHash(encoding.GetBytes(secret));
TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
des.Key = key;
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
byte[] input = encoding.GetBytes(data);
try { clear = des.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); }
finally
{
des.Clear();
md5.Clear();
}
return Convert.ToBase64String(clear);
}
Here's the best of what I've come up with in PHP:
//In PHP
// echo apiEncode("testing", "56dsfkj3kj23asdf83kseegflkj43458afdl");
// Results in:
// 5aqvY6q1T54=
function apiEncode($data, $secret)
{
//Generate a key from a hash
$key = md5(utf8_encode($secret), true);
//Create init vector
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_3DES, MCRYPT_MODE_ecb), MCRYPT_RAND);
//Pad for PKCS7
$blockSize = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($data);
$pad = $blockSize - ($len % $blockSize);
$data .= str_repeat(chr($pad), $pad);
//Encrypt data
$encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb'); //, $iv);
return base64_encode($encData);
}
To the best of my knowledge, I'm handling the PKCS7 padding properly on the PHP side. I'm not sure what else to try.
One thing to note, the C# is happening on windows, and the PHP on linux, not sure that should make a difference.
It appears the C# version does not set the IV. This could be an issue if you dont know what it is because msdn says:It looks like in the PHP version, you are using an IV. You could try not supplying the IV and hope the C# version also uses zeros.
Edit: Looks like for ECB, the IV is ignored.
You might also need to encoding the key like in the C# version using utf8-encode
Take a look at encoding.getBytes, you need the secret key Bytes from UTF8...
The padding length in your PHP version is based on the length of the password. This is incorrect. It should be based on the length of your message instead.
Try replacing
strlen($password)
withstrlen($data)
.The second problem is that the
mcrypt
library requires 24-byte keys. Triple DES applies regular DES three times, so you can call the 8-byte key used in each round of DES K1, K2, and K3. There are different ways to choose these keys. The most secure is to choose three distinct keys. Another way is to set K3 equal to K1. The least secure method (equivalent to DES) is to make K1 = K2 = K3.Most libraries are "smart" enough to interpret a 16-byte 3DES key as the second option above: K3 = K1. The .NET implementation is doing this for you, but the
mcrypt
library is not; instead, it's setting K3 = 0. You'll need to fix this yourself, and passmcrypt
a 24-byte key.After computing the MD5 hash, take the first 8 bytes of
$key
, and append them to the end of$key
, so that you have a 24-byte value to pass tomcrypt_encrypt()
.I found a solution, check this link, may help you. http://sanity-free.com/131/triple_des_between_php_and_csharp.html
And here is the decrypt function just in case: