Search This Blog

Sunday, 20 October 2013

Understanding the Encryption and Decryption methods using “system.security.cryptography”



Introduction:

The purpose of this post is to understand the Encryption and decryption method.
Download code here

The Code for Encryption:
      // All the below keys are required to initialize the Encryptor, you can change the keys accordingly
    private readonly string keyHash = "@!t@8T*ikS2eY6K"; //Hash key
    private readonly string keySalt = "j.$1SiA4sLk9Tey"; // salt ket
    private readonly string keyVector = "@1B2c3D4e5F6g7H8"; // vector key
    public string EncryptToken(string val)
    {
        try
        {
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(val);

            byte[] keyBytes = new Rfc2898DeriveBytes(keyHash,
                      Encoding.ASCII.GetBytes(keySalt)).GetBytes(256 / 8);

            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding =
                                                  PaddingMode.Zeros };
          
    var encryptor = symmetricKey.CreateEncryptor(keyBytes,
     Encoding.ASCII.GetBytes(keyVector));

            byte[] cipherTextBytes;

            using (var memoryStream = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(memoryStream, encryptor,
                                                           CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                    cryptoStream.FlushFinalBlock();
                    cipherTextBytes = memoryStream.ToArray();
                    cryptoStream.Close();
                }
                memoryStream.Close();
            }
            return Convert.ToBase64String(cipherTextBytes);
        }
        catch
        {
            return "";
        }
      
    }
The Code for Decryption:
    public string DecryptToken(string encryptedText)
    {
        try
        {
            byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
            byte[] keyBytes = new Rfc2898DeriveBytes(keyHash,
                                         Encoding.ASCII.GetBytes(keySalt)).GetBytes(256 / 8);
            var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding =
                                                              PaddingMode.None };

            var decryptor = symmetricKey.CreateDecryptor(keyBytes,
     Encoding.ASCII.GetBytes(keyVector));
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor,
                                                CryptoStreamMode.Read);
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0,
                                                       plainTextBytes.Length);
            memoryStream.Close();
            cryptoStream.Close();
            return Encoding.UTF8.GetString(plainTextBytes, 0,
                                           decryptedByteCount).TrimEnd("\0".ToCharArray());
        }
        catch {
            return "";
        }
    }


System.Security.Cryptography.Rfc2898DeriveBytes class:

Rfc2898DeriveBytes takes a password (hashKey), and then generates keys through calls to the GetBytes method.
You can go to following link for more details of Rfc2898DeriveBytes class:  Rfc2898DeriveBytes

System.Security.Cryptography.RijndaelManaged class:

Here we are using this class to create the encryptor, although this class has more methods and properties, for details please go through following link:  RijndaelManaged


CipherMode Enumeration

The CipherMode Enumeration specifies the block cipher mode to use for encryption, in above encryption method we are using the Cipher Block Chaining (CBC) mode.
The Cipher Block Chaining (CBC) mode introduces feedback. Before each plain text block is encrypted, it is combined with the cipher text of the previous block by a bitwise exclusive OR operation. This ensures that even if the plain text contains many identical blocks, they will each encrypt to a different cipher text block. The initialization vector is combined with the first plain text block by a bitwise exclusive OR operation before the block is encrypted. If a single bit of the cipher text block is mangled, the corresponding plain text block will also be mangled. In addition, a bit in the subsequent block, in the same position as the original mangled bit, will be mangled.
The other Cipher modes are as following:
·         Cipher Feedback (CFB)
·         Cipher Text Stealing (CTS)
·         Electronic Codebook (ECB)
·         Output Feedback (OFB)

To know more details about above mentioned points please go through the following link: CipherMode


PaddingMode Enumeration:

The PaddingMode Enumeration Specifies the type of padding to apply when the message data block is shorter than the full number of bytes needed for a cryptographic operation. In above encryption method we are using the Zeros mode.


Most plain text messages do not consist of a number of bytes that completely fill blocks. Often, there are not enough bytes to fill the last block. When this happens, a padding string is added to the text. For example, if the block length is 64 bits and the last block contains only 40 bits, 24 bits of padding are added.


The other PaddingMode modes are as following:

  • ·         ANSIX923
    ·         ISO10126
    ·         None
    ·         PKCS7
To know more details about above mentioned points please go through the following link: PaddingMode
 


SymmetricAlgorithm.CreateEncryptor Method:

The CreateEncryptor method creates a symmetric encryptor object with the current key property and initialization vector, for more detail please go through the following link: CreateEncryptor

System.Security.Cryptography.CryptoStream Class:


The CLR (common language runtime) uses a stream-oriented design for cryptography. The core of this design is CryptoStream. Any cryptographic objects that implement CryptoStream can be chained together with any objects that implement Stream, so the streamed output from one object can be fed into the input of another object. The intermediate result (the output from the first object) does not need to be stored separately.

You should always explicitly close your CryptoStream object after you are done using it by calling the Close method. Doing so flushes the stream and causes all remain blocks of data to be processed by the CryptoStream object. However, if an exception occurs before you call the Close method, the CryptoStream object might not be closed. To ensure that the Close method always gets called, place your call to the Close method within the finally block of a try/catch statement, in above Encryption method we are using the using statement of c#, for more detail please go through the following link: CryptoStream


using statement of c#:

When we are using an object that encapsulates any resource, we have to make sure that when we are done with the object, the object's Dispose method is called. This can be done more easily using the using statement in C#. The using statement simplifies the code that you have to write to create and then finally clean up the object. The using statement obtains the resource specified, executes the statements and finally calls the Dispose method of the object to clean up the object.
 
 

 
Remarks:
The above encryption and decryption methods are only example methods, you can create your own more powerful encryption and decryption methods using the system.security.cryptography.

References:
·          http://msdn.microsoft.com