diff options
Diffstat (limited to 'mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs')
-rwxr-xr-x | mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs | 1020 |
1 files changed, 510 insertions, 510 deletions
diff --git a/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs b/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs index f99e0e5c7bc..b3926ee28db 100755 --- a/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs +++ b/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs @@ -1,511 +1,511 @@ -/* Transport Security Layer (TLS)
- * Copyright (c) 2003 Carlos Guzmán Álvarez
- *
- * 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;
-
-namespace Mono.Security.Protocol.Tls
-{
- internal abstract class CipherSuite
- {
- #region FIELDS
-
- private short code;
- private string name;
- private string algName;
- private string hashName;
- private bool isExportable;
- private CipherMode cipherMode;
- private byte keyMaterialSize;
- private byte expandedKeyMaterialSize;
- private short effectiveKeyBits;
- private byte ivSize;
- private byte blockSize;
- private TlsSessionContext 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 encryptionCipher; }
- }
-
- protected ICryptoTransform DecryptionCipher
- {
- get { return decryptionCipher; }
- }
-
- protected KeyedHashAlgorithm ClientHMAC
- {
- get { return clientHMAC; }
- }
-
- protected KeyedHashAlgorithm ServerHMAC
- {
- get { return serverHMAC; }
- }
-
- #endregion
-
- #region PROPERTIES
-
- public short Code
- {
- get { return code; }
- }
-
- public string Name
- {
- get { return name; }
- }
-
- public bool IsExportable
- {
- get { return isExportable; }
- }
-
- public CipherMode CipherMode
- {
- get { return cipherMode; }
- }
-
- public int HashSize
- {
- get { return (int)(hashName == "MD5" ? 16 : 20); }
- }
-
- public byte KeyMaterialSize
- {
- get { return keyMaterialSize; }
- }
-
- public int KeyBlockSize
- {
- get
- {
- return keyMaterialSize*2 + HashSize*2 + ivSize*2;
- }
- }
-
- public byte ExpandedKeyMaterialSize
- {
- get { return expandedKeyMaterialSize; }
- }
-
- public byte EffectiveKeyBits
- {
- get { return EffectiveKeyBits; }
- }
-
- public byte IvSize
- {
- get { return ivSize; }
- }
-
- public byte BlockSize
- {
- get { return blockSize; }
- }
-
- public string HashName
- {
- get { return hashName; }
- }
-
- public TlsSessionContext Context
- {
- get { return context; }
- set { context = value; }
- }
-
- #endregion
-
- #region CONSTRUCTORS
-
- public CipherSuite(short code, string name, string algName, string hashName, bool exportable, bool blockMode, byte keyMaterialSize, byte expandedKeyMaterialSize, short effectiveKeyBytes, byte ivSize, byte blockSize)
- {
- this.code = code;
- this.name = name;
- this.algName = algName;
- this.hashName = hashName;
- this.isExportable = exportable;
- if (blockMode)
- {
- this.cipherMode = CipherMode.CBC;
- }
- this.keyMaterialSize = keyMaterialSize;
- this.expandedKeyMaterialSize = expandedKeyMaterialSize;
- this.effectiveKeyBits = effectiveKeyBits;
- this.ivSize = ivSize;
- this.blockSize = blockSize;
- }
-
- #endregion
-
- #region METHODS
-
- public void InitializeCipher()
- {
- createEncryptionCipher();
- createDecryptionCipher();
- }
-
- public RSA CreateRSA()
- {
- RSA rsa;
- if (this.Context.ServerSettings.ServerKeyExchange)
- {
- rsa = new RSACryptoServiceProvider();
- rsa.ImportParameters(this.Context.ServerSettings.RsaParameters);
- }
- else
- {
- rsa = this.Context.ServerSettings.ServerCertificates[0].RSA;
- }
-
- return rsa;
- }
-
- public RSACryptoServiceProvider CreateRSA(RSAParameters rsaParams)
- {
- // BUG: MS BCL 1.0 can't import a key which
- // isn't the same size as the one present in
- // the container.
- int keySize = (rsaParams.Modulus.Length << 3);
- RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize);
- rsa.ImportParameters(rsaParams);
-
- return rsa;
- }
-
- public void UpdateClientCipherIV(byte[] iv)
- {
- if (cipherMode == CipherMode.CBC)
- {
- // Set the new IV
- encryptionAlgorithm.IV = iv;
-
- // Create encryption cipher with the new IV
- encryptionCipher = encryptionAlgorithm.CreateEncryptor();
- }
- }
-
- public void UpdateServerCipherIV(byte[] iv)
- {
- if (cipherMode == CipherMode.CBC)
- {
- // Set the new IV
- decryptionAlgorithm.IV = iv;
-
- // Create encryption cipher with the new IV
- decryptionCipher = 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
- int fragmentLength = fragment.Length + mac.Length + 1;
- int paddingLength = this.blockSize - fragmentLength % this.blockSize;
- if (paddingLength == this.blockSize)
- {
- paddingLength = 0;
- }
-
- // Write padding length byte
- for (int i = 0; i < (paddingLength + 1); i++)
- {
- cs.WriteByte((byte)paddingLength);
- }
- }
- // 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];
-
- /* Review this that is valid way for TLS1 but not for SSL3
- for (int i = (buffer.Length - 1); i > (buffer.Length - (paddingLength + 1)); i--)
- {
- if (buffer[i] != paddingLength)
- {
- paddingLength = 0;
- break;
- }
- }
- */
-
- fragmentSize = (buffer.Length - (paddingLength + 1)) - HashSize;
- }
- else
- {
- fragmentSize = buffer.Length - 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_METODS
-
- 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)
- {
- MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
- SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
-
- 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++;
- }
-
- HMAC hmac = new 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
-
- // This code is from Mono.Security.X509Certificate class.
- private byte[] getUnsignedBigInteger(byte[] integer)
- {
- if (integer[0] == 0x00)
- {
- // this first byte is added so we're sure it's an unsigned integer
- // however we can't feed it into RSAParameters or DSAParameters
- int length = integer.Length - 1;
- byte[] uinteger = new byte[length];
- Array.Copy(integer, 1, uinteger, 0, length);
-
- return uinteger;
- }
- else
- {
- return integer;
- }
- }
-
- private void createEncryptionCipher()
- {
- // Create and configure the symmetric algorithm
- switch (this.algName)
- {
- case "RC4":
- encryptionAlgorithm = new ARC4Managed();
- break;
-
- default:
- encryptionAlgorithm = SymmetricAlgorithm.Create(algName);
- break;
- }
-
- // If it's a block cipher
- if (cipherMode == CipherMode.CBC)
- {
- // Configure encrypt algorithm
- encryptionAlgorithm.Mode = this.cipherMode;
- encryptionAlgorithm.Padding = PaddingMode.None;
- encryptionAlgorithm.KeySize = this.keyMaterialSize * 8;
- encryptionAlgorithm.BlockSize = this.blockSize * 8;
- }
-
- // Set the key and IV for the algorithm
- encryptionAlgorithm.Key = context.ClientWriteKey;
- encryptionAlgorithm.IV = context.ClientWriteIV;
-
- // Create encryption cipher
- encryptionCipher = encryptionAlgorithm.CreateEncryptor();
-
- // Create the HMAC algorithm for the client
- clientHMAC = new HMAC(hashName, context.ClientWriteMAC);
- }
-
- private void createDecryptionCipher()
- {
- // Create and configure the symmetric algorithm
- switch (this.algName)
- {
- case "RC4":
- decryptionAlgorithm = new ARC4Managed();
- break;
-
- default:
- decryptionAlgorithm = SymmetricAlgorithm.Create(algName);
- break;
- }
-
- // If it's a block cipher
- if (cipherMode == CipherMode.CBC)
- {
- // Configure encrypt algorithm
- decryptionAlgorithm.Mode = this.cipherMode;
- decryptionAlgorithm.Padding = PaddingMode.None;
- decryptionAlgorithm.KeySize = this.keyMaterialSize * 8;
- decryptionAlgorithm.BlockSize = this.blockSize * 8;
- }
-
- // Set the key and IV for the algorithm
- decryptionAlgorithm.Key = context.ServerWriteKey;
- decryptionAlgorithm.IV = context.ServerWriteIV;
-
- // Create decryption cipher
- decryptionCipher = decryptionAlgorithm.CreateDecryptor();
-
- // Create the HMAC algorithm for the server
- serverHMAC = new HMAC(hashName, context.ServerWriteMAC);
- }
-
- #endregion
- }
+/* Transport Security Layer (TLS) + * Copyright (c) 2003 Carlos Guzmán Álvarez + * + * 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; + +namespace Mono.Security.Protocol.Tls +{ + internal abstract class CipherSuite + { + #region FIELDS + + private short code; + private string name; + private string algName; + private string hashName; + private bool isExportable; + private CipherMode cipherMode; + private byte keyMaterialSize; + private byte expandedKeyMaterialSize; + private short effectiveKeyBits; + private byte ivSize; + private byte blockSize; + private TlsSessionContext 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 encryptionCipher; } + } + + protected ICryptoTransform DecryptionCipher + { + get { return decryptionCipher; } + } + + protected KeyedHashAlgorithm ClientHMAC + { + get { return clientHMAC; } + } + + protected KeyedHashAlgorithm ServerHMAC + { + get { return serverHMAC; } + } + + #endregion + + #region PROPERTIES + + public short Code + { + get { return code; } + } + + public string Name + { + get { return name; } + } + + public bool IsExportable + { + get { return isExportable; } + } + + public CipherMode CipherMode + { + get { return cipherMode; } + } + + public int HashSize + { + get { return (int)(hashName == "MD5" ? 16 : 20); } + } + + public byte KeyMaterialSize + { + get { return keyMaterialSize; } + } + + public int KeyBlockSize + { + get + { + return keyMaterialSize*2 + HashSize*2 + ivSize*2; + } + } + + public byte ExpandedKeyMaterialSize + { + get { return expandedKeyMaterialSize; } + } + + public byte EffectiveKeyBits + { + get { return EffectiveKeyBits; } + } + + public byte IvSize + { + get { return ivSize; } + } + + public byte BlockSize + { + get { return blockSize; } + } + + public string HashName + { + get { return hashName; } + } + + public TlsSessionContext Context + { + get { return context; } + set { context = value; } + } + + #endregion + + #region CONSTRUCTORS + + public CipherSuite(short code, string name, string algName, string hashName, bool exportable, bool blockMode, byte keyMaterialSize, byte expandedKeyMaterialSize, short effectiveKeyBytes, byte ivSize, byte blockSize) + { + this.code = code; + this.name = name; + this.algName = algName; + this.hashName = hashName; + this.isExportable = exportable; + if (blockMode) + { + this.cipherMode = CipherMode.CBC; + } + this.keyMaterialSize = keyMaterialSize; + this.expandedKeyMaterialSize = expandedKeyMaterialSize; + this.effectiveKeyBits = effectiveKeyBits; + this.ivSize = ivSize; + this.blockSize = blockSize; + } + + #endregion + + #region METHODS + + public void InitializeCipher() + { + createEncryptionCipher(); + createDecryptionCipher(); + } + + public RSA CreateRSA() + { + RSA rsa; + if (this.Context.ServerSettings.ServerKeyExchange) + { + rsa = new RSACryptoServiceProvider(); + rsa.ImportParameters(this.Context.ServerSettings.RsaParameters); + } + else + { + rsa = this.Context.ServerSettings.ServerCertificates[0].RSA; + } + + return rsa; + } + + public RSACryptoServiceProvider CreateRSA(RSAParameters rsaParams) + { + // BUG: MS BCL 1.0 can't import a key which + // isn't the same size as the one present in + // the container. + int keySize = (rsaParams.Modulus.Length << 3); + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(keySize); + rsa.ImportParameters(rsaParams); + + return rsa; + } + + public void UpdateClientCipherIV(byte[] iv) + { + if (cipherMode == CipherMode.CBC) + { + // Set the new IV + encryptionAlgorithm.IV = iv; + + // Create encryption cipher with the new IV + encryptionCipher = encryptionAlgorithm.CreateEncryptor(); + } + } + + public void UpdateServerCipherIV(byte[] iv) + { + if (cipherMode == CipherMode.CBC) + { + // Set the new IV + decryptionAlgorithm.IV = iv; + + // Create encryption cipher with the new IV + decryptionCipher = 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 + int fragmentLength = fragment.Length + mac.Length + 1; + int paddingLength = this.blockSize - fragmentLength % this.blockSize; + if (paddingLength == this.blockSize) + { + paddingLength = 0; + } + + // Write padding length byte + for (int i = 0; i < (paddingLength + 1); i++) + { + cs.WriteByte((byte)paddingLength); + } + } + // 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]; + + /* Review this that is valid way for TLS1 but not for SSL3 + for (int i = (buffer.Length - 1); i > (buffer.Length - (paddingLength + 1)); i--) + { + if (buffer[i] != paddingLength) + { + paddingLength = 0; + break; + } + } + */ + + fragmentSize = (buffer.Length - (paddingLength + 1)) - HashSize; + } + else + { + fragmentSize = buffer.Length - 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_METODS + + 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) + { + MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider(); + SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); + + 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++; + } + + HMAC hmac = new 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 + + // This code is from Mono.Security.X509Certificate class. + private byte[] getUnsignedBigInteger(byte[] integer) + { + if (integer[0] == 0x00) + { + // this first byte is added so we're sure it's an unsigned integer + // however we can't feed it into RSAParameters or DSAParameters + int length = integer.Length - 1; + byte[] uinteger = new byte[length]; + Array.Copy(integer, 1, uinteger, 0, length); + + return uinteger; + } + else + { + return integer; + } + } + + private void createEncryptionCipher() + { + // Create and configure the symmetric algorithm + switch (this.algName) + { + case "RC4": + encryptionAlgorithm = new ARC4Managed(); + break; + + default: + encryptionAlgorithm = SymmetricAlgorithm.Create(algName); + break; + } + + // If it's a block cipher + if (cipherMode == CipherMode.CBC) + { + // Configure encrypt algorithm + encryptionAlgorithm.Mode = this.cipherMode; + encryptionAlgorithm.Padding = PaddingMode.None; + encryptionAlgorithm.KeySize = this.keyMaterialSize * 8; + encryptionAlgorithm.BlockSize = this.blockSize * 8; + } + + // Set the key and IV for the algorithm + encryptionAlgorithm.Key = context.ClientWriteKey; + encryptionAlgorithm.IV = context.ClientWriteIV; + + // Create encryption cipher + encryptionCipher = encryptionAlgorithm.CreateEncryptor(); + + // Create the HMAC algorithm for the client + clientHMAC = new HMAC(hashName, context.ClientWriteMAC); + } + + private void createDecryptionCipher() + { + // Create and configure the symmetric algorithm + switch (this.algName) + { + case "RC4": + decryptionAlgorithm = new ARC4Managed(); + break; + + default: + decryptionAlgorithm = SymmetricAlgorithm.Create(algName); + break; + } + + // If it's a block cipher + if (cipherMode == CipherMode.CBC) + { + // Configure encrypt algorithm + decryptionAlgorithm.Mode = this.cipherMode; + decryptionAlgorithm.Padding = PaddingMode.None; + decryptionAlgorithm.KeySize = this.keyMaterialSize * 8; + decryptionAlgorithm.BlockSize = this.blockSize * 8; + } + + // Set the key and IV for the algorithm + decryptionAlgorithm.Key = context.ServerWriteKey; + decryptionAlgorithm.IV = context.ServerWriteIV; + + // Create decryption cipher + decryptionCipher = decryptionAlgorithm.CreateDecryptor(); + + // Create the HMAC algorithm for the server + serverHMAC = new HMAC(hashName, context.ServerWriteMAC); + } + + #endregion + } }
\ No newline at end of file |