Click here to Skip to main content
15,892,697 members
Articles / Programming Languages / C#

Creating a secure channel

Rate me:
Please Sign up or sign in to vote.
4.90/5 (33 votes)
24 May 2008CDDL13 min read 118.2K   2.9K   86  
The purpose of this article is to explain how a secure channel is built. The article will explain the structure of a Very Simple Secured Protocol (VSSP) that sits above the TCP/IP layer.
using System;
using System.Security.Cryptography;
using VSSProtocol.Exceptions;
using VSSProtocol.Utils;
using VSSProtocol.Suits;
using System.Security.Cryptography.X509Certificates;

namespace VSSProtocol.Suits
{
	/// <summary>
	/// Currently supported suites.
	/// </summary>
	[Flags]
	internal enum Suit { RSA_1024_3DES_HSHA1_160_GZIP = 0x01,
						None = 0x02
	} // Make sure that lowest are strongest.
	/// <summary>
	/// Various utility methods that handle suits.
	/// </summary>
	internal class SuitsUtils
	{
		/// <summary>
		/// Gets from the suits list (bitwised OR) the best suit.
		/// </summary>
		/// <param name="suitList">A bitwised OR suit.</param>
		/// <returns>Best suit available or None if none was chosen.</returns>
		public static Suit GetBestSuit(Suit suitList)
		{
			Array values = Enum.GetValues(typeof(Suit));
			// Make sure lowest values are first.
			Array.Sort(values);
			foreach (int enumValue in values)
			{
				if ((enumValue & (int)suitList) == enumValue)
				{
					return (Suit) enumValue;
				}
			}
			return Suit.None;
		}
	}
}

namespace VSSProtocol.Session
{
	internal class SessionFactory
	{
		/// <summary>
		/// Create session data from the chosen suit, available assets and the master key.
		/// </summary>
		/// <param name="chosenSuit">Chosen suit to create.</param>
		/// <param name="assets">Available assets used for creation.</param>
		/// <param name="masterKey">The master key from which you derive the keys.
		/// At the end of the process the master key will be trimmed to the size that was actual used.</param>
		/// <returns>A session</returns>
		public static ISession CreateSessionFromSuit(Suit chosenSuit, Assets assets, ref byte[] masterKey)
		{
			switch (chosenSuit)
			{
				#region RSA_1024_3DES_HSHA1_160_GZIP
				case Suits.Suit.RSA_1024_3DES_HSHA1_160_GZIP:
					// Create appropriate algorithms.
					#region Create algorithms
					IAsymmetricAlgorithm rsaAsym = CreateAsymetricAlgorithmFromSuit(chosenSuit, assets.ServerCertificate);
					TripleDESCryptoServiceProvider symetric = new TripleDESCryptoServiceProvider();
					GZipCompressionAlgorithm compression = new GZipCompressionAlgorithm();
					HMACSHA1 hash = new HMACSHA1();
					#endregion
					
					#region Key creation
					// I need two keys and one IV. One key for 3DES, One for HMAC. The IV is for 3DES.
					byte[] tripleDesKey = new byte[symetric.KeySize / 8]; // Given in bits
					byte[] hmacKey = new byte[16]; // Key length of 128 bits.
					byte[] iv = new byte[symetric.BlockSize / 8]; // The size of IV is the size of each block.

					// Key derivation funtion.
					masterKey = kdf(tripleDesKey, hmacKey, iv, masterKey);
					#endregion

					// Update the keys.
					hash.Key = hmacKey;
					symetric.IV = iv;
					symetric.Key = tripleDesKey;

					ConcreteSession returnValue = new ConcreteSession(rsaAsym, hash, symetric, compression);
					return returnValue; 
				#endregion
		
				default:
					throw new ArgumentOutOfRangeException("chosenSuit");
			}
		}

		/// <summary>
		/// Gets appropriate asymetric algorithm from suit and certificate.
		/// </summary>
		/// <param name="chosenSuit">The chosen suit.</param>
		/// <param name="certificate">The certificate</param>
		/// <returns></returns>
		public static IAsymmetricAlgorithm CreateAsymetricAlgorithmFromSuit(Suit chosenSuit, X509Certificate2 certificate)
		{
			switch(chosenSuit)
			{
				#region RSA_1024_3DES_HSHA1_160_GZIP
				case Suit.RSA_1024_3DES_HSHA1_160_GZIP:
					RSACryptoServiceProvider asymetric;
					// If public than retrieve public key.
					if (certificate.PrivateKey == null)
					{
						asymetric = certificate.PublicKey.Key as RSACryptoServiceProvider;
					}
					else // Get private key.
					{
						asymetric = certificate.PrivateKey as RSACryptoServiceProvider;
					}

					if (asymetric == null) // The key is not RSA compatiable.
					{
						throw new CertificateDoNotMacthSuit();
					}
					IAsymmetricAlgorithm rsaAsym = new RsaAsymetricAlgorithm(asymetric); // Adapter.
					return rsaAsym; 
				#endregion
				default:
					throw new ArgumentOutOfRangeException("chosenSuit");
			}
		}

		/// <summary>
		/// Key derivation funtion. A very simple implementation - just cut from the master key the appropriate sizes.
		/// </summary>
		/// <param name="key">Holds the key. Must be initialized in the correct size.</param>
		/// <param name="hmacKey">Holds the hmac key. Must be initialized in the correct size.</param>
		/// <param name="iv">Holds the IV. Must be initialized in the correct size.</param>
		/// <param name="masterKey">Holds the master key from which we derive our keys.</param>
		/// <returns>The trimmed version of the master key.</returns>
		/// <exception cref="ArgumentOutOfRangeException">Master key is too small for derivation.</exception>
		private static byte[] kdf(byte[] key, byte[] hmacKey, byte[] iv, byte[] masterKey )
		{
			#region Null checking
			if (key == null) throw new ArgumentNullException("key");
			if (hmacKey == null) throw new ArgumentNullException("hmacKey");
			if (iv == null) throw new ArgumentNullException("iv");
			if (masterKey == null) throw new ArgumentNullException("masterKey"); 
			#endregion

			int totalLength = key.Length + hmacKey.Length + iv.Length;
			// The kdf is quite simple. Just cut from the master key the appropriate sizes.
			if (masterKey.Length < totalLength)
			{
				throw new ArgumentOutOfRangeException("The required length is greater then the supplied one.");
			}
			// Copy key
			Array.Copy(masterKey, 0, key, 0, key.Length);
			// Copy IV.
			Array.Copy(masterKey, key.Length, iv, 0, iv.Length);
			// Copy hmac key.
			Array.Copy(masterKey, iv.Length + key.Length, hmacKey, 0, hmacKey.Length);

			// Trim the master key.
			byte[] returnValue = new byte[totalLength];
			Array.Copy(masterKey, returnValue, totalLength);
			return returnValue;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer
Israel Israel
A computer science master student at Bar Ilan University under the supervision of Dr. Gal Kaminka.
Dealing mainly with trajectory mining.

Comments and Discussions