in Development

Using the CryptoStream class

One of the main problems people faces when they try to encrypt / decrypt with .NET classes is that, after decrypt, the resulting string contains unexpected chars or “garbage” at the end.

Normally, you will think that there is a problem with the padding used by the algorithm. But even if it’s related, the problem comes out because of a common people does when using the CryptoStream class.

The next code reproduces the error.

   1: static void Main(string[] args)
   2: {
   3:     RijndaelManaged rijndael = new RijndaelManaged();
   4:  
   5:     ICryptoTransform encryptor = rijndael.CreateEncryptor();
   6:     ICryptoTransform decryptor = rijndael.CreateDecryptor();
   7:  
   8:     string original = "jose fco bonnin";
   9:     System.Console.WriteLine("Encrypted: " + original + "|");
  10:  
  11:     byte[] plainData = System.Text.Encoding.Default.GetBytes(original);
  12:     byte[] encryptedData;
  13:  
  14:  
  15:     using (MemoryStream memoryStream = new MemoryStream())
  16:     {
  17:         using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
  18:         {
  19:             cryptoStream.Write(plainData, 0, plainData.Length);
  20:             cryptoStream.FlushFinalBlock();
  21:         }
  22:  
  23:         encryptedData = memoryStream.ToArray();
  24:     }
  25:  
  26:     byte[] decrypted;
  27:     using (MemoryStream memoryStream = new MemoryStream(encryptedData))
  28:     {
  29:         using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
  30:         {
  31:             int length = encryptedData.Length;
  32:             decrypted = new byte[length];
  33:  
  34:             cryptoStream.Read(decrypted, 0, length);
  35:         }
  36:     }
  37:  
  38:     System.Console.WriteLine("Decrypted: " + System.Text.Encoding.Default.GetString(decrypted) + "|");
  39:  
  40:     Console.ReadKey();
  41: }

If you execute the code, you will see how the original string and the decrypted string are different. I’ve added the pipe char (“|”) at the end of the string to see it better.

The problem with he code above is that you create an array with the length of the encrypted data, which not necessarily will have the same size as the decrypted byte array. The code below shows you how you can implement the decryption properly. You could do it also by intializing the MemoryStream with the decrypted data and then read from the cryptoStream using a StreamReader.

   1: using (MemoryStream memoryStream = new MemoryStream())
   2: {
   3:     using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
   4:     {
   5:         cryptoStream.Write(encryptedData, 0, encryptedData.Length);
   6:  
   7:         cryptoStream.FlushFinalBlock();
   8:     }
   9:  
  10:     decrypted = memoryStream.ToArray();
  11: }

As you can see, we do the same as to encrypt the string. We create the CryptoStream using the CryptoStreamMode.Write instead of CryptoStreamMode.Read and we write to it, the only difference is that, of course, we use the decryptor instead of the encryptor.

If you do the changes to the first code you will find that both strings are now exactly the same.