3

I've been given the task of decrypting some data in C# that was originally encrypted using PHP. Below is the PHP code

$opts = OPENSSL_RAW_DATA;
$res = openssl_decrypt($raw, 'aes-256-ctr', $keyhash, $opts, base64_decode($iv));

$raw is a byte array with a length of 312, $keyhash is 32 bytes and $iv is 16 bytes.

My problem is when I duplicate this code in C# I receive the following CryptographicException - The input data is not a complete block.

Not being a crypto guy, I've tried many, many C# examples to try to get this to work, but pretty much always end up with the same error. This is one sample of the C# code I've tried.

static string DecryptStringFromBytes_Aes(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("IV");

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

        // Create an AesManaged object
        // with the specified key and IV.
        using (AesManaged aesAlg = new AesManaged())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;
            aesAlg.Padding = PaddingMode.PKCS7;

            // 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 (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }

        }

        return plaintext;

    }

I've implemented the code in PHP and it works fine. I've also checked all the input byte arrays and they all exactly the same for both PHP and C#. In desperation I even implemented this in Java and again it works no problem.

        SecretKeySpec keySpec = new SecretKeySpec(keyHash, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");


        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);  
        byte [] original = cipher.doFinal(encData);
        String plaintext = new String(original);

So what's up with the C# code and how can I make it work?

Thanks in advance.

TwiddleDumb
  • 51
  • 1
  • 5
  • My first guess would be the padding. If I remember correctly, there was a differecne in c# and java's implementations ... if I only could remember exactly ... , but I think it's worthwhile researching in that direction. – Fildor Mar 12 '18 at 12:38
  • 1
    CTR mode is not implemented in .NET. You can read this question for some inspiration: https://stackoverflow.com/q/6374437/5311735 – Evk Mar 12 '18 at 12:51
  • 1
    Possible duplicate of [Can I use AES in CTR mode in .NET?](https://stackoverflow.com/questions/6374437/can-i-use-aes-in-ctr-mode-in-net) – bartonjs Mar 12 '18 at 15:04
  • @Fildor CTR mode does **not** use padding. – zaph Mar 12 '18 at 17:13
  • @zaph exactly. That is the problem. – Fildor Mar 12 '18 at 18:12
  • @Fildor It is not a padding "differecne in c# and java's implementations" since CTR mode does not use padding in either/any. – zaph Mar 12 '18 at 18:27
  • @zaph yes. Exactly. See evk's comment. – Fildor Mar 13 '18 at 06:42

1 Answers1

2

OK. This is a duplicate question which has already been answered. I just missed the easy answer, which is here - Aes128CounterMode.cs. And this code will generate the correct result -

byte[] plainText = new byte[encData.Length];
Aes128CounterMode am = new Aes128CounterMode(iv); 
ICryptoTransform ict = am.CreateEncryptor(keyHash, null);
ict.TransformBlock(encData, 0, encData.Length, plainText, 0);
return Encoding.UTF8.GetString(plainText);
TwiddleDumb
  • 51
  • 1
  • 5