0

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

  • 1
    So, you mean, if we look into the method `encryptData`, `res` is 30 bytes long and `enc` is 16 bytes long? That shouldn't be and I can't see how that is. – Artjom B. Aug 05 '17 at 20:46
  • encryptData reads from the inner (memorystream) of the same class, it skips 62 bytes (because this is the length of the header) then it reads the remaining bytes (in this case 30) and then encrypts them and returns the encrypted byte[] (in this case 16) – Christopher Sorrels Aug 05 '17 at 23:13
  • Well, that can't be so it is time to provide the data with binary data in hex so you and we can see what is happening. My bet is that the final block is not being output, since it is the final block padding will be added to it and the encryption function needs to know to it is the last block. Typically there is a final call, sometimes implicitly called by the streaming code. – zaph Aug 05 '17 at 23:39
  • Edited the original question to provide a minimal, complete and verifyable example. Included current output of said program as-well. Still resulting in byte[30] becoming byte[16] becoming byte[13] – Christopher Sorrels Aug 06 '17 at 00:32
  • The addition is not verifyable, it is missing is the key and IV. – zaph Aug 06 '17 at 01:09

1 Answers1

2

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));
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • My goodness I can't believe it was so simple and after you mentioned that a streamwriter is just a textwriter that is attempting to write a string but has only been given a byte[] totally freaking dawned on my why the string output was always System.Byte[] I dang near smacked my own head! This is my first time writing encryption like this so thank you so much! – Christopher Sorrels Aug 06 '17 at 02:51