Search code examples
c#encryptionrijndaelrijndaelmanaged

RijdaelManaged Encrypted byte[] different than Decrypted byte[] using same key/iv


Ok so I am attempting to code a byte[] before transmission and decode it after. I start out with "This is a super secret message" converted to byte[] and then encrypted by using RijdaelManaged. It goes from byte[30] (unencrypted) to byte[16] when encrypted, but when I attempt to unencrypt it, it becomes byte[13] and renders only "System.Byte[]" when translated into string with a string builder.

Edit: I already triple checked that the keyIV.Key and keyIV.IV are both matching when encrypting/decrypting

Calling Method:

    static void Main(string[] args)
    {
        KeyIV keyIV = Encryption.GenerateKeyIV();
        int keyLen = keyIV.Key.Length;
        int ivLen = keyIV.IV.Length;

        string plain = "This is a super secret message";

        byte[] plainArray = Encoding.ASCII.GetBytes(plain);

        byte[] encryptedArray = Encryption.EncryptBytes(ref plainArray, keyIV.Key, keyIV.IV);

        byte[] decryptedArray = Encryption.DecryptBytes(ref encryptedArray, keyIV.Key, keyIV.IV);

        Console.WriteLine("Original Message: {0}\n", plain);
        Console.WriteLine("Byte[{0}] Converted Message: {1}\n", plainArray.Length, BitConverter.ToString(plainArray));
        Console.WriteLine("Byte[{0}] Encrypted Message: {1}\n", encryptedArray.Length, BitConverter.ToString(encryptedArray));
        Console.WriteLine("Byte[{0}] Decrypted Message: {1}\n", decryptedArray.Length, BitConverter.ToString(decryptedArray));

        Console.ReadLine();
    }

Encrypt Method:

        public static byte[] EncryptBytes(ref byte[] input, byte[] key, byte[] iv)
    {
        if (input.Length > 0 && key != null && iv != null)
        {
            using (RijndaelManaged rm = new RijndaelManaged() { Key = key, IV = iv })
            {
                rm.Padding = PaddingMode.PKCS7;

                ICryptoTransform encryptor = rm.CreateEncryptor(rm.Key, rm.IV);

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(cs)) { sw.Write(input); }
                    }

                    return ms.ToArray();
                }
            }
        }

        return null;
    }

Decrypt Method:

        public static byte[] DecryptBytes(ref byte[] input, byte[] key, byte[] iv)
    {
        if (input != null && key != null && iv != null)
        {
            using (RijndaelManaged rm = new RijndaelManaged() { Key = key, IV = iv })
            {
                ICryptoTransform decryptor = rm.CreateDecryptor(rm.Key, rm.IV);

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { cs.Write(input, 0, input.Length); }

                    return ms.ToArray();
                }
            }
        }

        return null;
    }

Resulting Output:

Original Message: This is a super secret message

Byte[30] Converted Message: 54-68-69-73-20-69-73-20-61-20-73-75-70-65-72-20-73-65-63-72-65-74-20-6D-65-73-73-61-67-65

Byte[16] Encrypted Message: DD-85-D4-1E-E6-40-AA-44-DB-1A-17-33-A7-73-70-34

Byte[13] Decrypted Message: 53-79-73-74-65-6D-2E-42-79-74-65-5B-5D


Solution

  • The issue is that you are using a StreamWriter (which is a TextWriter) to write to your encryption stream. What that is doing is selecting the overload of .Write that takes an Object, and you are passing an array... When you do this, the TextWriter assumes that the object you are passing has some kind of smart .ToString() overload that's going to return the string value that you want to write to the target stream. In this case your array does not, so you are encrypting the value "System.Byte[]".

    As it turns out, you don't really want a StreamWriter. You just want to write the bytes of the array that your encrypt method is given to the CryptoStream. Fortunately streams have a built in Write method for just that. Try this in the body of your encrypt method instead:

                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                        {
                            cs.Write(input, 0, input.Length);
                            cs.Flush();
                        }
    
                        return ms.ToArray();
                    }
    

    I got a hint of what was going wrong when I compared the text output of your arrays, rather than the byte representations:

            Console.WriteLine("Original Message: {0}\n", plain);
            Console.WriteLine("Byte[{0}] Converted Message: {1}\n", plainArray.Length, Encoding.ASCII.GetString(plainArray));
            Console.WriteLine("Byte[{0}] Encrypted Message: {1}\n", encryptedArray.Length, Encoding.ASCII.GetString(encryptedArray));
            Console.WriteLine("Byte[{0}] Decrypted Message: {1}\n", decryptedArray.Length, Encoding.ASCII.GetString(decryptedArray));