Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication
Retired Content |
---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
J.D. Meier, Alex Mackman, Michael Dunner, and Srinath Vasireddy
Microsoft Corporation
Published: November 2002
Last Revised: January 2006
Applies to:
- .NET Framework 1.1
See the "patterns & practices Security Guidance for Applications Index" for links to additional security resources.
See the Landing Page for a starting point and complete overview of Building Secure ASP.NET Applications.
Summary: This How To shows you how to create a managed class library to provide encryption functionality for applications. It allows an application to choose the encryption algorithm. Supported algorithms include DES, Triple DES, RC2, and Rijndael. (15 printed pages)
Summary of Steps Step 1. Create a C# Class Library Step 2. Create a Console Test Application
Additional Resources
This How To describes how to create a generic encryption library that can be used to encrypt and decrypt data using the following algorithms:
- DES (Digital Encryption Standard)
- Triple DES
- Rijndael
- RC2
For an example application that uses the class library created in this How To, see How To: Store an Encrypted Connection String in the Registry in ASP.NET 1.1 in the Reference section of this guide.
This How To includes the following steps:
- Step 1. Create a C# Class Library
- Step 2. Create a Console Test Application
This procedure creates a C# class library, which will provide encryption and decryption functionality.
To create a C# class library
Start Visual Studio .NET and create a new C# Class Library project called Encryption.
Use Solution Explorer to rename class1.cs as EncryptTransformer.cs.
In EncryptTransformer.cs, rename Class1 as EncryptTransformer.
Change the scope of the class from public to internal.
internal class EncryptTransformer
Add the following using statement at the top of the file.
using System.Security.Cryptography;
Add the following enumerated type within the Encryption namespace.
public enum EncryptionAlgorithm {Des = 1, Rc2, Rijndael, TripleDes};
Add the following private member variables to the EncryptTransformer class.
private EncryptionAlgorithm algorithmID; private byte[] initVec; private byte[] encKey;
Replace the default constructor with the following constructor.
internal EncryptTransformer(EncryptionAlgorithm algId) { //Save the algorithm being used. algorithmID = algId; }
Add the following method to the class.
internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey, byte[] initVec) { // Pick the provider. switch (algorithmID) { case EncryptionAlgorithm.Des: { DES des = new DESCryptoServiceProvider(); des.Mode = CipherMode.CBC; // See if a key was provided if (null == bytesKey) { encKey = des.Key; } else { des.Key = bytesKey; encKey = des.Key; } // See if the client provided an initialization vector if (null == initVec) { // Have the algorithm create one initVec = des.IV; } else { //No, give it to the algorithm des.IV = initVec; } return des.CreateEncryptor(); } case EncryptionAlgorithm.TripleDes: { TripleDES des3 = new TripleDESCryptoServiceProvider(); des3.Mode = CipherMode.CBC; // See if a key was provided if (null == bytesKey) { encKey = des3.Key; } else { des3.Key = bytesKey; encKey = des3.Key; } // See if the client provided an IV if (null == initVec) { //Yes, have the alg create one initVec = des3.IV; } else { //No, give it to the alg. des3.IV = initVec; } return des3.CreateEncryptor(); } case EncryptionAlgorithm.Rc2: { RC2 rc2 = new RC2CryptoServiceProvider(); rc2.Mode = CipherMode.CBC; // Test to see if a key was provided if (null == bytesKey) { encKey = rc2.Key; } else { rc2.Key = bytesKey; encKey = rc2.Key; } // See if the client provided an IV if (null == initVec) { //Yes, have the alg create one initVec = rc2.IV; } else { //No, give it to the alg. rc2.IV = initVec; } return rc2.CreateEncryptor(); } case EncryptionAlgorithm.Rijndael: { Rijndael rijndael = new RijndaelManaged(); rijndael.Mode = CipherMode.CBC; // Test to see if a key was provided if(null == bytesKey) { encKey = rijndael.Key; } else { rijndael.Key = bytesKey; encKey = rijndael.Key; } // See if the client provided an IV if(null == initVec) { //Yes, have the alg create one initVec = rijndael.IV; } else { //No, give it to the alg. rijndael.IV = initVec; } return rijndael.CreateEncryptor(); } default: { throw new CryptographicException("Algorithm ID '" + algorithmID + "' not supported."); } } }
Add the following properties to the class.
internal byte[] IV { get{return initVec;} set{initVec = value;} } internal byte[] Key { get{return encKey;} }
Add a new class called DecryptTransformer to the project.
Add the following using statement at the top of the DecryptTransformer.cs file.
using System.Security.Cryptography;
Change the class scope from public to internal.
Replace the default constructor with the following constructor.
internal DecryptTransformer(EncryptionAlgorithm deCryptId) { algorithmID = deCryptId; }
Add the following private variables to the class.
private EncryptionAlgorithm algorithmID; private byte[] initVec;
Add the following method to the class.
internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey, byte[] initVec) { // Pick the provider. switch (algorithmID) { case EncryptionAlgorithm.Des: { DES des = new DESCryptoServiceProvider(); des.Mode = CipherMode.CBC; des.Key = bytesKey; des.IV = initVec; return des.CreateDecryptor(); } case EncryptionAlgorithm.TripleDes: { TripleDES des3 = new TripleDESCryptoServiceProvider(); des3.Mode = CipherMode.CBC; return des3.CreateDecryptor(bytesKey, initVec); } case EncryptionAlgorithm.Rc2: { RC2 rc2 = new RC2CryptoServiceProvider(); rc2.Mode = CipherMode.CBC; return rc2.CreateDecryptor(bytesKey, initVec); } case EncryptionAlgorithm.Rijndael: { Rijndael rijndael = new RijndaelManaged(); rijndael.Mode = CipherMode.CBC; return rijndael.CreateDecryptor(bytesKey, initVec); } default: { throw new CryptographicException("Algorithm ID '" + algorithmID + "' not supported."); } } } //end GetCryptoServiceProvider
Add the following property to the class.
internal byte[] IV { set{initVec = value;} }
Add a new class called Encryptor to the project.
Add the following using statements at the top of Encryptor.cs.
using System.Security.Cryptography; using System.IO;
Replace the default constructor with the following constructor.
public Encryptor(EncryptionAlgorithm algId) { transformer = new EncryptTransformer(algId); }
Add the following private member variables to the class.
private EncryptTransformer transformer; private byte[] initVec; private byte[] encKey;
Add the following Encrypt method to the class.
public byte[] Encrypt(byte[] bytesData, byte[] bytesKey, byte[] initVec) { //Set up the stream that will hold the encrypted data. MemoryStream memStreamEncryptedData = new MemoryStream(); transformer.IV = initVec; ICryptoTransform transform = transformer.GetCryptoServiceProvider(bytesKey); CryptoStream encStream = new CryptoStream(memStreamEncryptedData, transform, CryptoStreamMode.Write); try { //Encrypt the data, write it to the memory stream. encStream.Write(bytesData, 0, bytesData.Length); } catch(Exception ex) { throw new Exception("Error while writing encrypted data to the stream: \n" + ex.Message); } //Set the IV and key for the client to retrieve encKey = transformer.Key; encStream.FlushFinalBlock(); encStream.Close(); //Send the data back. return memStreamEncryptedData.ToArray(); }//end Encrypt
Add the following properties to the class.
public byte[] IV { get{return initVec;} set{initVec = value;} } public byte[] Key { get{return encKey;} }
Add a new class called Decryptor to the project.
Add the following using statements at the top of Decryptor.cs
using System.Security.Cryptography; using System.IO;
Replace the default constructor with the following constructor.
public Decryptor(EncryptionAlgorithm algId) { transformer = new DecryptTransformer(algId); }
Add the following private member variables to the class.
private DecryptTransformer transformer; private byte[] initVec;
Add the following Decrypt method to the class.
public byte[] Decrypt(byte[] bytesData, byte[] bytesKey, byte[] initVec) { //Set up the memory stream for the decrypted data. MemoryStream memStreamDecryptedData = new MemoryStream(); //Pass in the initialization vector. transformer.IV = initVec; ICryptoTransform transform = transformer.GetCryptoServiceProvider(bytesKey); CryptoStream decStream = new CryptoStream(memStreamDecryptedData, transform, CryptoStreamMode.Write); try { decStream.Write(bytesData, 0, bytesData.Length); } catch(Exception ex) { throw new Exception("Error while writing encrypted data to the stream: \n" + ex.Message); } decStream.FlushFinalBlock(); decStream.Close(); // Send the data back. return memStreamDecryptedData.ToArray(); } //end Decrypt
Add the following property to the class.
public byte[] IV { set{initVec = value;} }
On the Build menu, click BuildSolution.
This procedure creates a simple console test application to test the encryption and decryption functionality.
To create a console test application
Add a new C# Console application called EncryptionTester to the current solution.
In Solution Explorer, right-click the EncryptionTester project, and then click Set as StartUp Project.
Use Solution Explorer to rename class1.cs as EncryptionTest.cs.
In EncryptionTest.cs, rename Class1 as EncryptionTest.
Add a project reference to the Encryption project.
Add the following using statements at the top of EncryptionTest.cs.
using System.Text; using Encryption;
Add the following code to the Main method.
// Set the required algorithm EncryptionAlgorithm algorithm = EncryptionAlgorithm.Des; // Init variables. byte[] IV = null; byte[] cipherText = null; byte[] key = null; try { //Try to encrypt. //Create the encryptor. Encryptor enc = new Encryptor(EncryptionAlgorithm.Des); byte[] plainText = Encoding.ASCII.GetBytes("Test String"); if ((EncryptionAlgorithm.TripleDes == algorithm) || (EncryptionAlgorithm.Rijndael == algorithm)) { //3Des only work with a 16 or 24 byte key. key = Encoding.ASCII.GetBytes("password12345678"); if (EncryptionAlgorithm.Rijndael == algorithm) { // Must be 16 bytes for Rijndael. IV = Encoding.ASCII.GetBytes("init vec is big."); } else { IV = Encoding.ASCII.GetBytes("init vec"); } } else { //Des only works with an 8 byte key. The others uses variable length keys. //Set the key to null to have a new one generated. key = Encoding.ASCII.GetBytes("password"); IV = Encoding.ASCII.GetBytes("init vec"); } // Uncomment the next lines to have the key or IV generated for you. // key = null; // IV = null; enc.IV = IV; // Perform the encryption. cipherText = enc.Encrypt(plainText, key); // Retrieve the intialization vector and key. You will need it // for decryption. IV = enc.IV; key = enc.Key; // Look at your cipher text and initialization vector. Console.WriteLine(" Cipher text: " + Convert.ToBase64String(cipherText)); Console.WriteLine("Initialization vector: " + Convert.ToBase64String(IV)); Console.WriteLine(" Key: " + Convert.ToBase64String(key)); } catch(Exception ex) { Console.WriteLine("Exception encrypting. " + ex.Message); return; } try { //Try to decrypt. //Set up your decryption, give it the algorithm and initialization vector. Decryptor dec = new Decryptor(algorithm); dec.IV = IV; // Go ahead and decrypt. byte[] plainText = dec.Decrypt(cipherText, key); // Look at your plain text. Console.WriteLine(" Plain text: " + Encoding.ASCII.GetString(plainText)); } catch(Exception ex) { Console.WriteLine("Exception decrypting. " + ex.Message); return; }
On the Build menu, click BuildSolution.
Run the test application to verify the operation of the Encryptor and Decryptor classes.
For more information, see "How To: Store an Encrypted Connection String in the Registry" in the Reference section of this guide.
Retired Content |
---|
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |