6

I am trying to create a decrypted File stream reader (DFSR) class by subclassing StreamReader so I can pass the filename with encrpyted info to its (DFSR) constructor and return with the streamReader that I can call upon ReadLine method of StreamReader.

I know how to do it as below, but I do not know how to refractor it into a class with StreamReader as parent class.

using (Rijndael rijAlg = Rijndael.Create())
{
    rijAlg.Key = DX_KEY_32;
    rijAlg.IV = DX_IV_16;

    // Create a decrytor to perform the stream transform.
    using (FileStream fs = File.Open("test.crypt", FileMode.Open))
    {
        using (CryptoStream cs = new CryptoStream(fs, rijAlg.CreateDecryptor(), CryptoStreamMode.Read))
        {
            using (StreamReader sr = new StreamReader(cs))
            {
                string line;
                // Read and display lines from the file until the end of  
                // the file is reached. 
                while ((line = sr.ReadLine()) != null)
                {
                    Console.WriteLine(line);
                }
            }

        }
    }

}
Christian Ternus
  • 8,406
  • 24
  • 39
Irene Lee
  • 101
  • 3
  • 1
    That would be a misuse of inheritance. What you should do is to just use the regular StreamReader, but properly initialized to use a CryptoStream. Basically, just like your code is structured right now. You can put all of that into a helper method. Inheritance adds no value here. If you insist on inheriting from something, inherit from TextReader and wrap a properly initialized StreamReader. – usr Oct 29 '13 at 16:14
  • Agree with @usr that you should be using System.Security.Cryptography.CryptoStream as it already inherits from System.IO.Stream. – Jamie Clayton Jan 04 '14 at 23:54

1 Answers1

0

You can use a static method from the constructor to generate the crypto stream similar to the following:

public class EncryptingFileStream : System.IO.StreamReader
{

    public EncryptingFileStream(string fileName, byte[] key, byte[] IV)
        : base(GenerateCryptoStream(fileName, key, IV))
    {
    }

    private static System.IO.Stream GenerateCryptoStream(string fileName, byte[] key, byte[] IV)
    {

        using (System.Security.Cryptography.Rijndael rijAlg = System.Security.Cryptography.Rijndael.Create())
        {
            rijAlg.Key = key;
            rijAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            using (System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.Open))
            {
                return new System.Security.Cryptography.CryptoStream(fs, rijAlg.CreateDecryptor(), System.Security.Cryptography.CryptoStreamMode.Read);
            }
        }
    }
}

To use this class:

        using (EncryptingFileStream fs = new EncryptingFileStream("test.crypt", DX_KEY_32, DX_IV_16))
        {
            string line;
            // Read and display lines from the file until the end of  
            // the file is reached. 
            while ((line = fs.ReadLine()) != null)
            {
                Console.WriteLine(line);
            }
        }
competent_tech
  • 44,465
  • 11
  • 90
  • 113
  • The `using` statement is closing the file stream. It needs to remain open for the lifetime of the reader. – Mike Zboray Jul 04 '13 at 19:19
  • It make sense to remove 'using', Does that mean we will have to declare 'rijAlg' and 'fs' statics. If I make 'fs' static, does that mean all instance of this class is restricted to a single file called 'filename' – Irene Lee Jul 04 '13 at 20:46
  • @IreneLee: the only thing that needs to be static is the method itself. Any parameters passed to the method would be instance, non-static values, so you can call it with whatever file names you like. – competent_tech Jul 04 '13 at 20:54
  • @IreneLee: I updated the answer to show how the class would be used. – competent_tech Jul 04 '13 at 20:58
  • How do I destroy CryptoStream instance in my destructor. Or do I need to do that? – Irene Lee Jul 04 '13 at 21:20
  • @IreneLee: you shouldn't need to do that, but if you do, you can get at it using the BaseStream property of the EncryptingFileStream. – competent_tech Jul 04 '13 at 21:22
  • I try to copy the above code and test it. I got the problem - 'Can not access the closed file' using (EncryptingFileStream wr = new EncryptingFileStream("test2.crypt")) { for (int i = 0; i < 10; i++) { wr.WriteLine("The Y number is Y" + i.ToString()); } } – Irene Lee Jul 04 '13 at 23:26