You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			595 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			595 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| // Transport Security Layer (TLS)
 | |
| // Copyright (c) 2003-2004 Carlos Guzman Alvarez
 | |
| // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
 | |
| //
 | |
| // Permission is hereby granted, free of charge, to any person obtaining
 | |
| // a copy of this software and associated documentation files (the
 | |
| // "Software"), to deal in the Software without restriction, including
 | |
| // without limitation the rights to use, copy, modify, merge, publish,
 | |
| // distribute, sublicense, and/or sell copies of the Software, and to
 | |
| // permit persons to whom the Software is furnished to do so, subject to
 | |
| // the following conditions:
 | |
| // 
 | |
| // The above copyright notice and this permission notice shall be
 | |
| // included in all copies or substantial portions of the Software.
 | |
| // 
 | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
| // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
| // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | |
| // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | |
| // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | |
| // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| //
 | |
| 
 | |
| using System;
 | |
| using System.IO;
 | |
| using System.Text;
 | |
| using System.Security.Cryptography;
 | |
| 
 | |
| using Mono.Security;
 | |
| using Mono.Security.Cryptography;
 | |
| using M = Mono.Security.Cryptography;
 | |
| 
 | |
| namespace Mono.Security.Protocol.Tls
 | |
| {
 | |
| 	internal abstract class CipherSuite
 | |
| 	{
 | |
| 		#region Static Fields
 | |
| 
 | |
| 		public static byte[] EmptyArray = new byte[0];
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Fields
 | |
| 
 | |
| 		private short					code;
 | |
| 		private string					name;
 | |
| 		private CipherAlgorithmType		cipherAlgorithmType;
 | |
| 		private HashAlgorithmType		hashAlgorithmType;
 | |
| 		private ExchangeAlgorithmType	exchangeAlgorithmType;
 | |
| 		private bool					isExportable;
 | |
| 		private CipherMode				cipherMode;
 | |
| 		private byte					keyMaterialSize;
 | |
| 		private int						keyBlockSize;
 | |
| 		private byte					expandedKeyMaterialSize;
 | |
| 		private short					effectiveKeyBits;
 | |
| 		private byte					ivSize;
 | |
| 		private byte					blockSize;
 | |
| 		private Context					context;
 | |
| 		private SymmetricAlgorithm		encryptionAlgorithm;
 | |
| 		private ICryptoTransform		encryptionCipher;
 | |
| 		private SymmetricAlgorithm		decryptionAlgorithm;
 | |
| 		private ICryptoTransform		decryptionCipher;
 | |
| 		private KeyedHashAlgorithm		clientHMAC;
 | |
| 		private KeyedHashAlgorithm		serverHMAC;
 | |
| 			
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Protected Properties
 | |
| 
 | |
| 		protected ICryptoTransform EncryptionCipher
 | |
| 		{
 | |
| 			get { return this.encryptionCipher; }
 | |
| 		}
 | |
| 
 | |
| 		protected ICryptoTransform DecryptionCipher
 | |
| 		{
 | |
| 			get { return this.decryptionCipher; }
 | |
| 		}
 | |
| 
 | |
| 		protected KeyedHashAlgorithm ClientHMAC
 | |
| 		{
 | |
| 			get { return this.clientHMAC; }
 | |
| 		}
 | |
| 		
 | |
| 		protected KeyedHashAlgorithm ServerHMAC
 | |
| 		{
 | |
| 			get { return this.serverHMAC; }
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Properties
 | |
| 
 | |
| 		public CipherAlgorithmType CipherAlgorithmType
 | |
| 		{
 | |
| 			get { return this.cipherAlgorithmType; }
 | |
| 		}
 | |
| 
 | |
| 		public string HashAlgorithmName
 | |
| 		{
 | |
| 			get 
 | |
| 			{  
 | |
| 				switch (this.hashAlgorithmType)
 | |
| 				{
 | |
| 					case HashAlgorithmType.Md5:
 | |
| 						return "MD5";
 | |
| 
 | |
| 					case HashAlgorithmType.Sha1:
 | |
| 						return "SHA1";
 | |
| 
 | |
| 					default:
 | |
| 						return "None";
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		internal HashAlgorithm CreateHashAlgorithm ()
 | |
| 		{
 | |
| 			switch (hashAlgorithmType) {
 | |
| 			case HashAlgorithmType.Md5:
 | |
| 				return MD5.Create ();
 | |
| 			case HashAlgorithmType.Sha1:
 | |
| 				return SHA1.Create ();
 | |
| 			default:
 | |
| 				return null;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public HashAlgorithmType HashAlgorithmType
 | |
| 		{
 | |
| 			get { return this.hashAlgorithmType; }
 | |
| 		}
 | |
| 
 | |
| 		public int HashSize
 | |
| 		{
 | |
| 			get 
 | |
| 			{ 
 | |
| 				switch (this.hashAlgorithmType)
 | |
| 				{
 | |
| 					case HashAlgorithmType.Md5:
 | |
| 						return 16;
 | |
| 
 | |
| 					case HashAlgorithmType.Sha1:
 | |
| 						return 20;
 | |
| 
 | |
| 					default:
 | |
| 						return 0;
 | |
| 				}
 | |
| 			}	
 | |
| 		}
 | |
| 		
 | |
| 		public ExchangeAlgorithmType ExchangeAlgorithmType
 | |
| 		{
 | |
| 			get { return this.exchangeAlgorithmType; }
 | |
| 		}
 | |
| 
 | |
| 		public CipherMode CipherMode
 | |
| 		{
 | |
| 			get { return this.cipherMode; }
 | |
| 		}
 | |
| 
 | |
| 		public short Code
 | |
| 		{
 | |
| 			get { return this.code; }
 | |
| 		}
 | |
| 
 | |
| 		public string Name
 | |
| 		{
 | |
| 			get { return this.name; }
 | |
| 		}
 | |
| 
 | |
| 		public bool IsExportable
 | |
| 		{
 | |
| 			get { return this.isExportable; }
 | |
| 		}
 | |
| 
 | |
| 		public byte	KeyMaterialSize
 | |
| 		{
 | |
| 			get { return this.keyMaterialSize; }
 | |
| 		}
 | |
| 
 | |
| 		public int KeyBlockSize
 | |
| 		{
 | |
| 			get { return this.keyBlockSize; }
 | |
| 		}
 | |
| 
 | |
| 		public byte	ExpandedKeyMaterialSize
 | |
| 		{
 | |
| 			get { return this.expandedKeyMaterialSize; }
 | |
| 		}
 | |
| 
 | |
| 		public short	EffectiveKeyBits
 | |
| 		{
 | |
| 			get { return this.effectiveKeyBits; }
 | |
| 		}
 | |
| 		
 | |
| 		public byte IvSize
 | |
| 		{
 | |
| 			get { return this.ivSize; }
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		public byte	BlockSize
 | |
| 		{
 | |
| 			get { return this.blockSize; }
 | |
| 		}
 | |
| 		*/
 | |
| 
 | |
| 		public Context Context
 | |
| 		{
 | |
| 			get { return this.context; }
 | |
| 			set 
 | |
| 			{ 
 | |
| 				this.context = value; 
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Constructors
 | |
| 		
 | |
| 		public CipherSuite(
 | |
| 			short code, string name, CipherAlgorithmType cipherAlgorithmType, 
 | |
| 			HashAlgorithmType hashAlgorithmType, ExchangeAlgorithmType exchangeAlgorithmType,
 | |
| 			bool exportable, bool blockMode, byte keyMaterialSize, 
 | |
| 			byte expandedKeyMaterialSize, short effectiveKeyBits, 
 | |
| 			byte ivSize, byte blockSize)
 | |
| 		{
 | |
| 			this.code					= code;
 | |
| 			this.name					= name;
 | |
| 			this.cipherAlgorithmType	= cipherAlgorithmType;
 | |
| 			this.hashAlgorithmType		= hashAlgorithmType;
 | |
| 			this.exchangeAlgorithmType	= exchangeAlgorithmType;
 | |
| 			this.isExportable			= exportable;
 | |
| 			if (blockMode)
 | |
| 			{
 | |
| 				this.cipherMode			= CipherMode.CBC;
 | |
| 			}
 | |
| 			this.keyMaterialSize		= keyMaterialSize;
 | |
| 			this.expandedKeyMaterialSize= expandedKeyMaterialSize;
 | |
| 			this.effectiveKeyBits		= effectiveKeyBits;
 | |
| 			this.ivSize					= ivSize;
 | |
| 			this.blockSize				= blockSize;
 | |
| 			this.keyBlockSize			= (this.keyMaterialSize + this.HashSize + this.ivSize) << 1;
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Methods
 | |
| 
 | |
| 		internal void Write (byte[] array, int offset, short value)
 | |
| 		{
 | |
| 			if (offset > array.Length - 2)
 | |
| 				throw new ArgumentException ("offset");
 | |
| 
 | |
| 			array [offset    ] = (byte) (value >> 8);
 | |
| 			array [offset + 1] = (byte) value;
 | |
| 		}
 | |
| 
 | |
| 		internal void Write (byte[] array, int offset, ulong value)
 | |
| 		{
 | |
| 			if (offset > array.Length - 8)
 | |
| 				throw new ArgumentException ("offset");
 | |
| 
 | |
| 			array [offset    ] = (byte) (value >> 56);
 | |
| 			array [offset + 1] = (byte) (value >> 48);
 | |
| 			array [offset + 2] = (byte) (value >> 40);
 | |
| 			array [offset + 3] = (byte) (value >> 32);
 | |
| 			array [offset + 4] = (byte) (value >> 24);
 | |
| 			array [offset + 5] = (byte) (value >> 16);
 | |
| 			array [offset + 6] = (byte) (value >> 8);
 | |
| 			array [offset + 7] = (byte) value;
 | |
| 		}
 | |
| 
 | |
| 		public void InitializeCipher()
 | |
| 		{
 | |
| 			this.createEncryptionCipher();
 | |
| 			this.createDecryptionCipher();
 | |
| 		}
 | |
| 
 | |
| 		public byte[] EncryptRecord(byte[] fragment, byte[] mac)
 | |
| 		{
 | |
| 			// Encryption ( fragment + mac [+ padding + padding_length] )
 | |
| 			int length = fragment.Length + mac.Length;
 | |
| 			int padlen = 0;
 | |
| 			if (this.CipherMode == CipherMode.CBC) {
 | |
| 				// Calculate padding_length
 | |
| 				length++; // keep an extra byte
 | |
| 				padlen = (this.blockSize - length % this.blockSize);
 | |
| 				if (padlen == this.blockSize) {
 | |
| 					padlen = 0;
 | |
| 				}
 | |
| 				length += padlen;
 | |
| 			}
 | |
| 
 | |
| 			byte[] plain = new byte [length];
 | |
| 			Buffer.BlockCopy (fragment, 0, plain, 0, fragment.Length);
 | |
| 			Buffer.BlockCopy (mac, 0, plain, fragment.Length, mac.Length);
 | |
| 			if (padlen > 0) {
 | |
| 				int start = fragment.Length + mac.Length;
 | |
| 				for (int i = start; i < (start + padlen + 1); i++) {
 | |
| 					plain[i] = (byte)padlen;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			this.EncryptionCipher.TransformBlock (plain, 0, plain.Length, plain, 0);
 | |
| 			return plain;
 | |
| 		}
 | |
| 
 | |
| 		public void DecryptRecord(byte[] fragment, out byte[] dcrFragment, out byte[] dcrMAC)
 | |
| 		{
 | |
| 			int	fragmentSize	= 0;
 | |
| 			int paddingLength	= 0;
 | |
| 
 | |
| 			// Decrypt message fragment ( fragment + mac [+ padding + padding_length] )
 | |
| 			this.DecryptionCipher.TransformBlock(fragment, 0, fragment.Length, fragment, 0);
 | |
| 			// optimization: decrypt "in place", worst case: padding will reduce the size of the data
 | |
| 			// this will cut in half the memory allocations (dcrFragment and dcrMAC remains)
 | |
| 
 | |
| 			// Calculate fragment size
 | |
| 			if (this.CipherMode == CipherMode.CBC)
 | |
| 			{
 | |
| 				// Calculate padding_length
 | |
| 				paddingLength	= fragment[fragment.Length - 1];
 | |
| 				fragmentSize	= (fragment.Length - (paddingLength + 1)) - this.HashSize;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				fragmentSize = fragment.Length - this.HashSize;
 | |
| 			}
 | |
| 
 | |
| 			dcrFragment = new byte[fragmentSize];
 | |
| 			dcrMAC		= new byte[HashSize];
 | |
| 
 | |
| 			Buffer.BlockCopy(fragment, 0, dcrFragment, 0, dcrFragment.Length);
 | |
| 			Buffer.BlockCopy(fragment, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Abstract Methods
 | |
| 
 | |
| 		public abstract byte[] ComputeClientRecordMAC(ContentType contentType, byte[] fragment);
 | |
| 
 | |
| 		public abstract byte[] ComputeServerRecordMAC(ContentType contentType, byte[] fragment);
 | |
| 
 | |
| 		public abstract void ComputeMasterSecret(byte[] preMasterSecret);
 | |
| 
 | |
| 		public abstract void ComputeKeys();
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Key Generation Methods
 | |
| 
 | |
| 		public byte[] CreatePremasterSecret()
 | |
| 		{
 | |
| 			ClientContext	context = (ClientContext)this.context;
 | |
| 
 | |
| 			// Generate random bytes (total size)
 | |
| 			byte[] preMasterSecret = this.context.GetSecureRandomBytes (48);
 | |
| 			// and replace the first two bytes with the protocol version
 | |
| 			// (maximum support version not actual)
 | |
| 			preMasterSecret [0] = (byte)(context.ClientHelloProtocol >> 8);
 | |
| 			preMasterSecret [1] = (byte)context.ClientHelloProtocol;
 | |
| 
 | |
| 			return preMasterSecret;
 | |
| 		}
 | |
| 
 | |
| 		public byte[] PRF(byte[] secret, string label, byte[] data, int length)
 | |
| 		{
 | |
| 			/* Secret Length calc exmplain from the RFC2246. Section 5
 | |
| 			 * 
 | |
| 			 * S1 and S2 are the two halves of the secret and each is the same
 | |
| 			 * length. S1 is taken from the first half of the secret, S2 from the
 | |
| 			 * second half. Their length is created by rounding up the length of the
 | |
| 			 * overall secret divided by two; thus, if the original secret is an odd
 | |
| 			 * number of bytes long, the last byte of S1 will be the same as the
 | |
| 			 * first byte of S2.
 | |
| 			 */
 | |
| 
 | |
| 			// split secret in 2
 | |
| 			int secretLen = secret.Length >> 1;
 | |
| 			// rounding up
 | |
| 			if ((secret.Length & 0x1) == 0x1)
 | |
| 				secretLen++;
 | |
| 
 | |
| 			// Seed
 | |
| 			TlsStream seedStream = new TlsStream();
 | |
| 			seedStream.Write(Encoding.ASCII.GetBytes(label));
 | |
| 			seedStream.Write(data);
 | |
| 			byte[] seed = seedStream.ToArray();
 | |
| 			seedStream.Reset();
 | |
| 
 | |
| 			// Secret 1
 | |
| 			byte[] secret1 = new byte[secretLen];
 | |
| 			Buffer.BlockCopy(secret, 0, secret1, 0, secretLen);
 | |
| 
 | |
| 			// Secret2
 | |
| 			byte[] secret2 = new byte[secretLen];
 | |
| 			Buffer.BlockCopy(secret, (secret.Length - secretLen), secret2, 0, secretLen);
 | |
| 
 | |
| 			// Secret 1 processing
 | |
| 			byte[] p_md5 = Expand (MD5.Create (), secret1, seed, length);
 | |
| 
 | |
| 			// Secret 2 processing
 | |
| 			byte[] p_sha = Expand (SHA1.Create (), secret2, seed, length);
 | |
| 
 | |
| 			// Perfor XOR of both results
 | |
| 			byte[] masterSecret = new byte[length];
 | |
| 			for (int i = 0; i < masterSecret.Length; i++)
 | |
| 			{
 | |
| 				masterSecret[i] = (byte)(p_md5[i] ^ p_sha[i]);
 | |
| 			}
 | |
| 
 | |
| 			return masterSecret;
 | |
| 		}
 | |
| 		
 | |
| 		public byte[] Expand (HashAlgorithm hash, byte[] secret, byte[] seed, int length)
 | |
| 		{
 | |
| 			int hashLength	= hash.HashSize / 8;
 | |
| 			int	iterations	= (int)(length / hashLength);
 | |
| 			if ((length % hashLength) > 0)
 | |
| 			{
 | |
| 				iterations++;
 | |
| 			}
 | |
| 			
 | |
| 			M.HMAC		hmac	= new M.HMAC (hash, secret);
 | |
| 			TlsStream	resMacs	= new TlsStream();
 | |
| 			
 | |
| 			byte[][] hmacs = new byte[iterations + 1][];
 | |
| 			hmacs[0] = seed;
 | |
| 			for (int i = 1; i <= iterations; i++)
 | |
| 			{				
 | |
| 				TlsStream hcseed = new TlsStream();
 | |
| 				hmac.TransformFinalBlock(hmacs[i-1], 0, hmacs[i-1].Length);
 | |
| 				hmacs[i] = hmac.Hash;
 | |
| 				hcseed.Write(hmacs[i]);
 | |
| 				hcseed.Write(seed);
 | |
| 				hmac.TransformFinalBlock(hcseed.ToArray(), 0, (int)hcseed.Length);
 | |
| 				resMacs.Write(hmac.Hash);
 | |
| 				hcseed.Reset();
 | |
| 			}
 | |
| 
 | |
| 			byte[] res = new byte[length];
 | |
| 			
 | |
| 			Buffer.BlockCopy(resMacs.ToArray(), 0, res, 0, res.Length);
 | |
| 
 | |
| 			resMacs.Reset();
 | |
| 
 | |
| 			return res;
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 
 | |
| 		#region Private Methods
 | |
| 
 | |
| 		private void createEncryptionCipher()
 | |
| 		{
 | |
| 			// Create and configure the symmetric algorithm
 | |
| 			switch (this.cipherAlgorithmType)
 | |
| 			{
 | |
| 				case CipherAlgorithmType.Des:
 | |
| 					this.encryptionAlgorithm = DES.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rc2:
 | |
| 					this.encryptionAlgorithm = RC2.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rc4:
 | |
| 					this.encryptionAlgorithm = new ARC4Managed();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.TripleDes:
 | |
| 					this.encryptionAlgorithm = TripleDES.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rijndael:
 | |
| 					// only AES is really used - and we can use CommonCrypto for iOS and OSX this way
 | |
| 					this.encryptionAlgorithm = Aes.Create();
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			// If it's a block cipher
 | |
| 			if (this.cipherMode == CipherMode.CBC)
 | |
| 			{
 | |
| 				// Configure encrypt algorithm
 | |
| 				this.encryptionAlgorithm.Mode		= this.cipherMode;
 | |
| 				this.encryptionAlgorithm.Padding	= PaddingMode.None;
 | |
| 				this.encryptionAlgorithm.KeySize	= this.expandedKeyMaterialSize * 8;
 | |
| 				this.encryptionAlgorithm.BlockSize	= this.blockSize * 8;
 | |
| 			}
 | |
| 
 | |
| 			// Set the key and IV for the algorithm
 | |
| 			if (this.context is ClientContext)
 | |
| 			{
 | |
| 				this.encryptionAlgorithm.Key	= this.context.ClientWriteKey;
 | |
| 				this.encryptionAlgorithm.IV		= this.context.ClientWriteIV;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				this.encryptionAlgorithm.Key	= this.context.ServerWriteKey;
 | |
| 				this.encryptionAlgorithm.IV		= this.context.ServerWriteIV;
 | |
| 			}
 | |
| 			
 | |
| 			// Create encryption cipher
 | |
| 			this.encryptionCipher = this.encryptionAlgorithm.CreateEncryptor();
 | |
| 
 | |
| 			// Create the HMAC algorithm
 | |
| 			if (this.context is ClientContext)
 | |
| 			{
 | |
| 				this.clientHMAC = new M.HMAC(
 | |
| 					CreateHashAlgorithm (),
 | |
| 					this.context.Negotiating.ClientWriteMAC);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				this.serverHMAC = new M.HMAC(
 | |
| 					CreateHashAlgorithm (),
 | |
| 					this.context.Negotiating.ServerWriteMAC);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private void createDecryptionCipher()
 | |
| 		{
 | |
| 			// Create and configure the symmetric algorithm
 | |
| 			switch (this.cipherAlgorithmType)
 | |
| 			{
 | |
| 				case CipherAlgorithmType.Des:
 | |
| 					this.decryptionAlgorithm = DES.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rc2:
 | |
| 					this.decryptionAlgorithm = RC2.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rc4:
 | |
| 					this.decryptionAlgorithm = new ARC4Managed();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.TripleDes:
 | |
| 					this.decryptionAlgorithm = TripleDES.Create();
 | |
| 					break;
 | |
| 
 | |
| 				case CipherAlgorithmType.Rijndael:
 | |
| 					// only AES is really used - and we can use CommonCrypto for iOS and OSX this way
 | |
| 					this.decryptionAlgorithm = Aes.Create();
 | |
| 					break;
 | |
| 			}
 | |
| 
 | |
| 			// If it's a block cipher
 | |
| 			if (this.cipherMode == CipherMode.CBC)
 | |
| 			{
 | |
| 				// Configure encrypt algorithm
 | |
| 				this.decryptionAlgorithm.Mode		= this.cipherMode;
 | |
| 				this.decryptionAlgorithm.Padding	= PaddingMode.None;
 | |
| 				this.decryptionAlgorithm.KeySize	= this.expandedKeyMaterialSize * 8;
 | |
| 				this.decryptionAlgorithm.BlockSize	= this.blockSize * 8;
 | |
| 			}
 | |
| 
 | |
| 			// Set the key and IV for the algorithm
 | |
| 			if (this.context is ClientContext)
 | |
| 			{
 | |
| 				this.decryptionAlgorithm.Key	= this.context.ServerWriteKey;
 | |
| 				this.decryptionAlgorithm.IV		= this.context.ServerWriteIV;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				this.decryptionAlgorithm.Key	= this.context.ClientWriteKey;
 | |
| 				this.decryptionAlgorithm.IV		= this.context.ClientWriteIV;
 | |
| 			}
 | |
| 
 | |
| 			// Create decryption cipher			
 | |
| 			this.decryptionCipher = this.decryptionAlgorithm.CreateDecryptor();
 | |
| 
 | |
| 			// Create the HMAC
 | |
| 			if (this.context is ClientContext)
 | |
| 			{
 | |
| 				this.serverHMAC = new M.HMAC(
 | |
| 					CreateHashAlgorithm (),
 | |
| 					this.context.Negotiating.ServerWriteMAC);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				this.clientHMAC = new M.HMAC(
 | |
| 					CreateHashAlgorithm (),
 | |
| 					this.context.Negotiating.ClientWriteMAC);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		#endregion
 | |
| 	}
 | |
| }
 |