Note: If you want to experience a complete C++ .NET/C++-CLI programming tutorial please jump to Visual C++ .NET programming tutorial.
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:
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.
Create a new CLR console application project and you might want to use CryptoStreamSampleCP as the project and solution names.
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.
Create a new console application project. You can use the solution and project name as shown in the following Figure.
![]() |
|
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:
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);
}
Create a new console application project. You can use the solution and project name as shown in the following Figure.
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: