Click here to Skip to main content
15,887,596 members
Articles / Programming Languages / C#

Encrypt/Decrypt File or String

Rate me:
Please Sign up or sign in to vote.
3.04/5 (13 votes)
26 Sep 2007CPOL2 min read 118.3K   5.9K   47   22
This article describes the encrypt/decrypt of any type of file or any string value (like data from textbox) using the secret key (password). Here I have used RijndaelManaged class for encryption/decryption.
Snapshot for text encryption/decryption using the secret key

Screenshot - EncDec_string.jpg

Snapshot for file encryption using the secret key

Screenshot - EncryptFile.jpg

Snapshot for decryption using the secret key

Screenshot - DecryptFile.jpg

Introduction

I found a lot of articles in many sites, even many articles on CodeProject itself. An article Encrypt <--> Decrypt Data with C# written by Syed Moshiur Murshed is based on MD5CryptoServiceProvider class and it describes the encrypting/decrypting of text. I did nothing special. I was working on custom functoid for BizTalk Server 2006. Then I came across the problem with encryption of string and got the solution in this way.

Cryptography Classes

We have a number of cryptography classes which are used to encrypt and decrypt the data under the using System.Security.Cryptography namespace, e.g. DESCryptoServiceProvider class, DSACryptoServiceProvider, MD5CryptoServiceProvider, RNGCryptoServiceProvider, RSACryptoServiceProvider, SHA1CryptoServiceProvider, TripleDESCryptoServiceProvider blah! blah! Each has its own algorithm. So there are many ways to encrypt/decrypt data by using any of the cryptography classes. To know more about cryptography, click here.

Using the Code

In this sample project, I have two types of encryption/decryption:

  1. Encryption/decryption of string using secret key
  2. Encryption/decryption of file using secret key

The code itself is self descriptive. There is nothing special which needs to be explained.

Overview

This is the simple example of encrypting/decrypting of any kind of file, data or string object. you can customize it in your own way. Here I have used the Transform() method. It works in two different ways:

  1. If you want to encrypt/decrypt a small size of string, data, or files then in this case you can pass byte array as input. So before calling this method, you will have to convert input object into byte array.
  2. If you want to encrypt/decrypt any big file like avi, Word document, mpg file, then you will have to pass input as null, but you have to specify an input and output file name with complete path.
C#
/*****************************************************************
* Transform one form to anoter based on CryptoTransform
* It is used to encrypt to decrypt as well as decrypt to encrypt
* Parameters:  input <byte /> - which needs to be transform 
*              transformType - encrypt/decrypt transform
* 
* Return Val:  byte array - transformed value.
***************************************************************/
private byte[] Transform(byte[] input, TransformType transformType)
{
    CryptoStream cryptoStream = null;      	// Stream used to encrypt
    RijndaelManaged rijndael = null;        // Rijndael provider
    ICryptoTransform rijndaelTransform = null;// Encrypting object            
    FileStream fsIn = null;                	//input file
    FileStream fsOut = null;               	//output file
    MemoryStream memStream = null;         	// Stream to contain data
    try
    {
        // Create the crypto objects
        rijndael = new RijndaelManaged();
        rijndael.Key = this._Key;
        rijndael.IV = this._IV;
        if (transformType == TransformType.ENCRYPT)
        {
            rijndaelTransform = rijndael.CreateEncryptor();
        }
        else
        {
            rijndaelTransform = rijndael.CreateDecryptor();
        }

        if ((input != null) && (input.Length > 0))
        {
            memStream = new MemoryStream();
            cryptoStream = new CryptoStream(
                memStream, rijndaelTransform, CryptoStreamMode.Write);

                cryptoStream.Write(input, 0, input.Length);

                cryptoStream.FlushFinalBlock();

                return memStream.ToArray();
        }
        else if ((_inputFile.Length > 0) && (_outputFile.Length > 0))
        {
            // First we are going to open the file streams 
            fsIn = new FileStream(_inputFile,
                FileMode.Open, FileAccess.Read);
            fsOut = new FileStream(_outputFile,
                FileMode.OpenOrCreate, FileAccess.Write);

            cryptoStream = new CryptoStream(
                fsOut, rijndaelTransform, CryptoStreamMode.Write);

            // Now will initialize a buffer and will be 
            // processing the input file in chunks. 
            // This is done to avoid reading the whole file (which can be
            // huge) into memory. 
            int bufferLen = 4096;
            byte[] buffer = new byte<bufferlen />;
            int bytesRead;
            do
            {
                // read a chunk of data from the input file 
                bytesRead = fsIn.Read(buffer, 0, bufferLen);
                // Encrypt it 
                cryptoStream.Write(buffer, 0, bytesRead);
            } 
            while (bytesRead != 0);

            cryptoStream.FlushFinalBlock();
        }
        return null;
    }
    catch (CryptographicException)
    {
        throw new CryptographicException(
            "Password is invalid. Please verify once again.");
    }
    finally
    {
        if (rijndael != null) rijndael.Clear();
        if (rijndaelTransform != null) rijndaelTransform.Dispose();
        if (cryptoStream != null) cryptoStream.Close();
        if (memStream != null) memStream.Close();
        if (fsOut != null) fsOut.Close();
        if (fsIn != null) fsIn.Close();
    }
}

Here you can see the complete class with name EncryptDecrypt.cs. See the code below:

C#
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
/*********************************************
 * Created by Virendra on 13-Sep-2007
 * mail id: virendra.chandra@gmail.com
 *********************************************/
namespace EncryptDecrypt
{
    public class MyEncryptor
    {
        // Internal value of the phrase used to generate the secret key
        private string _Phrase = "";
        //contains input file path and name
        private string _inputFile = "";
        //contains output file path and name
        private string _outputFile = "";
        enum TransformType { ENCRYPT = 0, DECRYPT = 1 }

        /// <value>Set the phrase used to generate the secret key.</value>
        public string Phrase
        {
            set
            {
                this._Phrase = value;
                this.GenerateKey(this._Phrase);
            }
        }

        // Internal initialization vector value to 
        // encrypt/decrypt the first block
        private byte[] _IV;

        // Internal secret key value
        private byte[] _Key;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="SecretPhrase">Secret phrase to generate key</param>
        public MyEncryptor(string SecretPhrase)
        {
            this.Phrase = SecretPhrase;
        }

        /// <summary>
        /// Encrypt the given value with the Rijndael algorithm.
        /// </summary>
        /// <param name="EncryptValue">Value to encrypt</param>
        /// <returns>Encrypted value. </returns>
        public string Encrypt(string EncryptValue)
        {
            try
            {
                if (EncryptValue.Length > 0)
                {
                    // Write the encrypted value into memory
                    byte[] input = Encoding.UTF8.GetBytes(EncryptValue);

                    // Retrieve the encrypted value and return it
                    return (Convert.ToBase64String(Transform(input, 
                        TransformType.ENCRYPT)));
                }
                else
                {
                    return "";
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Decrypt the given value with the Rijndael algorithm.
        /// </summary>
        /// <param name="DecryptValue">Value to decrypt</param>
        /// <returns>Decrypted value. </returns>
        public string Decrypt(string DecryptValue)
        {

            try
            {
                if (DecryptValue.Length > 0)
                {
                    // Write the encrypted value into memory                    
                    byte[] input = Convert.FromBase64String(DecryptValue);

                    // Retrieve the decrypted value and return it
                    return (Encoding.UTF8.GetString(Transform(input, 
                        TransformType.DECRYPT)));
                }
                else
                {
                    return "";
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Encrypt the given value with the Rijndael algorithm.
        /// </summary>
        /// <param name="EncryptValue">Value to encrypt</param>
        /// <returns>Encrypted value. </returns>
        public void Encrypt(string InputFile, string OutputFile)
        {
            try
            {
                if ((InputFile != null) && (InputFile.Length > 0))
                {
                    _inputFile = InputFile;
                }
                if ((OutputFile != null) && (OutputFile.Length > 0))
                {
                    _outputFile = OutputFile;
                }
                Transform(null, TransformType.ENCRYPT);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Decrypt the given value with the Rijndael algorithm.
        /// </summary>
        /// <param name="DecryptValue">Value to decrypt</param>
        /// <returns>Decrypted value. </returns>
        public void Decrypt(string InputFile, string OutputFile)
        {
            try
            {
                if ((InputFile != null) && (InputFile.Length > 0))
                {
                    _inputFile = InputFile;
                }
                if ((OutputFile != null) && (OutputFile.Length > 0))
                {
                    _outputFile = OutputFile;
                }
                Transform(null, TransformType.DECRYPT);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /*****************************************************************
         * Generate an encryption key based on the given phrase.  The 
         * phrase is hashed to create a unique 32 character (256-bit) 
         * value, of which 24 characters (192 bit) are used for the
         * key and the remaining 8 are used for the initialization 
         * vector (IV).
         * 
         * Parameters:  SecretPhrase - phrase to generate the key and 
         * IV from.
         * 
         * Return Val:  None  
         ***************************************************************/
        private void GenerateKey(string SecretPhrase)
        {
            // Initialize internal values
            this._Key = new byte[24];
            this._IV = new byte[16];

            // Perform a hash operation using the phrase.  This will 
            // generate a unique 32 character value to be used as the key.
            byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
            SHA384Managed sha384 = new SHA384Managed();
            sha384.ComputeHash(bytePhrase);
            byte[] result = sha384.Hash;

            // Transfer the first 24 characters of the hashed value to the key
            // and the remaining 8 characters to the initialization vector.
            for (int loop = 0; 
                loop < 24; loop++) this._Key[loop] = result[loop];
            for (int loop = 24; 
                loop < 40; loop++) this._IV[loop - 24] = result[loop];
        }

        /*****************************************************************
         * Transform one form to anoter based on CryptoTransform
         * It is used to encrypt to decrypt as well as decrypt to encrypt
         * Parameters:  input <byte /> - which needs to be transform 
         *              transformType - encrypt/decrypt transform
         * 
         * Return Val:  byte array - transformed value.
         ***************************************************************/
        private byte[] Transform(byte[] input, TransformType transformType)
        {
            CryptoStream cryptoStream = null;      // Stream used to encrypt
            RijndaelManaged rijndael = null;        // Rijndael provider
            ICryptoTransform rijndaelTransform = null;// Encrypting object 
            FileStream fsIn = null;                 //input file
            FileStream fsOut = null;                //output file
            MemoryStream memStream = null;          // Stream to contain data
            try
            {
                // Create the crypto objects
                rijndael = new RijndaelManaged();
                rijndael.Key = this._Key;
                rijndael.IV = this._IV;
                if (transformType == TransformType.ENCRYPT)
                {
                    rijndaelTransform = rijndael.CreateEncryptor();
                }
                else
                {
                    rijndaelTransform = rijndael.CreateDecryptor();
                }

                if ((input != null) && (input.Length > 0))
                {
                    memStream = new MemoryStream();
                    cryptoStream = new CryptoStream(
                         memStream, rijndaelTransform, 
                         CryptoStreamMode.Write);

                    cryptoStream.Write(input, 0, input.Length);

                    cryptoStream.FlushFinalBlock();

                    return memStream.ToArray();
                }
                else if ((_inputFile.Length > 0) && (_outputFile.Length > 0))
                {
                    // First we are going to open the file streams 
                    fsIn = new FileStream(_inputFile,
                                FileMode.Open, FileAccess.Read);
                    fsOut = new FileStream(_outputFile,
                                FileMode.OpenOrCreate, FileAccess.Write);

                    cryptoStream = new CryptoStream(
                        fsOut, rijndaelTransform, CryptoStreamMode.Write);

                    // Now will initialize a buffer and will be 
                    // processing the input file in chunks. 
                    // This is done to avoid reading the whole file 
                    // (which can be huge) into memory. 
                    int bufferLen = 4096;
                    byte[] buffer = new byte<bufferlen />;
                    int bytesRead;
                    do
                    {
                        // read a chunk of data from the input file 
                        bytesRead = fsIn.Read(buffer, 0, bufferLen);
                        // Encrypt it 
                        cryptoStream.Write(buffer, 0, bytesRead);

                    } while (bytesRead != 0);

                    cryptoStream.FlushFinalBlock();
                }
                return null;
            }
            catch (CryptographicException)
            {
                throw new CryptographicException(
                    "Password is invalid. Please verify once again.");
            }
            finally
            {
                if (rijndael != null) rijndael.Clear();
                if (rijndaelTransform != null) rijndaelTransform.Dispose();
                if (cryptoStream != null) cryptoStream.Close();
                if (memStream != null) memStream.Close();
                if (fsOut != null) fsOut.Close();
                if (fsIn != null) fsIn.Close();
            }
        }
    }
}

License

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


Written By
Web Developer
India India
I am a software developer. now i am working microsoft.net technolgy like c#, and asp.net.

Comments and Discussions

 
GeneralOpenfiledialog filter needs to be reset Pin
gherard1-Jan-10 18:46
gherard1-Jan-10 18:46 
NewsTwo other related encryption articles in CodeProject ... Pin
Tony Selke27-Sep-07 6:48
Tony Selke27-Sep-07 6:48 
QuestionIV and Key same for Encryption and Decryption? Pin
Vsree26-Sep-07 18:35
Vsree26-Sep-07 18:35 
AnswerRe: IV and Key same for Encryption and Decryption? Pin
Virendrachandra26-Sep-07 19:08
Virendrachandra26-Sep-07 19:08 
GeneralRe: IV and Key same for Encryption and Decryption? Pin
Virendrachandra26-Sep-07 23:54
Virendrachandra26-Sep-07 23:54 
AnswerRe: IV and Key same for Encryption and Decryption? Pin
Virendrachandra27-Sep-07 0:28
Virendrachandra27-Sep-07 0:28 
GeneralExecutable ZIP is corrupted Pin
OscarTV26-Sep-07 3:41
OscarTV26-Sep-07 3:41 
GeneralRe: Executable ZIP is corrupted Pin
OscarTV26-Sep-07 3:42
OscarTV26-Sep-07 3:42 
GeneralRe: Executable ZIP is corrupted Pin
Virendrachandra26-Sep-07 18:35
Virendrachandra26-Sep-07 18:35 
AnswerRe: Executable ZIP is corrupted Pin
OscarTV26-Sep-07 22:27
OscarTV26-Sep-07 22:27 
GeneralRe: Executable ZIP is corrupted Pin
Sean Ewington9-Oct-07 5:03
staffSean Ewington9-Oct-07 5:03 
GeneralDo Not Calculate the IV; Be Sure to &quot;Chunk&quot; Correctly Pin
Philip J. Smith20-Sep-07 5:13
Philip J. Smith20-Sep-07 5:13 
Initialization Vectors. The initialization vector provides a way to make multiple encrypted instances of the same data appear different after encryption. It is a "security enhancement", but should not be confused with increasing cipher strength.

The correct way to use the IV is to generate it randomly (I believe the RijndaelManaged class can actually do this for you, so you don't have to call the RNG crypto class). Then, append or preface the encrypted data with the unencrypted IV.

Here is an example why it is bad to hard-code the IV, or calculate it based on the input string/key. Let's say you are encrypting passwords into a field in a database. A hacker gets hold of the database and notices that 10 of the password fields have exactly the same byte-pattern, but only one of them is for a user who is an admin. He sends spam to a bunch of addresses at the company with a keylogger payload, but he only has a 1-in-10 success rate of people running the payload. So, guess what? One of those 10 people load it, and you're 0WN3D. Why? Because the hacker can see what other accounts use the same password, and he doesn't have to trip any alarms by trying every account to find a duplicate that might not even exist.

Now, if you encrypted the same passwords with random IVs, he could know exactly what algorithm you used, and even know that your random IVs are always appended on the encrypted data, but it does him no good. He has no way of knowing if two or more passwords are identical. He needs to decrypt the data first, and in order to do that, he needs your key.

Chunking. Processing the file in chunks to be mindful of memory usage is great. However, if you are using an encryption mechanism like Rijndael, you should capture the "feedback" from the end of each encrypted block and feed it back into the encryption/decryption algorithm as the IV for the next block. Otherwise, your encryption is "segmented" into isolated chunks. Similar byte patterns existing in different places in different files could result in the same encrypted byte-patterns. The other disadvantage is that your encryption/decryption scheme is married to your chunk-size. For example, you should be able to encrypt the file using 4 KB chunks and successfully decrypt it using 2 MB chunks.

In order to do that, you will have to flip the padding off while processing all but the last block, capture the leftover padding bits from each block to feed as the IV to the next block, then flip padding back on for the final block so the remainder of pad bits are written correctly.
GeneralRe: Do Not Calculate the IV; Be Sure to &quot;Chunk&quot; Correctly Pin
Virendrachandra21-Sep-07 1:55
Virendrachandra21-Sep-07 1:55 
GeneralRe: Do Not Calculate the IV; Be Sure to &quot;Chunk&quot; Correctly Pin
Philip J. Smith21-Sep-07 5:12
Philip J. Smith21-Sep-07 5:12 
GeneralYou can (re)factor out about 75% of your code Pin
Tony Selke19-Sep-07 2:41
Tony Selke19-Sep-07 2:41 
GeneralRe: You can (re)factor out about 75% of your code Pin
Virendrachandra19-Sep-07 18:52
Virendrachandra19-Sep-07 18:52 
Generalthrow ex is bad Pin
Steve Hansen19-Sep-07 1:45
Steve Hansen19-Sep-07 1:45 
GeneralRe: throw ex is bad Pin
Virendrachandra19-Sep-07 3:02
Virendrachandra19-Sep-07 3:02 
GeneralRe: throw ex is bad Pin
Steve Hansen19-Sep-07 4:26
Steve Hansen19-Sep-07 4:26 
GeneralRe: throw ex is bad Pin
Tony Selke20-Sep-07 2:03
Tony Selke20-Sep-07 2:03 
GeneralRe: throw ex is bad Pin
knuteski9-Oct-07 8:21
knuteski9-Oct-07 8:21 
GeneralRe: throw ex is bad Pin
Virendrachandra9-Oct-07 19:50
Virendrachandra9-Oct-07 19:50 

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.