Encryption and Decryption in .NET

Not all information should be carelessly thrown about the internet.  Bits of information can be re-created easily .  So, what if we don't want the world to have access? Time to put on our cryptographer hats!  Here are some things I learned about encrypting and decrypting plain-text in .NET.  

To summarize briefly... encryption (aka the "cipher" process) involves moving or shifting bytes around in a specific algorithm so as to make the original meaning unknown.  Decryption uses the same algorithm to re-create the original text.

Security Standards

Many examples for .NET security use a special .NET class called Rijndael.  What a strange name, and what is it exactly? Well, it is the cipher behind the current Advanced Encryption Standard (AES).  The name is simply a combination of the names of the two cryptographers who created it, Vincent Rijmen and Joan Daemen.

"The AES cipher is specified as a number of repetitions of transformation rounds that convert the input plaintext into the final output of ciphertext"... and it is approved for "top secret" information.

Rijndael is a symmetric key algorithm, meaning the same "key" is used to create and decipher the information.

Rijndael in .NET

The .NET framework has its own implementation of Rijndael and it is found in the System.Security.Cryptography namespace.  MSDN page on Rijndael Managed. The class has to methods which create encryption and decryption classes... CreateEncryptor() and CreateDecryptor().  These must be called with the proper key and initialization vector (IV).

Here is sample code for Encryption...

            RijndaelManaged aesAlg = null;
            try
            {
                aesAlg = new RijndaelManaged();
                aesAlg.BlockSize = 128;         // 128 (for AES), 192 and 256 (Rijndael only), default = 128
                aesAlg.Padding = PaddingMode.PKCS7;
                aesAlg.KeySize = keySize;       // 128, 192, or 256; Key size must be set BEFORE actual Key
                aesAlg.Key = key;               // Secret Key
                aesAlg.IV = iv;                 // Initialization Vector (bit length must match BlockSize)

                // create a decryptor
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(key, iv);

                // create streams used for encryption
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (BinaryReader rdr = new BinaryReader(csDecrypt))
                        {
                            result = rdr.ReadBytes(cipherText.Length);
                        }
                    }
                }
            }
            finally
            {
                if (aesAlg != null)
                    aesAlg.Dispose();
            }

I have hard-coded some values for clarity. The BlockSize defaults to 128 bits. Rijndael does support sizes of 192 or 256, but these are not included in the actual AES standard as mentioned here.

The padding mode determines how extra bits are filled in, and the library's default is PKCS7

The KeySize can be set to 128, 192, or 256 bits, and it must be set BEFORE you set the Key

The Initialization Vector (IV) is a random string which must be the same length (in bits) as the BlockSize

A Unique Key

In order to create a unique key to pass to the CreateEncryptor and CreateDecryptor methods, you can use the PasswordDeriveBytes class. This class will generate a unique key based on a password and salt. This is done through its CryptDeriveKey method. But this method requires the name of the cryptography algorithm.

If the CryptDeriveKey method does not work for you, such as the case with Rijndael, you can use the GetBytes method instead.

                PasswordDeriveBytes pdb = new PasswordDeriveBytes(pwdBytes, saltBytes, hashType, iterations);

                // For other encryption algorithms, pdb.CryptDeriveKey() is preferred instead of GetBytes(length), 
                // but I could not get this to work with Rijndael

                // Use the password to generate pseudo-random bytes for the encryption
                // key. Specify the size of the key in bytes (instead of bits).
                result = pdb.GetBytes(keyLength / 8);

Here is a link to a sample Visual Studio 2010 windows form project. Unzip, open in VS 2010 and hit F5.

BasicEncryption.zip (66.20 kb)

Tags:

 

ASP.NET 3.5 Temporary Files

It looks like the location of ASP.NET Temporary Files has changed in .NET 3.5.

I found the new location today, and it was in the Windows User's AppData folder.  Here is an example path...

C:\Users\[user]\AppData\Local\Temp\Temporary ASP.NET Files\

Previous to 3.5, the temp files could be found in...

C:\Windows\Microsoft.NET\framework\v2.0.50727\Temporary ASP.NET Files\

I don't usually have to be concerned with these files, but on occasion the cached files can cause problems with project builds.  Some build issues can be resolved by deleting all the files in the Temporary ASP.NET Files folder.

Tags:

 

Converting (text, html, word) to PDF in C#

Here's the problem...

We need an imaging solutions that will process e-mail messages and attachments and convert them to pdf or tif so that they can be stored and viewed through a management system.  A single message could consist of any number of d ocuments with varying formats (text, .doc, html, .xls, etc.) and I need to convert anything that can be converted into a PDF document.  This all needs to happen on the fly.

The Tools

I am finally putting together a number of tools to use for this task.  First is the MIME processing required to extract the different parts of a message.

Mime4Net is likely going to be my tool for extracting mime messages.  I plan to create text e mails as .txt files and html emails as .html files.  Attachments will be extracted as they are. (Mime4Net is a commercial product, but there is also an open source tool, called SharpMime that works, but is not as refined as Mime4Net).

The next step is to convert the messages (.txt and .html) and the files.  Right now, I am only really concerned with converting all .txt, .doc, .tif, and any images (.jpg, .gif, etc).  

This is where things get tricky.  There are posts all over the web about various tools for this.  But, I have not found any straight forward solution.  In the end, it seems that the only way to get an accurate reproduction of the original document is going to involve opening the document in it's native application and printing it to a PostScript file.  Ghostscript comes with a print driver for performing this task.  There is a good walk through of this at ASPAlliance

This Post Script file can then be converted to PDF using Ghostscript.  Ghostscript is an "interpreter for the PostScript language and for PDF".

Finally, I will need to merge all my PDF docs into one file for each message. This can be accomplished using iTextSharp

The Solution

After some prototyping I think the entire process for one message is going to look like this.

  • Extract the various message parts
  • Open and print all .txt, .doc, .jpg, .gif files to PostScript
  • Convert PostScript files to PDF using a C# Ghostscript Wrapper
  • Merge PDF files using iTextSharp

More to come in later posts.

== Edit == 

I just found a commercial tool that promises to convert just about anything to PDF.... activePDF

 

Tags:

 

Tip: Error Handling in .NET

In .NET development the common approach to exception handling is to make use of Try...Catch...Finally.

try {
  // some code
}
catch (NullReferenceException ex)
{
   // handle the exception
}

Sometimes you don't need to handle the exception and you just want to throw it to the calling application

try {
  // some code
}
catch (NullReferenceException ex)
{  
   throw ex;
}

But, if you do that you will get useless messages while debugging your application.

The better approach is to just call throw without "ex"...

try {
  // some code
}
catch (NullReferenceException)
{  
   throw;
}

This now provides the following error message which is much more useful.

Tags: