C# Symmetric encryption wrapper

The original class can be found at codeproject.com. This class is a tidied up version (and disposes more aggressively). You may get issues with the GetLegalIV portion of the code, particularly with triple DES. This is because it pads the IV with spaces, and is not compatible with other implementations of the algorithm, such as the Perl one. The class uses UTF8.

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

/// <summary>
/// Provides the standard 4 types of symmetric encryption
/// methods supported by the .net framework.
/// </summary>
public enum EncryptionType
{
    /// <summary>
    /// Data Encryption Standard algorithm, created in 1977.
    /// The standard encryption strength of DES is 56bit. The
    /// algorithm has been cracked using 100,00 PCs (combined power via the
    /// internet) in 22 hours 15 minutes!
    /// A detailed explanation can be found at:
    /// http://www.tropsoft.com/strongenc/des.htm
    /// </summary>
    DES,
    /// <summary>
    /// RC2 was created by RSA as a proposed replacement for
    /// the DES encryption standard. Its strength is 64bit
    /// (64bit block sizes). The RFC for the standard can 
    /// be found at: 
    /// http://www.networksorcery.com/enp/rfc/rfc2268.txt
    /// </summary>
    RC2,
    /// <summary>
    /// Rijndael is the encryption algorithm used for 
    /// the Advanced Encryption Standard (AES), the standard
    /// symmetric encryption method used by US Government organisations.
    /// The block size can be 128, 192, or 256 bits.
    /// Further information can be found at:
    /// http://csrc.nist.gov/CryptoToolkit/aes/rijndael/
    /// </summary>
    Rijndael,
    /// <summary>
    /// Triple DES is a more powerful form of the original DES standard,
    /// encrypting data using 364bit keys, giving Triple DES a strength
    /// of 192bits. The data is encrypted with the first key, 
    /// decrypted with the second key, and finally encrypted again with 
    /// the third key.
    /// A detailed explaination of the algorithm can be found at:
    /// http://www.tropsoft.com/strongenc/des3.htm
    /// </summary>
    TripleDES

    //RC4
}


/// <summary>
/// SymmetricEncryption is a wrapper of System.Security.Cryptography.SymmetricAlgorithm 
/// classes and simplifies the interface. Symmetric encryption involves a private
/// key to encrypt the data, which enables the data to be de-crypted by other
/// clients, providing they have the private key.
/// 
/// This class is based on Frank Fang's 'SymmCrypto' class, found at: 
/// http://www.codeproject.com/dotnet/encryption_decryption.asp
/// </summary>
public class SymmetricEncryption
{
    private string _initialIV = "12345678";
    private SymmetricAlgorithm _symmetricAlgorithm;

    public string InitialIV
    {
    	get
    	{
    		return _initialIV;
    	}
    	set
    	{
    		_initialIV = value;
    	}
    }

    /// <summary>
    /// Creates a new SymmetricEncryption class with the EncryptionType provided.
    /// </summary>
    /// <param name="Type">The type of symmetric encryption to use.</param>
    public SymmetricEncryption(EncryptionType Type)
    {
    	switch (Type)
    	{
    		case EncryptionType.DES:
    			_symmetricAlgorithm = new DESCryptoServiceProvider();
    			break;
    		case EncryptionType.RC2:
    			_symmetricAlgorithm = new RC2CryptoServiceProvider();
    			break;
    		case EncryptionType.Rijndael:
    			_symmetricAlgorithm = new RijndaelManaged();
    			break;
    		case EncryptionType.TripleDES:
    			_symmetricAlgorithm = new TripleDESCryptoServiceProvider();
    			break;
    		/*case EncryptionType.RC4:
    			symmetricAlgorithm = new Org.Mentalis.Security.Cryptography.RC4CryptoServiceProvider();
    			break;*/
    	}
    }

    /// <summary>
    /// Creates a new SymmetricEncryption class with the SymmetricAlgorithm
    /// provided (which could include an implementation of an algorithm
    /// not provided in the standard .net fcl).
    /// </summary>
    /// <param name="ServiceProvider">A</param>
    public SymmetricEncryption(SymmetricAlgorithm ServiceProvider)
    {
    	_symmetricAlgorithm = ServiceProvider;
    }

    /// <summary>
    /// Encrypts data using the key provided, and the algorithm
    /// specified in the constructor of the class.
    /// </summary>
    /// <param name="contents">The data to encrypt.</param>
    /// <param name="key">The key to encrypt the data with. The longer
    /// and more random the key, the stronger the encryption is.</param>
    /// <returns>A string containing the contents, encrypted using the
    /// key and the algorithm specified in the constructor of the class.</returns>
    public string Encrypt(string contents, string key)
    {
    	// Change to Unicode if you're using a wide character set
    	byte[] buffer = Encoding.UTF8.GetBytes(contents);

    	// Create a MemoryStream so that the process can be done without I/O files
    	using (MemoryStream memoryStream = new MemoryStream())
    	{
    		// Set the private key
    		_symmetricAlgorithm.Key = GetLegalKey(key);
    		_symmetricAlgorithm.IV = GetLegalIV();

    		// Create an Encryptor from the Provider Service instance
    		using (ICryptoTransform transform = _symmetricAlgorithm.CreateEncryptor())
    		{
    			// Create Crypto Stream that transforms a stream using the encryption
    			using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
    			{
    				// write out encrypted content into MemoryStream
    				cryptoStream.Write(buffer, 0, buffer.Length);
    				cryptoStream.FlushFinalBlock();

    				memoryStream.Close();
    				byte[] result = memoryStream.ToArray();

    				// Convert into Base64 so that the result is XML or web safe
    				return Convert.ToBase64String(result);
    			}
    		}
    	}
    }

    /// <summary>
    /// Decrypts data using the key provided, and the algorithm
    /// specified in the constructor of the class.
    /// </summary>
    /// <param name="contents">The data to decrypt.</param>
    /// <param name="key">The key to decrypt the data with.</param>
    /// <returns>A string containing the contents, decrypted using the
    /// key and the algorithm specified in the constructor of the class.</returns>
    public string Decrypt(string contents, string key)
    {
    	// Convert from Base64 to binary
    	byte[] buffer = Convert.FromBase64String(contents);

    	// Create a MemoryStream with the input
    	using (MemoryStream memorystream = new MemoryStream(buffer, 0, buffer.Length))
    	{
    		// Set the private key
    		_symmetricAlgorithm.Key = GetLegalKey(key);
    		_symmetricAlgorithm.IV = GetLegalIV();

    		// Create a Decryptor from the Provider Service instance
    		using (ICryptoTransform transform = _symmetricAlgorithm.CreateDecryptor())
    		{
    			// Create Crypto Stream that transforms a stream using the decryption
    			using (CryptoStream cryptoStream = new CryptoStream(memorystream, transform, CryptoStreamMode.Read))
    			{
    				// Read out the result from the Crypto Stream. Change to Unicode if you're using a wide character set
    				using (StreamReader reader = new StreamReader(cryptoStream,Encoding.UTF8))
    				{
    					return reader.ReadToEnd();
    				}
    			}
    		}
    	}
    }

    private byte[] GetLegalKey(string Key)
    {
    	string sTemp = Key;
    	_symmetricAlgorithm.GenerateKey();
    	byte[] bytTemp = _symmetricAlgorithm.Key;
    	int KeyLength = bytTemp.Length;

    	if (sTemp.Length > KeyLength)
    		sTemp = sTemp.Substring(0, KeyLength);
    	else if (sTemp.Length < KeyLength)
    		sTemp = sTemp.PadRight(KeyLength, ' ');

    	return ASCIIEncoding.ASCII.GetBytes(sTemp);
    }

    private byte[] GetLegalIV()
    {
    	// The initial string of IV may be modified with any data you like
    	string sTemp = _initialIV;
    	_symmetricAlgorithm.GenerateIV();
    	byte[] bytTemp = _symmetricAlgorithm.IV;
    	int IVLength = bytTemp.Length;

    	if (sTemp.Length > IVLength)
    		sTemp = sTemp.Substring(0, IVLength);
    	else if (sTemp.Length < IVLength)
    		sTemp = sTemp.PadRight(IVLength, ' ');

    	return ASCIIEncoding.ASCII.GetBytes(sTemp);
    }
}
Last updated on 02 February 2010

Comments

blog comments powered by Disqus