Matt
Matt

Reputation: 321

Converting AES decryption from php to c#

I'm attempting to convert some working php code to c# in order to do aes decryption.

Working PHP code:

function convert_from_hex($h) {
    $r="";
    for ($i=0; $i<strlen($h); $i+=2) 
        if ((isset($h[$i])) && (isset($h[$i+1]))) 
            $r.=chr(hexdec($h[$i].$h[$i+1]));

    return $r;
}

function decryptAES($crypt_text, $key) {

    $crypt_text=convert_from_hex($crypt_text);                                              // convert from hex

    $iv = substr($crypt_text, 0, 16);                                                       // extract iv
    $crypt_text = substr($crypt_text, 16);                                                  // extract iv

    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');                 // decrypt
    @mcrypt_generic_init($td, $key, $iv);
    $package = @mdecrypt_generic($td, $crypt_text);

    mcrypt_generic_deinit($td);                                                             // close encryption
    mcrypt_module_close($td);

    $padqty=ord($package[strlen($package)-1]);                                              // remove padding

    return substr($package, 0, strlen($package)-$padqty);
}

Broken C# Code:

public string test()
        {
            string data = ConvertHex("149B56B7240DCFBE75B7B8B9452121B0E202A18286D4E8108C52DBB2149D820B980FFC7157470B9573AA660B2FAAB158E321023922191BCEA5D6E1376ABE6474");

            string iv = data.Substring(0, 16);
            string toDecrypt = data.Substring(16);

            return AESEncryption.DecryptString(Encoding.Default.GetBytes(toDecrypt), Encoding.ASCII.GetBytes("C728DF944B666652"), Encoding.Default.GetBytes(iv));
        }

static public string DecryptString(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments. 
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("Key");

            // Declare the string used to hold 
            // the decrypted text. 
            string plaintext = null;

            byte[] binaryDecryptedData;

            // Create an Aes object 
            // with the specified key and IV. 
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Mode = CipherMode.CBC;
                aesAlg.Padding = PaddingMode.PKCS7;
                aesAlg.KeySize = 128;
                aesAlg.BlockSize = 128;
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);


                // Create the streams used for decryption. 
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (MemoryStream srDecrypt = new MemoryStream())
                        {
                            var buffer = new byte[1024];
                            var read = csDecrypt.Read(buffer, 0, buffer.Length);
                            while (read > 0)
                            {
                                srDecrypt.Write(buffer, 0, read);
                                read = csDecrypt.Read(buffer, 0, buffer.Length);
                            }
                            csDecrypt.Flush();
                            binaryDecryptedData = srDecrypt.ToArray();
                        }
                    }
                }

            }

            StringBuilder sb = new StringBuilder();
            foreach (byte b in binaryDecryptedData)
                sb.Append((char)b);
            plaintext = sb.ToString();

            return plaintext;
        }

        public string ConvertHex(String hexString)
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < hexString.Length; i += 2)
            {
                string hs = hexString.Substring(i, 2);

                sb.Append((char)Convert.ToUInt32(hs, 16));
            }

            return sb.ToString();
        }

The correct output of the PHP code is: Fail (1) Not a valid Request or Command.

The output of the C# code is: ²H,-§±uH¤¥±BÃrY¡|¡JJѾà`ªx"äommand

I'm guessing that I have some sort of encoding issue, although I've tried many different options without success. Both code snippets are running on a windows box, so I believe the default encoding is windows-1252.

Any suggestions would be appreciated.

Replacement for ConvertHex which fixed my issues (thanks to owlstead's help)

public static byte[] StringToByteArray(string hex)
{
    return Enumerable.Range(0, hex.Length)
                     .Where(x => x % 2 == 0)
                     .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                     .ToArray();
}

Upvotes: 0

Views: 165

Answers (1)

Maarten Bodewes
Maarten Bodewes

Reputation: 93948

You are using the first 16 bytes of string data instead of 16 bytes of binary data. This is what is causing the main issue. You need first to convert hex to bytes and then strip off the first 16 bytes to use as IV. Your ConvertHex method (not shown) is broken, it should return a byte array. The fact that your decrypted plaintext does end correctly with "ommand" clearly indicates a problem with the IV value.

Upvotes: 1

Related Questions