Reading from a cryptostream to the end of the stream

25,178

Solution 1

Well, there are several things going wrong here.

1. Your setting the size of the IV too large. If you have a key size of 256, the IV for Rijndael is 16 bytes. If you try to set the key with more bytes than that you will get an exception. IV size should be set to Block size / 8 see MSDN so the IV size you have is correct.

  1. You have a padding mode of None. Unless your data is exactly the correct block size, then you are going to have problems. You probably want to pick a padding mode.
  2. You typically need to call FlushFInalBlock when done writing to the crypto stream when you are encrypting to ensure all of the data is written to the stream.

I am posting some sample code using memory streams to show the encrypting and decrypting.

var tempData = "This is the text to encrypt. It's not much, but it's all there is.";

using (var rijCrypto = new RijndaelManaged())
{
    byte[] encryptedData;
    rijCrypto.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
    rijCrypto.KeySize = 256;

    using (var input = new MemoryStream(Encoding.Unicode.GetBytes(tempData)))
    using (var output = new MemoryStream())
    {
        var encryptor = rijCrypto.CreateEncryptor();

        using (var cryptStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write))
        {
            var buffer = new byte[1024];
            var read = input.Read(buffer, 0, buffer.Length);
            while (read > 0)
            {
                cryptStream.Write(buffer, 0, read);
                read = input.Read(buffer, 0, buffer.Length);
            }
            cryptStream.FlushFinalBlock();
            encryptedData = output.ToArray();
        }
    }

    using (var input = new MemoryStream(encryptedData))
    using (var output = new MemoryStream())
    {
        var decryptor = rijCrypto.CreateDecryptor();
        using (var cryptStream = new CryptoStream(input, decryptor, CryptoStreamMode.Read))
        {
            var buffer = new byte[1024];
            var read = cryptStream.Read(buffer, 0, buffer.Length);
            while (read > 0)
            {
                 output.Write(buffer, 0, read);
                 read = cryptStream.Read(buffer, 0, buffer.Length);
            }
            cryptStream.Flush();
            var result = Encoding.Unicode.GetString(output.ToArray());
        }
    }
}

Solution 2

Another way to read CryptoStream is to using CopyTo methord:

...

    using (var output = new MemoryStream())
    {
       cryptStream.CopyTo(output);
       return output.ToArray();
    }

...
Share:
25,178
David
Author by

David

Updated on February 06, 2020

Comments

  • David
    David over 4 years

    I'm having some trouble with the code below. I have a file in a temporary location which is in need of encryption, this function encrypts that data which is then stored at the "pathToSave" location.

    On inspection is does not seem to be handling the whole file properly - There are bits missing from my output and I suspect it has something to do with the while loop not running through the whole stream.

    As an aside, if I try and call CryptStrm.Close() after the while loop I receive an exception. This means that if I attempt to decrypt the file, I get a file already in use error!

    Tried all the usual and Ive looked on here at similar issues, any help would be great.

    Thanks

    public void EncryptFile(String tempPath, String pathToSave)
        {
            try
            {
                FileStream InputFile = new FileStream(tempPath, FileMode.Open, FileAccess.Read);
                FileStream OutputFile = new FileStream(pathToSave, FileMode.Create, FileAccess.Write);
    
                RijndaelManaged RijCrypto = new RijndaelManaged();
    
                //Key
                byte[] Key = new byte[32] { ... };
    
                //Initialisation Vector
                byte[] IV = new byte[32] { ... };
    
                RijCrypto.Padding = PaddingMode.None;
                RijCrypto.KeySize = 256;
                RijCrypto.BlockSize = 256;
                RijCrypto.Key = Key;
                RijCrypto.IV = IV;
    
                ICryptoTransform Encryptor = RijCrypto.CreateEncryptor(Key, IV);
    
                CryptoStream CryptStrm = new CryptoStream(OutputFile, Encryptor, CryptoStreamMode.Write);
    
                int data;
                while (-1 != (data = InputFile.ReadByte()))
                {
                    CryptStrm.WriteByte((byte)data);
                }
            }
            catch (Exception EncEx)
            {
                throw new Exception("Encoding Error: " + EncEx.Message);
            }
        }
    

    EDIT:

    I've made the assumption that my problem is with Encryption. My Decrypt might be the culprit

            public String DecryptFile(String encryptedFilePath)
        {
            FileStream InputFile = new FileStream(encryptedFilePath, FileMode.Open, FileAccess.Read);
    
            RijndaelManaged RijCrypto = new RijndaelManaged();
    
            //Key
            byte[] Key = new byte[32] { ... };
    
            //Initialisation Vector
            byte[] IV = new byte[32] { ... };
    
            RijCrypto.Padding = PaddingMode.None;
            RijCrypto.KeySize = 256;
            RijCrypto.BlockSize = 256;
            RijCrypto.Key = Key;
            RijCrypto.IV = IV;
    
            ICryptoTransform Decryptor = RijCrypto.CreateDecryptor(Key, IV);
    
            CryptoStream CryptStrm = new CryptoStream(InputFile, Decryptor, CryptoStreamMode.Read);
    
            String OutputFilePath = Path.GetTempPath() + "myfile.name";
            StreamWriter OutputFile = new StreamWriter(OutputFilePath);
    
            OutputFile.Write(new StreamReader(CryptStrm).ReadToEnd());
    
            CryptStrm.Close();
            OutputFile.Close();
    
            return OutputFilePath;
        }