Click here to Skip to main content
11,930,069 members (50,351 online)
Click here to Skip to main content
Add your own
alternative version


34 bookmarked

Password Protected Stream Using Decorator Pattern

, 9 Jan 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Builds a password protected stream on top of System.IO.Stream


This article explains how to build a Password Protected Stream on top of System.IO.Stream using decorator pattern. The stream can then be used as a normal stream, with slight changes in usage.


This work is just a part of my exercise that I was doing while reading the book titled 'C# 3.0 Design Patterns' by 'Judith Bishop'. It is an exercise of the section 'Decorator Patterns'. I opted to make it a bit complex and more functional rather than just a simple one for the sake of an exercise.

Using the Code

The code has four logical parts:

  1. The PasswordProtectedStream class that extends System.IO.Stream and overrides several required properties of the stream class. The main points of interest are how I have overridden the read and write methods of Stream.
  2. The 'DataEnvelop' class that is marked as 'Serializable' and it is the actual place holder for the data. This class is serialized to a class file using 'BinaryFormatter'. To keep the code simpler, I have saved the data as plain text otherwise for a more real world scenario, encryption can be applied or another stream can be extended as 'EncryptedStream' using the same 'Decorator Pattern' technique.
  3. A delegate 'ReadCompleteHandler' and a corresponding event 'On_ReadComplete'. This event passes the data to the client application after verifying the password. I couldn't make the data available directly from the read method as the data to be read was more in length than the actual data (because of serialization). So this technique is used. However, I would request the readers if anyone can help me erase the delegate and make the data available in the buffer directly by resetting the position and length of data to be read.
  4. A class 'ReadCompleteEventArgs' that is a parameter to the event 'On_ReadComplete' and passes the read status and data to the client application.

The whole code works according to the flow below:

  1. You create an instance of PasswordProtectedStream with two arguments: A base stream and a password.
  2. You put this stream into a StreamReader or StreamWriter.
  3. If you put it in StreamWriter, it will call the overridden 'Write' method of the PasswordProtectedStream. This method will create an instance of a seriliazable object of the class 'DataEnvelop' and put the password in that object along with data and write it on the actual stream.
  4. If you put it in StreamReader, the overridden 'Read' method is called for PasswordProtectedStream. It works slightly different than the usual way of how streams read. It will read all the bytes(including the headers also for the serialized object DataEnvelop), check the password and it is correct, will pass the data to the 'On_ReadComplete' event for processing by the client application. This is done using 'ReadCompleteEventArgs' class. Else if the password is wrong, no data is passed to the event and only failed status is reported so that it can be caught in the client application. The status is marked by an enum named 'Status'

Shortcomings: Since this is the first version, so the code works fine on single reads and single writes. However it is likely to have problems on multiple reads and multiple writes. This issue can be resolved if anyone can suggest a way where I don't have to use delegates and events and can directly reset the buffer in the Read method of the stream. I tried it but it was looping forever due to some seeking and positioning problems and also due to the length of the buffer having a chunk of 1024 bytes. All suggestions would be most welcome.

The whole code is as below:

//extends the stream class
public class PasswordProtectedStream : Stream
    string password; //password for the stream
    Stream str; //the base stream
    bool eventRaised = false; //this is a kind of locking variable 
            //so that if read operations are called multiple times, 
            //the event (the description to be followed) doesn't 
            //get invoked multiple times
    public delegate void ReadCompleteHandler
        (object s, ReadCompleteEventArgs e); //delegate for event
    public event ReadCompleteHandler On_ReadComplete; // event that passes data 
                //and read status to the client application 
    public PasswordProtectedStream(Stream str, 
    string password) //set the base parameters
        : base()
        this.str = str;
        this.password = password;
    #region "Overridden Methods of Stream"
    public override void Write(byte[] buffer, 
        int offset, int count) //override the write method
        byte[] data = new byte[count];
        for (int i = offset, j = 0; j < count; i++, j++)
            data[j] = buffer[i]; //construct the actual data buffer
        DataEnvelop env = new DataEnvelop(data, password); //create an instance of 
                //our own custom serialized class (to be followed later)
        BinaryFormatter f = new BinaryFormatter();
        f.Serialize(str, env); //serialize the object
    public override int Read(byte[] buffer, int offset, int count) //override the 
                                //read method
        int r = str.Read(buffer, offset, count); //read all bytes from base stream
        byte[] newData = new byte[str.Length]; //construct buffer to hold 
                //actual data and not the default buffer otherwise the object 
                //won't be de-serialized properly due to padded empty bytes
        for (int i = 0; i < str.Length; i++)     //in respect to the actual 
                        //length of the base stream
            newData[i] = buffer[i];         //copy all non-empty bytes
        MemoryStream mstr = new MemoryStream(newData); //construct memory stream 
                        //for de-serialization
        BinaryFormatter f = new BinaryFormatter();
        DataEnvelop env = (DataEnvelop)f.Deserialize(mstr);
        if (env.password == password)         //if password is matched
            if (On_ReadComplete != null && !eventRaised) //if event is not empty 
                    // and it's not been invoked earlier
                On_ReadComplete(this, new ReadCompleteEventArgs
                (ReadCompleteEventArgs.Status.SUCCESS,;             //bind successful read event
                eventRaised = true;         //mark it so that the event 
                                //is not invoked again on multiple reads
        else //if wrong password
            if (On_ReadComplete != null && !eventRaised) //if event is not empty 
                    //and it's not been invoked earlier
                On_ReadComplete(this, new ReadCompleteEventArgs
                    (ReadCompleteEventArgs.Status.FAILURE, null)); //bind 
                        //un-successful read event
                eventRaised = true;     //mark it so that the event is not invoked 
                    //again on multiple reads
        return r; //return actual number of bytes read and not the bytes 
                //of the actual data otherwise it will loop. 
        //This is the only reason why 
                //I had to pass the data to the event and couldn't 
        //directly process here. 
                //If anyone can suggest a way, I would be grateful.
    public override void Close()
    #region "Overridden Properties of Stream"
    public override void SetLength(long value)
    public override long Seek(long offset, SeekOrigin origin)
        return str.Seek(offset, origin);
    public override long Position
            return str.Position;
            str.Position = value;
    public override long Length
        get { return str.Length; }
    public override bool CanWrite
        get { return str.CanWrite; }
    public override void Flush()
    public override bool CanSeek
        get { return str.CanSeek; }
    public override bool CanRead
        get { return str.CanRead; }
    class DataEnvelop //private DataEnvelop Class that is serialized to the base stream 
    // with the password and the data bytes, it can be enhanced to encrypt the password
        public byte[] data { get; set; }
        public string password { get; set; }
        public DataEnvelop(byte[] data, string password)
   = data;
            this.password = password;
    public class ReadCompleteEventArgs : EventArgs     //arguments passed to the event 
                            //that passes data to the client
        byte[] data;             //actually data bytes
        Status status;             //status of the current output, 
                    //whether password is correct or not
        public enum Status { SUCCESS, FAILURE }     //if password is correct, 
                        //set as CORRECT else FAILURE
        public ReadCompleteEventArgs(Status status, byte[] data)
   = data;
            this.status = status;
        public byte[] Data { get { return data; } }
        public Status ReadStatus { get { return status; } }
//This is the client code. You can place two buttons named 
//button1 and button2 and place the following code in the forms code section

        private void button1_Click(object sender, EventArgs e)
            PasswordProtectedStream st = new PasswordProtectedStream
            (new FileStream("C:/pwdsample.txt", 
            FileMode.Create), "12345"); //create instance of our stream
            StreamWriter w = new StreamWriter(st);
            w.Write("Hye this is test"); //write some data

            MessageBox.Show("Data Written Successfully");

        private void button2_Click(object sender, EventArgs e)
            PasswordProtectedStream st = new PasswordProtectedStream(new FileStream
            ("C:/pwdsample.txt", FileMode.Open), "12345");     //create instance 
                            //of our stream, 
                //try changing a password here
            st.On_ReadComplete += new PasswordProtectedStream.ReadCompleteHandler
                (st_On_ReadComplete); //hook the read complete event
            StreamReader w = new StreamReader(st);
            w.ReadToEnd();         //read but don't display the data here, 
                    //else you won't get anything useful.
            //Readers are welcome if they can provide an implementation 
            //which enables us to read the data in usual manner, 
       //without the use of event

        void st_On_ReadComplete
    (object s, PasswordProtectedStream.ReadCompleteEventArgs e)
            if (e.ReadStatus == PasswordProtectedStream.ReadCompleteEventArgs.
                Status.FAILURE) //if wrong password
                MessageBox.Show("Wrong Password");
                MessageBox.Show("Data Read back: " + 
        Encoding.ASCII.GetString(e.Data)); //display data

Points of Interest

  1. Design Patterns
  2. I/O Streams in .NET


  • This is the first version of this sample application.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer (Senior)
India India
Hi Friends,

Myself, Sumit Mehta, an IT consultant and a software engineer in India.

My Skillset is based on the 7+ years of working experience in different heterogeneous technologies.

I have successfully designed, developed, and supported live web applications in .NET.

Besides this, I have also managed and administered Plesk control panel, having almost 100 domains and 50+ clients.

I have developed projects for a wide scale and range, i.e. from small scale clients to banking applications. Currently I work in .NET 4.0 and Visual Studio 2010. I also have hands on experience in PHP, Java and VB6. I am also heading towards iPhone development now.

You can get in touch with me at

You may also be interested in...

Comments and Discussions

GeneralMy vote of 2 Pin
Michael B. Hansen9-Jan-12 23:06
memberMichael B. Hansen9-Jan-12 23:06 
GeneralRe: My vote of 2 Pin
sumit46910-Jan-12 3:06
membersumit46910-Jan-12 3:06 
QuestionNice Pin
Navin Pandit9-Jan-12 18:25
memberNavin Pandit9-Jan-12 18:25 
AnswerRe: Nice Pin
sumit4699-Jan-12 18:39
membersumit4699-Jan-12 18:39 
GeneralMy vote of 5 Pin
Navin Pandit9-Jan-12 18:24
memberNavin Pandit9-Jan-12 18:24 
QuestionNot quite there yet... Pin
mark merrens9-Jan-12 7:16
membermark merrens9-Jan-12 7:16 
AnswerRe: Not quite there yet... Pin
sumit4699-Jan-12 18:40
membersumit4699-Jan-12 18:40 
AnswerRe: Not quite there yet... Pin
sumit4699-Jan-12 19:28
membersumit4699-Jan-12 19:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.151126.1 | Last Updated 10 Jan 2012
Article Copyright 2012 by sumit469
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid