Search code examples
c#encryptionstreamrijndaelmanaged

Using StreamWriter to write in a Stream (for large Stream encryption)


I am following the MSDN Example of Rijndael Encryption, only that I would like to encrypt and return a stream.

The following does not work.

It throws no exception but after stepping through the code, the return value has no data.

        public static Stream EncryptStream(Stream plainStream, byte[] Key, byte[] IV)
        {

            var encrypted = new MemoryStream()

            // Create an RijndaelManaged object 
            // with the specified key and IV. 
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;

                // Create a decrytor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

                // Create the streams used for encryption. 
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {

                            //Write all data to the stream.
                            swEncrypt.Write(plainStream);
                        }
                        msEncrypt.CopyTo(encrypted);
                    }
                }
            }
            return encrypted;


        }

I looked at the documentation for the Stream.Writer class, thinking that it has something to do with it not supporting writing to a Stream.

I noticed that there is an 'object' type parameter, so I am assuming it would work... Is that correct? If not, how do I do it?

I pass a FileStream to it, by the way. Stepping through the code, plainStream does contain data.


Solution

  • Here are some sample function to encrypt and decrypt from and to streams (replace the algo by the one you prefer):

    public static void Decrypt(Stream input, Stream output, byte[] key, byte[] iv)
    {
        using (SymmetricAlgorithm algo = SymmetricAlgorithm.Create()) // Creates the default implementation, which is RijndaelManaged. 
        {
            using (CryptoStream stream = new CryptoStream(input, algo.CreateDecryptor(key, iv), CryptoStreamMode.Read))
            {
                byte[] bytes = new byte[16];
                int read;
                do
                {
                    read = stream.Read(bytes, 0, bytes.Length);
                    output.Write(bytes, 0, read);
                }
                while (read > 0);
            }
        }
    }
    
    public static void Encrypt(Stream input, Stream output, byte[] key, byte[] iv)
    {
        using (SymmetricAlgorithm algo = SymmetricAlgorithm.Create()) //Creates the default implementation, which is RijndaelManaged. 
        {
            using (CryptoStream stream = new CryptoStream(output, algo.CreateEncryptor(key, iv), CryptoStreamMode.Write))
            {
                byte[] bytes = new byte[16];
                int read;
                do
                {
                    read = input.Read(bytes, 0, bytes.Length);
                    stream.Write(bytes, 0, read);
                }
                while (read > 0);
            }
        }
    }
    

    You can use them with any output stream. If you want to write to a large output stream, you can use that output stream directly (for example a FileStream or ASP.NET Response.OutputStream, etc.), you should not use an intermediary MemoryStream which will consume memory for no real purpose.

    That being said, if you really want to use a MemoryStream, you would do it like this:

    MemoryStream output = new MemoryStream();
    Encrypt(input, output, key, iv);
    output.Position = 0; // rewind the stream, so you can use it from the beginning