Cryptography Using .NET: .NET Overview

1. Cryptography with C# .NET Framework.  The required main namespace for this lab exercise is System.Security.Cryptography, which provides modern cryptographic services such as symmetric and asymmetric encryption, hashing algorithms, and digital signatures. To see all the classes provided by this namespace, see the System.Security.Cryptography topic in the MSDN documentation at 

2. Symmetric Encryption.  In this section, we will learn how to encrypt data using symmetric algorithms.  With classes defined under the System.Security.Cryptography Namespace, you can implement DES, RC2, Triple-DES, and Rinndael/AES cryptosystems with the key size and block size attributes described in the table below. 

Name Block Size Key Length (bits)
DES 64 56
RC2 64 40, 48, 56, 64, 72, 80, 88, 96,
104, 112, 120, 128  (56-bit keys, expressed as 64-bit )
Triple-DES 64 Numbers
Rijndael (AES) 128, 192, 256 128, 192, 256

3. Basic Encryption Example with C#. 

using System;
using System.Security.Cryptography;
using System.IO;
using System.Text;

     class CryptoClass {

     public byte[] Key;
     public byte[] IV;

     public int KeySize, BlockSize, FeedbackSize;
     public CipherMode Mode;
     public PaddingMode Padding;

     public void Initialize() {

     Key = new byte[] { 0xFC, 0x02, 0x03, 0x04,
                                       0x05, 0x06, 0x07, 0x08,
                                       0x09, 0x10, 0x11, 0x12,
                                       0x13, 0x14, 0x15, 0xAA};

     IV = new byte[] { 0x99, 0x02, 0x03, 0x04,
                                    0x05, 0x06, 0x07, 0x08,
                                    0x09, 0x10, 0x11, 0x12,
                                    0x13, 0x14, 0x15, 0x16};

     KeySize = 128;
     BlockSize = 128;
     FeedbackSize = 128; This is for feedback mode only
     Mode = CipherMode.ECB;
     Padding = PaddingMode.Zeros;

     } // end of Initialize

     public string Encrypt(string plaintext) {

          // get a byte array from a string of plaintext
          byte[] x_plaintext = Encoding.Default.GetBytes(plaintext);

          // create the encryption algorithm
          SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");

          x_alg.KeySize = KeySize;
          x_alg.BlockSize = BlockSize;

          // This is for feedback mode only.
          // The feedback size cannot be greater than the block size.
          x_alg.FeedbackSize = FeedbackSize;

          Console.WriteLine("KeySize = {0}",x_alg.KeySize);
          Console.WriteLine("BlockSize = {0}",x_alg.BlockSize);
          Console.WriteLine("FeedbackSize = {0}",x_alg.FeedbackSize);

          // set Key
          x_alg.Key = Key;

          // set IV
          x_alg.IV = IV;

          // set padding and cipher modes
          x_alg.Mode = Mode;
          x_alg.Padding = Padding;

          Console.WriteLine("\nMode: {0}",x_alg.Mode);
          Console.WriteLine("Padding: {0}",x_alg.Padding);

          // create an ICryptoTransform that can be used to encrypt data
          ICryptoTransform x_encryptor = x_alg.CreateEncryptor();

          // create the memory stream
          MemoryStream x_memory_stream = new MemoryStream();

          // create the CryptoStream that ties together the MemoryStream and the ICryptostream
          CryptoStream x_cryptostream = new CryptoStream(x_memory_stream,
          x_encryptor, CryptoStreamMode.Write);

          // write the plaintext out to the cryptostream
          x_cryptostream.Write(x_plaintext, 0, x_plaintext.Length);

          // close the CryptoStream

          // get the ciphertext from the MemoryStream
          byte[] x_ciphertext = x_memory_stream.ToArray();

          // close memory stream

          // convert from array to string
          string cipher_Tx =Encoding.Default.GetString(x_ciphertext);

          // print out the plaintext

          Console.WriteLine("\n\t\tPlaintext bytes in Hex:\n");

          foreach (byte b in x_plaintext) {

               Console.Write("{0:X2} ", b);

          } // end of foreach

          Console.WriteLine("{0}\n", cipher_Tx);



          return cipher_Tx;

     } // end of Encrypt

} // end of CryptoClass

     class CryptoApp {

     public static void Main() {

          string ciphertext;

          CryptoClass c1 = new CryptoClass();

          // string of plaintext
          string ptext = "We Love Cryptography Class!";

          ciphertext = c1.Encrypt(ptext);

          // print out the ciphertext
          // ...

     } // end of Main

} // end of CryptoApp

4. Program Explanation.  The class CryptoClass contains two methods, which are Initialize and Encrypt. The Initialize method is used to generate the values of the key and initial vector (IV). The Encrypt method receives a string of plaintext as an argument, and then converts the string into an array of bytes.

In this simple example you will set the values of the key and IV manually. Alternatively, the key and IV can be generated randomly using x_alg.GenerateKey() and x_alg.GenerateIV(), respectively.  Since AES is a block cipher, you need to specify the mode of operation and block padding on the Mode and Padding members. The following CipherMode options are available: ECB, CBC, CFB, CTS, OFB PaddingMode: Zeros, PKCS7.

To create or instantiate an encryption algorithm object (i.e., x_alg), use the Create method of the SymmetricAlgorithm class with the argument Rijndael as SymmetricAlgorithm x_alg = SymmetricAlgorithm.Create("Rijndael");  You can use this object to set the key, IV, and all other cipher attributes.

In the first stage of encryption, the class SymmetricAlgorithm uses the ICryptoTransform interface for the cryptographic transformation from plaintext to ciphertext or the reverse for decryption. This interface has to be used with the CryptoStream class, which defines a stream that links data streams to cryptographic transformations. The CryptoStream class requires a target data stream, the transformation to use, and the mode of the stream as the arguments. The target data stream is an instance of the MemoryStream class, which is defined under the System.IO namespace.  This class defines a stream that uses memory for backing. In the final stage, the ciphertext is obtained from the memory stream.

Before terminating the program, all sensitive information such as the key, IV, or other random seed values left in the memory should be destroyed. This can be achieved by using the Clear method for the instances of the algorithm implementation class, and the Close method for the Memory Stream or CryptoStream objects. The resources used by ICryptoTransform objects can be released by the Dispose method.