Decrypting in PHP a string encoded 3DES with C#

4.4k Views Asked by At

I have to decrypt in PHP a string encoded with this C# class (it's here)

using System;
using System.Security.Cryptography;
using System.Text;

public static class Encryption
{
   public static string Encrypt(string input, string key)
   {
      byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input);
      TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
      tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
      tripleDES.Mode = CipherMode.ECB;
      tripleDES.Padding = PaddingMode.PKCS7;
      ICryptoTransform cTransform = tripleDES.CreateEncryptor();
      byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
      tripleDES.Clear();
      return Convert.ToBase64String(resultArray, 0, resultArray.Length);
   }

   public static string Decrypt(string input, string key)
   {
      byte[] inputArray = Convert.FromBase64String(input);
      TripleDESCryptoServiceProvider tripleDES = new TripleDESCryptoServiceProvider();
      tripleDES.Key = UTF8Encoding.UTF8.GetBytes(key);
      tripleDES.Mode = CipherMode.ECB;
      tripleDES.Padding = PaddingMode.PKCS7;
      ICryptoTransform cTransform = tripleDES.CreateDecryptor();
      byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
      tripleDES.Clear();
      return UTF8Encoding.UTF8.GetString(resultArray);
   }
}

I've tried different examples found around on the web, but nothing seems to work. I think that the first problems comes with the $iv parameter in php mcrypt_generic_init and then another problem comes with padding that is missing in php functions. Can you please help me to convert the c# Decrypt function above in PHP? Thank you.

2

There are 2 best solutions below

1
On

Because the IV does not matter in ECB mode, we can ignore it. However, mcrypt isn't very lenient. We still need to provide an IV, even if it's fake.

// We'll be encrypting this data
    $key = 'password';
    $data = 'The quick brown fox jumped over the lazy dogs.';
    $encrypted = null;
    
// 3des in ECB mode
    $m = mcrypt_module_open(MCRYPT_3DES, null, MCRYPT_MODE_ECB, null);
// Our IV will be enough NUL bytes to satisfy mcrypt.
    $fake_iv = str_repeat(chr(0), mcrypt_enc_get_iv_size($m));
    mcrypt_generic_init($m, $key, $fake_iv);
    $encrypted = mcrypt_generic($m, $data);
// "s/6HOXpVyMyFdSPYUgIgneMRY0o3Kubkwc++hSg9kC4Sw0TWsNTqzrhXY3z4PH9w"
    echo base64_encode($encrypted), "\n";
    unset($m);

// And now, in reverse!
    $n = mcrypt_module_open(MCRYPT_3DES, null, MCRYPT_MODE_ECB, null);
// Another fake IV
    $fake_iv = str_repeat(chr(0), mcrypt_enc_get_iv_size($n));
    mcrypt_generic_init($n, $key, $fake_iv);
    $original = mdecrypt_generic($n, $encrypted);
// string(48) "The quick brown fox jumped over the lazy dogs."
    var_dump($original);

Again, you'll only want to do this if you stick with ECB mode. ECB mode can be pretty awful. You might want to review the Wikipedia article on block cipher modes for more information.

The only thing not handled here is the padding. mcrypt doesn't let you pick the padding method, and does something different depending on the cipher. Generally, it does not add any padding at all.

If your padding method of choice uses NUL bytes, you'll need to pre-pad the data yourself to ensure interoperability. You can use mcrypt_get_block_size and str_pad with the STR_PAD_RIGHT option to do this.

Likewise, you might need to trim NUL bytes off of the right after you decrypt. The second parameter to trim will help.

0
On

Even I tried today code for both PHP and C#

<?php
$key64 = "YOUR_KEY";
$iv64 = "YOUR_IV";


$keybytes = base64_decode($key64);
$ivbytes = base64_decode($iv64);

$text = ("4111111111111111");

// Padding the text
$padding = strlen($text)%8;
for($i=$padding; $i<8; $i++){
   $text .= chr(8-$padding);
}

$decryptRaw = mcrypt_encrypt(MCRYPT_3DES, $keybytes, $text, MCRYPT_MODE_CBC, $ivbytes);
$encoded = base64_encode($decryptRaw);

print "$encoded<br/>";
$encryptedString64 = $encoded;
$decryptbytes = base64_decode($encryptedString64);

$decryptRaw = mcrypt_decrypt(MCRYPT_3DES, $keybytes, $decryptbytes, MCRYPT_MODE_CBC, $ivbytes);
$decryptString=trim($decryptRaw,"\x00..\x1F");
print "$decryptString<br/>";

?>

C#

private string Decrypt(string encryptedValue)
{
    SymmetricAlgorithm tripleDESKey = SymmetricAlgorithm.Create("TripleDES") ;
    tripleDESKey.Key = Convert.FromBase64String("YOUR_KEY");
    tripleDESKey.IV = Convert.FromBase64String("YOUR_IV") ;

    MemoryStream encryptedStream = new MemoryStream();
    encryptedStream.Write(Convert.FromBase64String(encryptedValue), 0,
    Convert.FromBase64String(encryptedValue).Length);
    encryptedStream.Position = 0;
    CryptoStream cs = new CryptoStream(encryptedStream,
    tripleDESKey.CreateDecryptor(), CryptoStreamMode.Read);
    MemoryStream decryptedStream = new MemoryStream();

    byte[] buf = new byte[2049];
    int bytesRead = 0;
    bytesRead = cs.Read(buf, 0, buf.Length);
    while ((bytesRead > 0))
    {
        decryptedStream.Write(buf, 0, bytesRead);
        bytesRead = cs.Read(buf, 0, buf.Length);
    }
    return Encoding.ASCII.GetString(decryptedStream.ToArray());
}
private string Encrypt(string encrypt)
{
    SymmetricAlgorithm sa = SymmetricAlgorithm.Create("TripleDES") ;
    sa.Key = Convert.FromBase64String("YOUR_KEY");
    sa.IV = Convert.FromBase64String("YOUR_IV") ;
    byte[] inputByteArray = Encoding.ASCII.GetBytes(encrypt);
    MemoryStream mS = new MemoryStream();
    ICryptoTransform trans = sa.CreateEncryptor();
    byte[] buf = new byte[2049];
    CryptoStream cs = new CryptoStream(mS, trans, CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    return Convert.ToBase64String(mS.ToArray());
}