< Composable & BufferedStream Streams | Main | SSLStream Class Server Example >

 


 

Chapter 2 Part 9:

Managed I/O - Streams, Readers, and Writers

 

 

What do we have in this chapter 2 Part 9?

  1. CryptoStream Class

  2. C++ CryptoStream Program Example

  3. C# CryptoStream Program Example

  4. VB .NET CryptoStream Program Example

 

 

 

Note: If you want to experience a complete C++ .NET/C++-CLI programming tutorial please jump to Visual C++ .NET programming tutorial.

 

CryptoStream Class

 

The CryptoStream class is another composable stream that enables an application to encrypt and decrypt data to and from another stream. This class is located in the System.Security.Cryptography namespace. To use this class effectively, you need to understand cryptography, which is beyond the scope of this book. However, we’ll take a moment here to explain how to encrypt data using a cryptographic algorithm. One book that might be helpful in fully understanding cryptography is Applied Cryptography: Protocols, Algorithms, and Source Code in C, Second Edition by Bruce Schneier (John Wiley & Sons, 1995).

In cryptography, two different techniques are used to encrypt and decrypt data:

 

  1. A symmetric and
  2. An asymmetric cryptography.

 

Symmetric methods use a secret key to encode and decode data. Asymmetric methods use a public key to encode data and a private key to decode data. Symmetric cryptography is one of the oldest forms of cryptography, so for our sample code, we’ll use the well-known symmetric algorithm Data Encryption Standard (DES). Many other algorithms are available in the .NET Framework to support both symmetric and asymmetric techniques. Table 2-3 describes the available cryptography algorithms.

 

Table 2-3: Available Cryptography Algorithms

 

Algorithm

Technique

Digital Signature Algorithm (DSA)

Asymmetric

RSA Security

Asymmetric

Data Encryption Standard (DES)

Symmetric

“Rivest’s Cipher” (RC2)

Symmetric

Rijndael

Symmetric

Triple Data Encryption Standard (TripleDES/3DES)

Symmetric

 

The following code fragment shows how to set up a CryptoStream that can write encrypted data to a FileStream using the DES algorithm. For simplicity, we made up a secret key that’s a combination of the variables DESKey and DESInitializationVector to show how stream encryption can be accomplished using the DES algorithm.

 

C#

 

// Let's create a private key that will be used to encrypt and decrypt

// the data stored in the file Jim.dat.

byte[ ] DESKey = { 200, 5, 78, 232, 9, 6, 0, 4 };

byte[ ] DESInitializationVector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

//

// Let's create a Symmetric crypto stream using the

// DES algorithm to encode all the bytes written to

// the file Jim.

CryptoStream MyStreamEncrypter = null;

// Let's create a Symmetric crypto stream using the DES algorithm to

// encode all the bytes written to the file Jim.

try

{

      Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, encrypting the file...");

      DES DESAlgorithm = new DESCryptoServiceProvider();

      MyStreamEncrypter = new CryptoStream(MyFileStream, DESAlgorithm.CreateEncryptor(DESKey, DESInitializationVector),

                        CryptoStreamMode.Write);

 }

 catch (Exception e)

 {

       MyFileStream.Close();

       throw new Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message);

}

finally

{

       // We are finished performing IO on the file. We need to close the file to release operating system resources related to the file.

       MyStreamDecrypter.Close();

 }

 

Visual Basic .NET

 

' Let's create a private key that will be used to encrypt and decrypt

' the data stored in the file Jim.dat.

 Dim DESKey() As Byte = {200, 5, 78, 232, 9, 6, 0, 4}

 Dim DESInitializationVector() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

 

' Let's create a Symmetric crypto stream using the DES algorithm to encode all the bytes written to the file Jim.dat.

Dim MyStreamEncrypter As CryptoStream = Nothing

 

Try

                Dim DESAlgorithm As DES

                Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream to encrypt a file")

                DESAlgorithm = New DESCryptoServiceProvider

                'Dim MyStreamEncrypter As CryptoStream

                MyStreamEncrypter = New CryptoStream(MyFileStream, DESAlgorithm.CreateEncryptor(DESKey, DESInitializationVector), _

                        CryptoStreamMode.Write)

            Catch e As Exception

                Throw New Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message)

Finally

            ' Let's close the crypto stream and file stream now that we are finished writing data.

            MyStreamEncrypter.Close()

        End Try

 

The CryptoStream class supports reading and writing data to the stream; however, you can’t perform both operations at the same time. During CryptoStream creation, you have to specify whether your stream will read or write data by using the CryptoStreamMode parameter. The CryptoStream class also does not support seeking, so you can’t change the Position property or call the Seek() method to read or write to another section of a stream.

The following is CyptoStreamSampleCS application example that demonstrates how to use a CryptoStream with a FileStream to encrypt data and send it to a file. You may want to try other cryptography schemes based on the same program example.

 

C++ CryptoStream Example

 

Create a new CLR console application project and you might want to use CryptoStreamSampleCP as the project and solution names.

 

C++ CryptoStream Example - CLR console application project creation

 

Add the following code.

 

// CryptoStreamSampleCP.cpp : main project file.

// <summary>

// This sample is designed to show how to use the composable stream CryptoStream

// to read and write encrypted data to a file. The sample uses the DES encryption

// standard to encrypt data.

// </summary>

 

#include "stdafx.h"

 

using namespace System;

using namespace System::IO;

using namespace System::Security::Cryptography;

 

// <summary>

// The main entry point for the application.

// </summary>

[STAThread]

int main(array<System::String ^> ^args)

{

    // Let's create a private key that will be used to encrypt and decrypt the data stored in the file hantu.dat.

    array< Byte >^ DESKey = gcnew array< Byte >{200, 5, 78, 232, 9, 6, 0, 4};

    array< Byte >^ DESInitializationVector = gcnew array< Byte >{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

    String^ FileName = "C:\\temp\\hantu.dat";

    CryptoStream^ MyStreamEncrypter = nullptr;

 

    try

    {

        // Let's create a file named hantu.dat in the current C:\Temp directory

        FileStream^ MyFileStream = nullptr;

        try

        {

             MyFileStream = gcnew FileStream(FileName, FileMode::Create, FileAccess::Write);

             Console::WriteLine("{0} file created/opened successfully", FileName);

        }

        catch (Exception^ e)

        {

            throw gcnew Exception("Failed to create/open filestream with error: " + e->Message);

        }

 

        // Let's create a Symmetric crypto stream using the DES algorithm to encode all the bytes written to the file hantu.

        try

        {

            Console::WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, encrypting {0}...", FileName);

            DES^ DESAlgorithm = gcnew DESCryptoServiceProvider();

            MyStreamEncrypter = gcnew CryptoStream(MyFileStream, DESAlgorithm->CreateEncryptor(DESKey, DESInitializationVector), CryptoStreamMode::Write);

        }

        catch (Exception^ e)

        {

            MyFileStream->Close();

            throw gcnew Exception("Failed to create DES Symmetric CryptoStream with error: " + e->Message);

        }

 

        // Let's write 10 bytes to our crypto stream. For simplicity

        // we will write an array of 10 bytes where each byte contains a numeric value 0 - 9.

        array< Byte >^ MyByteArray = gcnew array< Byte >(10);

        

         Console::WriteLine("Writing...");

         for (short i = 0; i < MyByteArray->Length; i++)

        {

            MyByteArray[i] = (Byte)i;

            Console::Write("{0}, ", MyByteArray[i]);

         }

             Console::WriteLine();

 

        try

        {

              MyStreamEncrypter->Write(MyByteArray, 0, MyByteArray->Length);

              Console::WriteLine("Writing 10 bytes to the crypto stream...");

        }

        catch (Exception^ e)

        {

            throw gcnew Exception("Write failed with error: " + e->Message);

        }

    }

    catch (Exception^ e)

    {

        Console::WriteLine(e->Message);

        return 0;

    }

    finally

    {

        // Let's close the crypto stream now that we are finished writing data.

        Console::WriteLine("Closing the encrypter stream...");

        MyStreamEncrypter->Close();

    }

    // Now let's open the encrypted file Jim.dat and decrypt the contents.

    Console::WriteLine();

    Console::WriteLine("Opening the encrypted {0} file and decrypting it...", FileName);

    CryptoStream^ MyStreamDecrypter = nullptr;

 

    try

    {

        FileStream^ MyFileStream = nullptr;

 

        try

        {

             MyFileStream = gcnew FileStream(FileName, FileMode::Open, FileAccess::Read);

             Console::WriteLine("Decrypted {0} file opened successfully", FileName);

        }

        catch (Exception^ e)

        {

            throw gcnew Exception("Failed to open filestream with error: " + e->Message);

        }

 

        try

        {

            Console::WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, decrypting {0}...", FileName);

            DES^ DESAlgorithm = gcnew DESCryptoServiceProvider();

            MyStreamDecrypter = gcnew CryptoStream(MyFileStream, DESAlgorithm->CreateDecryptor(DESKey, DESInitializationVector), CryptoStreamMode::Read);

        }

        catch (Exception^ e)

        {

            MyFileStream->Close();

            throw gcnew Exception("Failed to create DES Symmetric CryptoStream with error: " + e->Message);

        }

 

        array< Byte >^ MyReadBuffer = gcnew array< Byte >(1);

        Console::WriteLine("Reading the decrypted {0} file content...", FileName);

        while (true)

        {

            int BytesRead;

 

            try

            {

                BytesRead = MyStreamDecrypter->Read(MyReadBuffer, 0, MyReadBuffer->Length);

            }

            catch (Exception^ e)

            {

                throw gcnew Exception("Read failed with error: " + e->Message);

            }

            if (BytesRead == 0)

            {

                Console::WriteLine("No more bytes to read...");

                break;

            }

            Console::WriteLine("Read byte -> " + MyReadBuffer[0].ToString());

        }

    }

    catch (Exception^ e)

    {

              Console::WriteLine(e->Message);

    }

    finally

    {

        // We are finished performing IO on the file. We need to close the file to release operating system resources related to the file.

        Console::WriteLine("Closing the decrypter stream...");

        MyStreamDecrypter->Close();

    }

    return 0;

}

 

Build and run the project. The following is an output example.

 

C++ CryptoStream Example - a sample output in action

 

C# CryptoStream Example

 

Create a new console application project. You can use the solution and project name as shown in the following Figure.

 

C# CryptoStream Example - console mode application project creation  

 

Add the following code.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Security.Cryptography;

 

// <summary>

// This sample is designed to show how to use the composable stream CryptoStream

// to read and write encrypted data to a file. The sample uses the DES encryption standard to encrypt data.

// </summary>

namespace CryptoStreamSampleCS

{

    class Program

    {   // <summary>

        // The main entry point for the application.

        // </summary>

        [STAThread]

        static void Main(string[ ] args)

        {

            // Let's create a private key that will be used to encrypt and decrypt the data stored in the file Jim.dat.

            byte[ ] DESKey = { 200, 5, 78, 232, 9, 6, 0, 4 };

            byte[ ] DESInitializationVector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

            CryptoStream MyStreamEncrypter = null;

 

            try

            {

                // Let's create a file named Jim.dat in the current working directory

                FileStream MyFileStream = null;

                try

                {

                    MyFileStream = new FileStream(".\\Jim.dat", FileMode.Create, FileAccess.Write);

                    Console.WriteLine("Jim.dat file created/opened successfully");

                }

                catch (Exception e)

                {

                    throw new Exception("Failed to create/open filestream with error: " + e.Message);

                }

                // Let's create a Symmetric crypto stream using the DES algorithm to encode all the bytes written to the file Jim.

                try

                {

                    Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, encrypting the file...");

                    DES DESAlgorithm = new DESCryptoServiceProvider();

                    MyStreamEncrypter = new CryptoStream(MyFileStream, DESAlgorithm.CreateEncryptor(DESKey, DESInitializationVector),

                        CryptoStreamMode.Write);

                }

                catch (Exception e)

                {

                    MyFileStream.Close();

                    throw new Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message);

                }

                // Let's write 10 bytes to our crypto stream. For simplicity

                // we will write an array of 10 bytes where each byte contains a numeric value 0 - 9.

                byte[ ] MyByteArray = new byte[10];

 

                for (short i = 0; i < MyByteArray.Length; i++)

                {

                    MyByteArray[i] = (byte)i;

                }

 

                try

                {

                    MyStreamEncrypter.Write(MyByteArray, 0, MyByteArray.Length);

                    Console.WriteLine("Writing 10 bytes to the crypto stream...");

                }

                catch (Exception e)

                {

                    throw new Exception("Write failed with error: " + e.Message);

                }

            }

            catch (Exception e)

            {

                Console.WriteLine(e.Message);

                return;

            }

            finally

            {

                // Let's close the crypto stream now that we are finished writing data.

                MyStreamEncrypter.Close();

            }

            // Now let's open the encrypted file Jim.dat and decrypt the contents.

            Console.WriteLine();

            Console.WriteLine("Opening the encrypted file and decrypting it...");

            CryptoStream MyStreamDecrypter = null;

 

            try

            {

                FileStream MyFileStream = null;

 

                try

                {

                    MyFileStream = new FileStream(".\\Jim.dat", FileMode.Open, FileAccess.Read);

                    Console.WriteLine("Decrypted file opened successfully");

                }

                catch (Exception e)

                {

                    throw new Exception("Failed to open filestream with error: " + e.Message);

                }

 

                try

                {

                    Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, decrypting the file...");

                    DES DESAlgorithm = new DESCryptoServiceProvider();

                    MyStreamDecrypter = new CryptoStream(MyFileStream, DESAlgorithm.CreateDecryptor(DESKey, DESInitializationVector),

                        CryptoStreamMode.Read);

                }

                catch (Exception e)

                {

                    MyFileStream.Close();

                    throw new Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message);

                }

 

                byte[ ] MyReadBuffer = new byte[1];

                Console.WriteLine("Reading the decrypted file content...");

                while (true)

                {

                    int BytesRead;

 

                    try

                    {

                        BytesRead = MyStreamDecrypter.Read(MyReadBuffer, 0, MyReadBuffer.Length);

                    }

                    catch (Exception e)

                    {

                        throw new Exception("Read failed with error: " + e.Message);

                    }

 

                    if (BytesRead == 0)

                    {

                        Console.WriteLine("No more bytes to read");

                        break;

                    }

 

                    Console.WriteLine("Read byte -> " + MyReadBuffer[0].ToString());

                }

            }

            catch (Exception e)

            {

                Console.WriteLine(e.Message);

            }

            finally

            {

                // We are finished performing IO on the file. We need to close the file to release operating system resources related to the file.

                MyStreamDecrypter.Close();

            }

        }

    }

}

 

An output sample:

 

C# CryptoStream Example - sample output

 

You may want to try other crypto scheme using the previous same program example. Find the related information in the System.Security.Cryptography Namespace. The part that needs to be modified is shown below (C#).

 

try

{

   Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, encrypting the file...");

   DES DESAlgorithm = new DESCryptoServiceProvider();

   MyStreamEncrypter = new CryptoStream(MyFileStream, DESAlgorithm.CreateEncryptor(DESKey, DESInitializationVector), CryptoStreamMode.Write);

}

catch (Exception e)

{

   MyFileStream.Close();

throw new Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message);

}

try

{

    Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream, decrypting the file...");

    DES DESAlgorithm = new DESCryptoServiceProvider();

    MyStreamDecrypter = new CryptoStream(MyFileStream, DESAlgorithm.CreateDecryptor(DESKey, DESInitializationVector), CryptoStreamMode.Read);

}

catch (Exception e)

{

    MyFileStream.Close();

    throw new Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message);

}

 

VB .NET CryptoStream Example

 

Create a new console application project. You can use the solution and project name as shown in the following Figure.

 

VB .NET CryptoStream Example - console mode project creation example

 

Add the following code.

 

 

Imports System

Imports System.IO

Imports System.Security.Cryptography

 

' This sample is designed to show how to use the composable stream CryptoStream

' to read and write encrypted data to a file. The sample uses the DES encryption standard to encrypt data.

Module Module1

    'The main entry point for the application.

    Sub Main()

        ' Let's create a private key that will be used to encrypt and decrypt the data stored in the file Jim.dat.

        Dim DESKey() As Byte = {200, 5, 78, 232, 9, 6, 0, 4}

        Dim DESInitializationVector() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

 

        Dim MyStreamEncrypter As CryptoStream = Nothing

 

        Try

            ' Let's create a file named Jim.dat in the current working directory

            Dim MyFileStream As FileStream = Nothing

 

            Try

                MyFileStream = New FileStream(".\\Jim.dat", FileMode.Create, FileAccess.Write)

                Console.WriteLine("Jim.dat file created/opened successfully")

            Catch e As Exception

                Throw New Exception("Failed to create/open filestream with error: " + e.Message)

            End Try

 

            ' Let's create a Symmetric crypto stream using the DES algorithm to encode all the bytes written to the file Jim.dat.

            Try

                Dim DESAlgorithm As DES

                Console.WriteLine("Instantiate DESCryptoServiceProvider & CryptoStream to encrypt a file")

                DESAlgorithm = New DESCryptoServiceProvider

                MyStreamEncrypter = New CryptoStream(MyFileStream, DESAlgorithm.CreateEncryptor(DESKey, DESInitializationVector), _

                        CryptoStreamMode.Write)

            Catch e As Exception

                MyFileStream.Close()

                Throw New Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message)

            End Try

 

            ' Let's write 10 bytes to our crypto stream. For simplicity we will write an array of 10 bytes

            ' where each byte contains a numeric value 0 - 9.

            Dim MyByteArray(10) As Byte

            Dim i As Short

 

            For i = MyByteArray.GetLowerBound(0) To MyByteArray.GetUpperBound(0) - 1

                MyByteArray(i) = i

            Next

 

            Try

                Console.WriteLine("Writing 10 bytes to crypto stream using Write()...")

                MyStreamEncrypter.Write(MyByteArray, 0, MyByteArray.GetUpperBound(0))

            Catch e As Exception

                Throw New Exception("Write failed with error: " + e.Message)

            End Try

        Catch e As Exception

            Console.WriteLine(e.Message)

            Exit Sub

        Finally

            ' Let's close the crypto stream and file stream now that we are finished writing data.

            MyStreamEncrypter.Close()

        End Try

 

        ' Now let's open the encrypted file Jim.dat and decrypt the contents.

        Console.WriteLine()

        Console.WriteLine("Opening the encrypted file and decrypting it...")

        Dim MyStreamDecrypter As CryptoStream = Nothing

 

        Try

            Dim MyFileStream As FileStream = Nothing

            Try

                MyFileStream = New FileStream(".\\Jim.dat", FileMode.Open, FileAccess.Read)

                Console.WriteLine("Decrypted file opened successfully...")

            Catch e As Exception

                Throw New Exception("Failed to open filestream with error: " + e.Message)

            End Try

 

            Try

                Dim DESAlgorithm As DES

                DESAlgorithm = New DESCryptoServiceProvider

 

                MyStreamDecrypter = New CryptoStream(MyFileStream, DESAlgorithm.CreateDecryptor(DESKey, DESInitializationVector), _

                  CryptoStreamMode.Read)

            Catch e As Exception

                MyFileStream.Close()

                Throw New Exception("Failed to create DES Symmetric CryptoStream with error: " + e.Message)

            End Try

 

            Dim MyReadBuffer(1) As Byte

            Console.WriteLine("Decrypting the file and read the content using Read()...")

            Do While True

                Dim BytesRead As Integer

 

                Try

                    BytesRead = MyStreamDecrypter.Read(MyReadBuffer, 0, MyReadBuffer.GetUpperBound(0))

                Catch e As Exception

                    Throw New Exception("Read failed with error: " + e.Message)

                End Try

 

                If (BytesRead = 0) Then

                    Console.WriteLine("No more bytes to read")

                    Exit Do

                End If

 

                Console.WriteLine("Read byte -> " + MyReadBuffer(0).ToString())

            Loop

 

        Catch e As Exception

            Console.WriteLine(e.Message)

 

        Finally

            ' We are finished performing IO on the file. We need to close the file to release operating system resources related to the file.

            MyStreamDecrypter.Close()

        End Try

    End Sub

End Module

 

An output sample:

 

VB .NET CryptoStream Example - an output sample in action

 

 

 


 

< Composable & BufferedStream Streams | Main | SSLStream Class Server Example >