Encryption

Summary

The United States Federal Information Processing Standard (FIPS) defines encryption policies that all U.S. Government computer systems must use. Since Microsoft chooses not to document which encryption routines are FIPS-compliant, and which are not, I had to rely on trial-and-error to come up with a completely FIPS-compliant encryption algorithm.

Source Code

Utilities.cs

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


namespace KXM.Fx.Encryption
{
	/// <summary>
	/// FIPS-Compliant encryption utilities.
	/// </summary>
	public class Utilities
	{
		protected static string Encrypt(string strPlainText, string strKey)
		{
			KeyIV3Des kiv = new KeyIV3Des(strKey);
			TripleDESCryptoServiceProvider des3 = new TripleDESCryptoServiceProvider();
			ICryptoTransform des3Enc = des3.CreateEncryptor(kiv.Key, kiv.IV);

			return Encrypt(strPlainText, des3Enc);

		} //END: EncryptStringDes3(string, string)

		protected static string Decrypt(string strEncryptedText, string strKey)
		{
			ICryptoTransform dec3Des;

			KeyIV3Des kiv = new KeyIV3Des(strKey);
			TripleDESCryptoServiceProvider des3 = null;
			string strReturn = "";

			try
			{
				des3 = new TripleDESCryptoServiceProvider();
				dec3Des = des3.CreateDecryptor(kiv.Key, kiv.IV);

				strReturn = Utilities.Decrypt(strEncryptedText, dec3Des);

			}
			catch (Exception ex)
			{
				throw ex;
			}
			finally
			{
				if (des3 != null)
					des3.Clear();
				if (kiv != null)
					kiv.Clear();
			}


			return strReturn;

		} //END: DectryptStringDes3(string, string)

		/// <summary>
		/// Encrypts a string using the ICryptoTransform provided.
		/// </summary>
		/// <param name="strPlainText">The string to encrypt.</param>
		/// <param name="trans">The ICryptoTransform that will perform the encryption.</param>
		/// <returns>An encrypted string</returns>
		public static string Encrypt(string strPlainText, ICryptoTransform trans)
		{
			// Convert the string to its unicode bytes
			byte[] buf = UnicodeEncoding.Unicode.GetBytes(strPlainText);

			// Create a memory stream
			MemoryStream memStream = new MemoryStream();

			// Create a CryptoStream to encrypt the data and write it to the memory stream.
			CryptoStream cryptStream = new CryptoStream(memStream, trans, CryptoStreamMode.Write);

			// Write the data to the memory stream, encrypting it in the process
			cryptStream.Write(buf, 0, buf.Length);
			cryptStream.FlushFinalBlock();

			// Save the data in the memorystream into a string to be returned.
			string strRet = Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);

			// Close the streams
			cryptStream.Close();
			memStream.Close();

			// Return the encrypted string.
			return strRet;

		} //END: EncryptAndBase64(string, ICryptoTransform)

		/// <summary>
		/// Decrypts a string using the ICryptoTransform provided.
		/// </summary>
		/// <param name="strEncryptedText">The encrypted string.</param>
		/// <param name="trans">The ICryptoTransform that will perform the encryption.</param>
		/// <returns>A plain-text (unencrypted) string.</returns>
		public static string Decrypt(string strEncryptedText, ICryptoTransform trans)
		{
			// Convert the string to its bytes
			byte[] buf = Convert.FromBase64String(strEncryptedText);

			// Create a memory stream
			MemoryStream memStream = new MemoryStream();

			// Create a CryptoStream to decrypt the data and write it to the memory stream.
			CryptoStream cryptStream = new CryptoStream(memStream, trans, CryptoStreamMode.Write);

			// Write the data to the memory stream, decrypting it in the process
			cryptStream.Write(buf, 0, buf.Length);
			cryptStream.FlushFinalBlock();

			// Save the data in the memorystream into a string to be returned.
			string strRet = UnicodeEncoding.Unicode.GetString(memStream.GetBuffer(), 0, (int)memStream.Length);

			// Close the streams
			cryptStream.Close();
			memStream.Close();

			// Return the decrypted string.
			return strRet;

		} //END: DecryptFromBase64(string, ICryptoTransform)

	} // END CLASS Utilities

} // END NAMESPACE KXM.Fx.Encryption

KeyIV3Des.cs

using System;
using System.Security.Cryptography;

namespace KXM.Fx.Encryption
{
	/// <summary>
	/// Represents a Key and Initialization Vector generated from a string.
	/// </summary>
	public class KeyIV3Des
	{
		#region Fields

		private byte[] key3des;
		private byte[] iv3des;

		#endregion

		#region Properties

		/// <summary>
		/// A byte array that can be used as a key in Triple DES encryption
		/// </summary>
		public byte[] Key
		{
			get { return key3des; }
		}

		/// <summary>
		/// A byte array that can be used as an Initialization Vector in Triple DES encryption
		/// </summary>
		public byte[] IV
		{
			get { return iv3des; }
		}

		#endregion

		/// <summary>
		/// Creates a new instance of this class.
		/// </summary>
		/// <param name="txtKey">A String to use as a seed to generate the Key and IV.</param>
		public KeyIV3Des(string strKey)
		{

			byte[] salt = System.Text.UTF8Encoding.UTF8.GetBytes(strKey);
			SHA1CryptoServiceProvider hash = new SHA1CryptoServiceProvider();

			for (int i = 0; i < 200; ++i)
			{
				salt = hash.ComputeHash(salt, 0, salt.Length);
				hash.Initialize();
			}

			PasswordDeriveBytes pdb = new PasswordDeriveBytes(strKey, salt, "SHA1", 1000);
			Array.Clear(salt, 0, salt.Length);
			hash.Clear();

			key3des = pdb.GetBytes(24);
			iv3des = pdb.GetBytes(8);

		} //END: KeyIV3Des(string)


		/// <summary>
		/// Clears the key values.
		/// </summary>
		public void Clear()
		{
			Array.Clear(key3des, 0, key3des.Length);
			Array.Clear(iv3des, 0, iv3des.Length);

		} //END: Clear()

	} // END CLASS KeyIV3Des

} // END NAMESPACE KXM.Fx.Encryption

See Also

Microsoft KB Article 811833