2004-02-17 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls / CipherSuite.cs
index f99e0e5c7bcbed6f564b5f87f35fa311f9fb5080..968eb6e0c0ea6b715757dd12facd48ec45ba639a 100755 (executable)
-/* Transport Security Layer (TLS)\r
- * Copyright (c) 2003 Carlos Guzmán Álvarez\r
- * \r
- * Permission is hereby granted, free of charge, to any person \r
- * obtaining a copy of this software and associated documentation \r
- * files (the "Software"), to deal in the Software without restriction, \r
- * including without limitation the rights to use, copy, modify, merge, \r
- * publish, distribute, sublicense, and/or sell copies of the Software, \r
- * and to permit persons to whom the Software is furnished to do so, \r
- * subject to the following conditions:\r
- * \r
- * The above copyright notice and this permission notice shall be included \r
- * in all copies or substantial portions of the Software.\r
- * \r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, \r
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES \r
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \r
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT \r
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, \r
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \r
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \r
- * DEALINGS IN THE SOFTWARE.\r
- */\r
-\r
-using System;\r
-using System.IO;\r
-using System.Text;\r
-using System.Security.Cryptography;\r
-\r
-using Mono.Security;\r
-using Mono.Security.Cryptography;\r
-using Mono.Security.X509;\r
-\r
-namespace Mono.Security.Protocol.Tls\r
-{\r
-       internal abstract class CipherSuite\r
-       {\r
-               #region FIELDS\r
-\r
-               private short                           code;\r
-               private string                          name;\r
-               private string                          algName;\r
-               private string                          hashName;\r
-               private bool                            isExportable;\r
-               private CipherMode                      cipherMode;\r
-               private byte                            keyMaterialSize;\r
-               private byte                            expandedKeyMaterialSize;\r
-               private short                           effectiveKeyBits;\r
-               private byte                            ivSize;\r
-               private byte                            blockSize;\r
-               private TlsSessionContext       context;\r
-               private SymmetricAlgorithm      encryptionAlgorithm;\r
-               private ICryptoTransform        encryptionCipher;\r
-               private SymmetricAlgorithm      decryptionAlgorithm;\r
-               private ICryptoTransform        decryptionCipher;\r
-               private KeyedHashAlgorithm      clientHMAC;\r
-               private KeyedHashAlgorithm      serverHMAC;\r
-                       \r
-               #endregion\r
-\r
-               #region PROTECTED_PROPERTIES\r
-\r
-               protected ICryptoTransform EncryptionCipher\r
-               {\r
-                       get { return encryptionCipher; }\r
-               }\r
-\r
-               protected ICryptoTransform DecryptionCipher\r
-               {\r
-                       get { return decryptionCipher; }\r
-               }\r
-\r
-               protected KeyedHashAlgorithm ClientHMAC\r
-               {\r
-                       get { return clientHMAC; }\r
-               }\r
-               \r
-               protected KeyedHashAlgorithm ServerHMAC\r
-               {\r
-                       get { return serverHMAC; }\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region PROPERTIES\r
-\r
-               public short Code\r
-               {\r
-                       get { return code; }\r
-               }\r
-\r
-               public string Name\r
-               {\r
-                       get { return name; }\r
-               }\r
-\r
-               public bool IsExportable\r
-               {\r
-                       get { return isExportable; }\r
-               }\r
-\r
-               public CipherMode CipherMode\r
-               {\r
-                       get { return cipherMode; }\r
-               }\r
-\r
-               public int HashSize\r
-               {\r
-                       get { return (int)(hashName == "MD5" ? 16 : 20); }\r
-               }\r
-\r
-               public byte     KeyMaterialSize\r
-               {\r
-                       get { return keyMaterialSize; }\r
-               }\r
-\r
-               public int KeyBlockSize\r
-               {\r
-                       get \r
-                       {\r
-                               return keyMaterialSize*2 + HashSize*2 + ivSize*2;\r
-                       }\r
-               }\r
-\r
-               public byte     ExpandedKeyMaterialSize\r
-               {\r
-                       get { return expandedKeyMaterialSize; }\r
-               }\r
-\r
-               public byte     EffectiveKeyBits\r
-               {\r
-                       get { return EffectiveKeyBits; }\r
-               }\r
-               \r
-               public byte IvSize\r
-               {\r
-                       get { return ivSize; }\r
-               }\r
-\r
-               public byte     BlockSize\r
-               {\r
-                       get { return blockSize; }\r
-               }\r
-\r
-               public string HashName\r
-               {\r
-                       get { return hashName; }\r
-               }\r
-\r
-               public TlsSessionContext Context\r
-               {\r
-                       get { return context; }\r
-                       set { context = value; }\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region CONSTRUCTORS\r
-               \r
-               public CipherSuite(short code, string name, string algName, string hashName, bool exportable, bool blockMode, byte keyMaterialSize, byte expandedKeyMaterialSize, short effectiveKeyBytes, byte ivSize, byte blockSize)\r
-               {\r
-                       this.code                                               = code;\r
-                       this.name                                               = name;\r
-                       this.algName                                    = algName;\r
-                       this.hashName                                   = hashName;\r
-                       this.isExportable                               = exportable;\r
-                       if (blockMode)\r
-                       {\r
-                               this.cipherMode                         = CipherMode.CBC;\r
-                       }\r
-                       this.keyMaterialSize                    = keyMaterialSize;\r
-                       this.expandedKeyMaterialSize    = expandedKeyMaterialSize;\r
-                       this.effectiveKeyBits                   = effectiveKeyBits;\r
-                       this.ivSize                                             = ivSize;\r
-                       this.blockSize                                  = blockSize;\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region METHODS\r
-\r
-               public void InitializeCipher()\r
-               {\r
-                       createEncryptionCipher();\r
-                       createDecryptionCipher();\r
-               }\r
-\r
-               public RSA CreateRSA()\r
-               {\r
-                       RSA rsa;\r
-                       if (this.Context.ServerSettings.ServerKeyExchange)\r
-                       {\r
-                               rsa = new RSACryptoServiceProvider();\r
-                               rsa.ImportParameters(this.Context.ServerSettings.RsaParameters);\r
-                       }\r
-                       else\r
-                       {\r
-                               rsa = this.Context.ServerSettings.ServerCertificates[0].RSA;\r
-                       }\r
-       \r
-                       return rsa;\r
-               }\r
-\r
-               public RSACryptoServiceProvider CreateRSA(RSAParameters rsaParams)\r
-               {                       \r
-                       // BUG: MS BCL 1.0 can't import a key which \r
-                       // isn't the same size as the one present in\r
-                       // the container.\r
-                       int keySize = (rsaParams.Modulus.Length << 3);\r
-                       RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);\r
-                       rsa.ImportParameters(rsaParams);\r
-\r
-                       return rsa;\r
-               }\r
-\r
-               public void UpdateClientCipherIV(byte[] iv)\r
-               {\r
-                       if (cipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Set the new IV\r
-                               encryptionAlgorithm.IV  = iv;\r
-                       \r
-                               // Create encryption cipher with the new IV\r
-                               encryptionCipher = encryptionAlgorithm.CreateEncryptor();\r
-                       }\r
-               }\r
-\r
-               public void UpdateServerCipherIV(byte[] iv)\r
-               {\r
-                       if (cipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Set the new IV\r
-                               decryptionAlgorithm.IV  = iv;\r
-                       \r
-                               // Create encryption cipher with the new IV\r
-                               decryptionCipher = decryptionAlgorithm.CreateDecryptor();\r
-                       }\r
-               }\r
-\r
-               public byte[] EncryptRecord(byte[] fragment, byte[] mac)\r
-               {\r
-                       // Encryption ( fragment + mac [+ padding + padding_length] )\r
-                       MemoryStream ms = new MemoryStream();\r
-                       CryptoStream cs = new CryptoStream(ms, this.EncryptionCipher, CryptoStreamMode.Write);\r
-\r
-                       cs.Write(fragment, 0, fragment.Length);\r
-                       cs.Write(mac, 0, mac.Length);\r
-                       if (this.CipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Calculate padding_length\r
-                               int fragmentLength      = fragment.Length + mac.Length + 1;\r
-                               int paddingLength       = this.blockSize - fragmentLength % this.blockSize;\r
-                               if (paddingLength == this.blockSize)\r
-                               {\r
-                                       paddingLength = 0;\r
-                               }\r
-\r
-                               // Write padding length byte\r
-                               for (int i = 0; i < (paddingLength + 1); i++)\r
-                               {\r
-                                       cs.WriteByte((byte)paddingLength);\r
-                               }\r
-                       }\r
-                       // cs.FlushFinalBlock();\r
-                       cs.Close();                     \r
-\r
-                       return ms.ToArray();\r
-               }\r
-\r
-               public void DecryptRecord(byte[] fragment, ref byte[] dcrFragment, ref byte[] dcrMAC)\r
-               {\r
-                       int     fragmentSize    = 0;\r
-                       int paddingLength       = 0;\r
-\r
-                       // Decrypt message fragment ( fragment + mac [+ padding + padding_length] )\r
-                       byte[] buffer = new byte[fragment.Length];\r
-                       this.DecryptionCipher.TransformBlock(fragment, 0, fragment.Length, buffer, 0);\r
-\r
-                       // Calculate fragment size\r
-                       if (this.CipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Calculate padding_length\r
-                               paddingLength = buffer[buffer.Length - 1];\r
-\r
-                               /* Review this that is valid way for TLS1 but not for SSL3\r
-                               for (int i = (buffer.Length - 1); i > (buffer.Length - (paddingLength + 1)); i--)\r
-                               {\r
-                                       if (buffer[i] != paddingLength)\r
-                                       {\r
-                                               paddingLength = 0;\r
-                                               break;\r
-                                       }\r
-                               }\r
-                               */\r
-\r
-                               fragmentSize = (buffer.Length - (paddingLength + 1)) - HashSize;\r
-                       }\r
-                       else\r
-                       {\r
-                               fragmentSize = buffer.Length - HashSize;\r
-                       }\r
-\r
-                       dcrFragment = new byte[fragmentSize];\r
-                       dcrMAC          = new byte[HashSize];\r
-\r
-                       Buffer.BlockCopy(buffer, 0, dcrFragment, 0, dcrFragment.Length);\r
-                       Buffer.BlockCopy(buffer, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region ABSTRACT_METHODS\r
-\r
-               public abstract byte[] ComputeClientRecordMAC(TlsContentType contentType, byte[] fragment);\r
-\r
-               public abstract byte[] ComputeServerRecordMAC(TlsContentType contentType, byte[] fragment);\r
-\r
-               public abstract void ComputeMasterSecret(byte[] preMasterSecret);\r
-\r
-               public abstract void ComputeKeys();\r
-\r
-               #endregion\r
-\r
-               #region KEY_GENERATION_METODS\r
-\r
-               public byte[] CreatePremasterSecret()\r
-               {\r
-                       TlsStream stream = new TlsStream();\r
-\r
-                       // Write protocol version\r
-                       stream.Write((short)this.Context.Protocol);\r
-\r
-                       // Generate random bytes\r
-                       stream.Write(this.context.GetSecureRandomBytes(46));\r
-\r
-                       byte[] preMasterSecret = stream.ToArray();\r
-\r
-                       stream.Reset();\r
-\r
-                       return preMasterSecret;\r
-               }\r
-\r
-               public byte[] PRF(byte[] secret, string label, byte[] data, int length)\r
-               {\r
-                       MD5CryptoServiceProvider        md5     = new MD5CryptoServiceProvider();\r
-                       SHA1CryptoServiceProvider       sha1 = new SHA1CryptoServiceProvider();\r
-\r
-                       int secretLen = secret.Length / 2;\r
-\r
-                       // Seed\r
-                       TlsStream seedStream = new TlsStream();\r
-                       seedStream.Write(Encoding.ASCII.GetBytes(label));\r
-                       seedStream.Write(data);\r
-                       byte[] seed = seedStream.ToArray();\r
-                       seedStream.Reset();\r
-\r
-                       // Secret 1\r
-                       byte[] secret1 = new byte[secretLen];\r
-                       System.Array.Copy(secret, 0, secret1, 0, secretLen);\r
-\r
-                       // Secret2\r
-                       byte[] secret2 = new byte[secretLen];\r
-                       System.Array.Copy(secret, secretLen, secret2, 0, secretLen);\r
-\r
-                       // Secret 1 processing\r
-                       byte[] p_md5 = Expand("MD5", secret1, seed, length);\r
-\r
-                       // Secret 2 processing\r
-                       byte[] p_sha = Expand("SHA1", secret2, seed, length);\r
-\r
-                       // Perfor XOR of both results\r
-                       byte[] masterSecret = new byte[length];\r
-                       for (int i = 0; i < masterSecret.Length; i++)\r
-                       {\r
-                               masterSecret[i] = (byte)(p_md5[i] ^ p_sha[i]);\r
-                       }\r
-\r
-                       return masterSecret;\r
-               }\r
-               \r
-               public byte[] Expand(string hashName, byte[] secret, byte[] seed, int length)\r
-               {\r
-                       int hashLength  = hashName == "MD5" ? 16 : 20;\r
-                       int     iterations      = (int)(length / hashLength);\r
-                       if ((length % hashLength) > 0)\r
-                       {\r
-                               iterations++;\r
-                       }\r
-                       \r
-                       HMAC            hmac    = new HMAC(hashName, secret);\r
-                       TlsStream       resMacs = new TlsStream();\r
-                       \r
-                       byte[][] hmacs = new byte[iterations + 1][];\r
-                       hmacs[0] = seed;\r
-                       for (int i = 1; i <= iterations; i++)\r
-                       {                               \r
-                               TlsStream hcseed = new TlsStream();\r
-                               hmac.TransformFinalBlock(hmacs[i-1], 0, hmacs[i-1].Length);\r
-                               hmacs[i] = hmac.Hash;\r
-                               hcseed.Write(hmacs[i]);\r
-                               hcseed.Write(seed);\r
-                               hmac.TransformFinalBlock(hcseed.ToArray(), 0, (int)hcseed.Length);\r
-                               resMacs.Write(hmac.Hash);\r
-                               hcseed.Reset();\r
-                       }\r
-\r
-                       byte[] res = new byte[length];\r
-                       \r
-                       System.Array.Copy(resMacs.ToArray(), 0, res, 0, res.Length);\r
-\r
-                       resMacs.Reset();\r
-\r
-                       return res;\r
-               }\r
-\r
-               #endregion\r
-\r
-               #region PRIVATE_METHODS\r
-\r
-               // This code is from Mono.Security.X509Certificate class.\r
-               private byte[] getUnsignedBigInteger(byte[] integer) \r
-               {\r
-                       if (integer[0] == 0x00) \r
-                       {\r
-                               // this first byte is added so we're sure it's an unsigned integer\r
-                               // however we can't feed it into RSAParameters or DSAParameters\r
-                               int             length   = integer.Length - 1;\r
-                               byte[]  uinteger = new byte[length];                            \r
-                               Array.Copy(integer, 1, uinteger, 0, length);\r
-\r
-                               return uinteger;\r
-                       }\r
-                       else\r
-                       {\r
-                               return integer;\r
-                       }\r
-               }\r
-\r
-               private void createEncryptionCipher()\r
-               {\r
-                       // Create and configure the symmetric algorithm\r
-                       switch (this.algName)\r
-                       {\r
-                               case "RC4":\r
-                                       encryptionAlgorithm = new ARC4Managed();\r
-                                       break;\r
-\r
-                               default:\r
-                                       encryptionAlgorithm = SymmetricAlgorithm.Create(algName);\r
-                                       break;\r
-                       }\r
-\r
-                       // If it's a block cipher\r
-                       if (cipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Configure encrypt algorithm\r
-                               encryptionAlgorithm.Mode                = this.cipherMode;\r
-                               encryptionAlgorithm.Padding             = PaddingMode.None;\r
-                               encryptionAlgorithm.KeySize             = this.keyMaterialSize * 8;\r
-                               encryptionAlgorithm.BlockSize   = this.blockSize * 8;\r
-                       }\r
-\r
-                       // Set the key and IV for the algorithm\r
-                       encryptionAlgorithm.Key = context.ClientWriteKey;\r
-                       encryptionAlgorithm.IV  = context.ClientWriteIV;\r
-                       \r
-                       // Create encryption cipher\r
-                       encryptionCipher = encryptionAlgorithm.CreateEncryptor();\r
-\r
-                       // Create the HMAC algorithm for the client\r
-                       clientHMAC = new HMAC(hashName, context.ClientWriteMAC);\r
-               }\r
-\r
-               private void createDecryptionCipher()\r
-               {\r
-                       // Create and configure the symmetric algorithm\r
-                       switch (this.algName)\r
-                       {\r
-                               case "RC4":\r
-                                       decryptionAlgorithm = new ARC4Managed();\r
-                                       break;\r
-\r
-                               default:\r
-                                       decryptionAlgorithm = SymmetricAlgorithm.Create(algName);\r
-                                       break;\r
-                       }\r
-\r
-                       // If it's a block cipher\r
-                       if (cipherMode == CipherMode.CBC)\r
-                       {\r
-                               // Configure encrypt algorithm\r
-                               decryptionAlgorithm.Mode                = this.cipherMode;\r
-                               decryptionAlgorithm.Padding             = PaddingMode.None;\r
-                               decryptionAlgorithm.KeySize             = this.keyMaterialSize * 8;\r
-                               decryptionAlgorithm.BlockSize   = this.blockSize * 8;\r
-                       }\r
-\r
-                       // Set the key and IV for the algorithm\r
-                       decryptionAlgorithm.Key = context.ServerWriteKey;\r
-                       decryptionAlgorithm.IV  = context.ServerWriteIV;\r
-\r
-                       // Create decryption cipher                     \r
-                       decryptionCipher = decryptionAlgorithm.CreateDecryptor();\r
-\r
-                       // Create the HMAC algorithm for the server\r
-                       serverHMAC = new HMAC(hashName, context.ServerWriteMAC);\r
-               }\r
-\r
-               #endregion\r
-       }\r
+/* Transport Security Layer (TLS)
+ * Copyright (c) 2003-2004 Carlos Guzman Alvarez
+ * 
+ * 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 Mono.Security.X509;
+using M = Mono.Security.Cryptography;
+
+namespace Mono.Security.Protocol.Tls
+{
+       internal abstract class CipherSuite
+       {
+               #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 TlsContext              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";
+                               }
+                       }
+               }
+
+               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 byte     EffectiveKeyBits
+               {
+                       get { return this.EffectiveKeyBits; }
+               }
+               
+               public byte IvSize
+               {
+                       get { return this.ivSize; }
+               }
+
+               public byte     BlockSize
+               {
+                       get { return this.blockSize; }
+               }
+
+               public TlsContext 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 effectiveKeyBytes, 
+                       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*2 + this.HashSize*2 + this.ivSize*2;
+               }
+
+               #endregion
+
+               #region Methods
+
+               public void InitializeCipher()
+               {
+                       this.createEncryptionCipher();
+                       this.createDecryptionCipher();
+               }
+
+               public RSA CertificateRSA()
+               {
+                       RSA rsaCert = this.Context.ServerSettings.Certificates[0].RSA;
+                       RSA rsa         = new RSAManaged(rsaCert.KeySize);
+
+                       rsa.ImportParameters(rsaCert.ExportParameters(false));
+
+                       return rsa;
+               }
+
+               public void UpdateClientCipherIV(byte[] iv)
+               {
+                       if (this.cipherMode == CipherMode.CBC)
+                       {
+                               // Set the new IV
+                               this.encryptionAlgorithm.IV     = iv;
+                       
+                               // Create encryption cipher with the new IV
+                               this.encryptionCipher = this.encryptionAlgorithm.CreateEncryptor();
+                       }
+               }
+
+               public void UpdateServerCipherIV(byte[] iv)
+               {
+                       if (this.cipherMode == CipherMode.CBC)
+                       {
+                               // Set the new IV
+                               this.decryptionAlgorithm.IV     = iv;
+                       
+                               // Create encryption cipher with the new IV
+                               this.decryptionCipher = this.decryptionAlgorithm.CreateDecryptor();
+                       }
+               }
+
+               public byte[] EncryptRecord(byte[] fragment, byte[] mac)
+               {
+                       // Encryption ( fragment + mac [+ padding + padding_length] )
+                       MemoryStream ms = new MemoryStream();
+                       CryptoStream cs = new CryptoStream(ms, this.EncryptionCipher, CryptoStreamMode.Write);
+
+                       cs.Write(fragment, 0, fragment.Length);
+                       cs.Write(mac, 0, mac.Length);
+                       if (this.CipherMode == CipherMode.CBC)
+                       {
+                               // Calculate padding_length
+                               byte fragmentLength     = (byte)(fragment.Length + mac.Length + 1);
+                               byte paddingLength      = (byte)(this.blockSize - fragmentLength % this.blockSize);
+                               if (paddingLength == this.blockSize)
+                               {
+                                       paddingLength = 0;
+                               }
+
+                               // Write padding length byte
+                               byte[] padding = new byte[(paddingLength + 1)];                         
+                               for (int i = 0; i < (paddingLength + 1); i++)
+                               {
+                                       padding[i] = paddingLength;
+                               }
+
+                               cs.Write(padding, 0, padding.Length);
+                       }
+                       cs.FlushFinalBlock();
+                       cs.Close();
+
+                       return ms.ToArray();
+               }
+
+               public void DecryptRecord(byte[] fragment, ref byte[] dcrFragment, ref byte[] dcrMAC)
+               {
+                       int     fragmentSize    = 0;
+                       int paddingLength       = 0;
+
+                       // Decrypt message fragment ( fragment + mac [+ padding + padding_length] )
+                       byte[] buffer = new byte[fragment.Length];
+                       this.DecryptionCipher.TransformBlock(fragment, 0, fragment.Length, buffer, 0);
+
+                       // Calculate fragment size
+                       if (this.CipherMode == CipherMode.CBC)
+                       {
+                               // Calculate padding_length
+                               paddingLength   = buffer[buffer.Length - 1];
+                               fragmentSize    = (buffer.Length - (paddingLength + 1)) - this.HashSize;
+                       }
+                       else
+                       {
+                               fragmentSize = buffer.Length - this.HashSize;
+                       }
+
+                       dcrFragment = new byte[fragmentSize];
+                       dcrMAC          = new byte[HashSize];
+
+                       Buffer.BlockCopy(buffer, 0, dcrFragment, 0, dcrFragment.Length);
+                       Buffer.BlockCopy(buffer, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);
+               }
+
+               #endregion
+
+               #region Abstract Methods
+
+               public abstract byte[] ComputeClientRecordMAC(TlsContentType contentType, byte[] fragment);
+
+               public abstract byte[] ComputeServerRecordMAC(TlsContentType contentType, byte[] fragment);
+
+               public abstract void ComputeMasterSecret(byte[] preMasterSecret);
+
+               public abstract void ComputeKeys();
+
+               #endregion
+
+               #region Key Generation Methods
+
+               public byte[] CreatePremasterSecret()
+               {
+                       TlsStream stream = new TlsStream();
+
+                       // Write protocol version
+                       stream.Write((short)this.Context.Protocol);
+
+                       // Generate random bytes
+                       stream.Write(this.context.GetSecureRandomBytes(46));
+
+                       byte[] preMasterSecret = stream.ToArray();
+
+                       stream.Reset();
+
+                       return preMasterSecret;
+               }
+
+               public byte[] PRF(byte[] secret, string label, byte[] data, int length)
+               {
+                       HashAlgorithm md5       = MD5.Create();
+                       HashAlgorithm sha1      = SHA1.Create();
+
+                       int secretLen = secret.Length / 2;
+
+                       // 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];
+                       System.Array.Copy(secret, 0, secret1, 0, secretLen);
+
+                       // Secret2
+                       byte[] secret2 = new byte[secretLen];
+                       System.Array.Copy(secret, secretLen, secret2, 0, secretLen);
+
+                       // Secret 1 processing
+                       byte[] p_md5 = Expand("MD5", secret1, seed, length);
+
+                       // Secret 2 processing
+                       byte[] p_sha = Expand("SHA1", 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(string hashName, byte[] secret, byte[] seed, int length)
+               {
+                       int hashLength  = hashName == "MD5" ? 16 : 20;
+                       int     iterations      = (int)(length / hashLength);
+                       if ((length % hashLength) > 0)
+                       {
+                               iterations++;
+                       }
+                       
+                       M.HMAC          hmac    = new M.HMAC(hashName, 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];
+                       
+                       System.Array.Copy(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:
+                                       this.encryptionAlgorithm = Rijndael.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.keyMaterialSize * 8;
+                               this.encryptionAlgorithm.BlockSize      = this.blockSize * 8;
+                       }
+
+                       // Set the key and IV for the algorithm
+                       this.encryptionAlgorithm.Key    = this.context.ClientWriteKey;
+                       this.encryptionAlgorithm.IV             = this.context.ClientWriteIV;
+                       
+                       // Create encryption cipher
+                       this.encryptionCipher = this.encryptionAlgorithm.CreateEncryptor();
+
+                       // Create the HMAC algorithm for the client
+                       this.clientHMAC = new M.HMAC(
+                               this.HashAlgorithmName,
+                               this.context.ClientWriteMAC);
+               }
+
+               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:
+                                       this.decryptionAlgorithm = Rijndael.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.keyMaterialSize * 8;
+                               this.decryptionAlgorithm.BlockSize      = this.blockSize * 8;
+                       }
+
+                       // Set the key and IV for the algorithm
+                       this.decryptionAlgorithm.Key    = this.context.ServerWriteKey;
+                       this.decryptionAlgorithm.IV             = this.context.ServerWriteIV;
+
+                       // Create decryption cipher                     
+                       this.decryptionCipher = this.decryptionAlgorithm.CreateDecryptor();
+
+                       // Create the HMAC algorithm for the server
+                       this.serverHMAC = new M.HMAC(
+                               this.HashAlgorithmName,
+                               this.context.ServerWriteMAC);
+               }
+
+               #endregion
+       }
 }
\ No newline at end of file