}
// Compose the message
- WriteInt24((int)stream.Length);
- Write(stream.ToArray());
+ this.WriteInt24((int)stream.Length);
+ this.Write(stream.ToArray());
}
#endregion
#region PROTECTED_METHODS
+ private byte[] computeSslHash(string hashName, byte[] hashes, int sender)
+ {
+ HashAlgorithm hash = HashAlgorithm.Create(hashName);
+ TlsStream block = new TlsStream();
+ TlsSslCipherSuite cipher = (TlsSslCipherSuite)this.Session.Context.Cipher;
+ byte[] pad1 = null;
+ byte[] pad2 = null;
+
+ cipher.GeneratePad(hashName, ref pad1, ref pad2);
+
+ block.Write(hashes);
+ block.Write(sender);
+ block.Write(this.Session.Context.MasterSecret);
+ block.Write(cipher.Pad1);
+
+ byte[] blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ block.Write(this.Session.Context.MasterSecret);
+ block.Write(cipher.Pad2);
+ block.Write(blockHash);
+
+ blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ return blockHash;
+ }
+
protected override void ProcessAsSsl3()
{
- throw new NotSupportedException();
+ this.Write(computeSslHash("MD5", Session.Context.HandshakeHashes.Messages, 0x434C4E54));
+ this.Write(computeSslHash("SHA1", Session.Context.HandshakeHashes.Messages, 0x434C4E54));
+
+ Session.Context.HandshakeHashes.Reset();
}
protected override void ProcessAsTls1()
#region CONSTRUCTORS
public TlsClientHello(TlsSession session)
- : base(session,
- TlsHandshakeType.ClientHello,
- TlsContentType.Handshake)
+ : base(session, TlsHandshakeType.ClientHello, TlsContentType.Handshake)
{
}
protected override void ProcessAsSsl3()
{
- throw new NotSupportedException();
+ this.ProcessAsTls1();
}
protected override void ProcessAsTls1()
{
// Client Version
- Write((short)this.Session.Context.Protocol);
+ this.Write((short)this.Session.Context.Protocol);
// Random bytes - Unix time + Radom bytes [28]
TlsStream clientRandom = new TlsStream();
this.random = clientRandom.ToArray();
clientRandom.Reset();
- Write(this.random);
+ this.Write(this.random);
// Session id
// Send the session ID empty
if (this.Session.SessionId != null)
{
- Write((byte)this.Session.SessionId.Length);
+ this.Write((byte)this.Session.SessionId.Length);
if (this.Session.SessionId.Length > 0)
{
- Write(this.Session.SessionId);
+ this.Write(this.Session.SessionId);
}
}
else
{
- Write((byte)0);
+ this.Write((byte)0);
}
// Write length of Cipher suites
- Write((short)(this.Session.SupportedCiphers.Count*2));
+ this.Write((short)(this.Session.Context.SupportedCiphers.Count*2));
// Write Supported Cipher suites
- for (int i = 0; i < this.Session.SupportedCiphers.Count; i++)
+ for (int i = 0; i < this.Session.Context.SupportedCiphers.Count; i++)
{
- Write((short)this.Session.SupportedCiphers[i].Code);
+ this.Write((short)this.Session.Context.SupportedCiphers[i].Code);
}
// Compression methods length
- Write((byte)1);
+ this.Write((byte)1);
// Compression methods ( 0 = none )
- Write((byte)TlsCompressionMethod.None);
+ this.Write((byte)this.Session.Context.CompressionMethod);
}
#endregion
protected override void ProcessAsSsl3()
{
- throw new NotSupportedException();
+ // Compute pre master secret
+ byte[] preMasterSecret = this.Session.Context.Cipher.CreatePremasterSecret();
+
+ // Create a new RSA key
+ RSACryptoServiceProvider rsa = null;
+ if (this.Session.Context.ServerSettings.ServerKeyExchange)
+ {
+ rsa = this.Session.Context.Cipher.CreateRSA(this.Session.Context.ServerSettings.RsaParameters);
+ }
+ else
+ {
+ rsa = this.Session.Context.Cipher.CreateRSA(this.Session.Context.ServerSettings.ServerCertificates[0]);
+ }
+
+ // Encrypt premaster_sercret
+ RSAPKCS1KeyExchangeFormatter formatter = new RSAPKCS1KeyExchangeFormatter(rsa);
+
+ // Write the preMasterSecret encrypted
+ byte[] buffer = formatter.CreateKeyExchange(preMasterSecret);
+ this.Write(buffer);
+
+ // Create master secret
+ this.Session.Context.Cipher.ComputeMasterSecret(preMasterSecret);
+
+ // Create keys
+ this.Session.Context.Cipher.ComputeKeys();
+
+ // Clear resources
+ rsa.Clear();
}
protected override void ProcessAsTls1()
{
// Compute pre master secret
- byte[] preMasterSecret = Session.Context.Cipher.CreatePremasterSecret();
+ byte[] preMasterSecret = this.Session.Context.Cipher.CreatePremasterSecret();
// Create a new RSA key
RSACryptoServiceProvider rsa = null;
- if (Session.Context.ServerSettings.ServerKeyExchange)
+ if (this.Session.Context.ServerSettings.ServerKeyExchange)
{
- rsa = Session.Context.Cipher.CreateRSA(Session.Context.ServerSettings.RsaParameters);
+ rsa = this.Session.Context.Cipher.CreateRSA(this.Session.Context.ServerSettings.RsaParameters);
}
else
{
- rsa = Session.Context.Cipher.CreateRSA(Session.Context.ServerSettings.ServerCertificates[0]);
+ rsa = this.Session.Context.Cipher.CreateRSA(this.Session.Context.ServerSettings.ServerCertificates[0]);
}
// Encrypt premaster_sercret
// Write the preMasterSecret encrypted
byte[] buffer = formatter.CreateKeyExchange(preMasterSecret);
- Write((short)buffer.Length);
- Write(buffer);
+ this.Write((short)buffer.Length);
+ this.Write(buffer);
// Create master secret
- Session.Context.Cipher.CreateMasterSecret(preMasterSecret);
+ this.Session.Context.Cipher.ComputeMasterSecret(preMasterSecret);
// Create keys
- Session.Context.Cipher.CreateKeys();
+ this.Session.Context.Cipher.ComputeKeys();
// Clear resources
rsa.Clear();
protected override void ProcessAsSsl3()
{
- throw new NotSupportedException();
+ this.ProcessAsTls1();
}
protected override void ProcessAsTls1()
this.certificates = new X509CertificateCollection();
int readed = 0;
- int length = ReadInt24();
+ int length = this.ReadInt24();
while (readed < length)
{
if (certLength > 0)
{
// Read certificate
- X509Certificate certificate = new X509Certificate(ReadBytes(certLength));
+ X509Certificate certificate = new X509Certificate(this.ReadBytes(certLength));
certificates.Add(certificate);
readed += certLength;
- validateCertificate(certificate);
+ this.validateCertificate(certificate);
}
}
}
{
base.UpdateSession();
- Session.Context.ServerSettings.CertificateTypes = this.certificateTypes;
- Session.Context.ServerSettings.DistinguisedNames = this.distinguisedNames;
- Session.Context.ServerSettings.CertificateRequest = true;
+ this.Session.Context.ServerSettings.CertificateTypes = this.certificateTypes;
+ this.Session.Context.ServerSettings.DistinguisedNames = this.distinguisedNames;
+ this.Session.Context.ServerSettings.CertificateRequest = true;
}
#endregion
protected override void ProcessAsTls1()
{
// Read requested certificate types
- int typesCount = ReadByte();
+ int typesCount = this.ReadByte();
certificateTypes = new TlsClientCertificateType[typesCount];
for (int i = 0; i < typesCount; i++)
{
- certificateTypes[i] = (TlsClientCertificateType)ReadByte();
+ certificateTypes[i] = (TlsClientCertificateType)this.ReadByte();
}
/*
* attributeType OBJECT IDENTIFIER
* attributeValue ANY }
*/
- int tmp = ReadInt16();
- ASN1 rdn = new ASN1(ReadBytes(ReadInt16()));
+ int tmp = this.ReadInt16();
+ ASN1 rdn = new ASN1(this.ReadBytes(this.ReadInt16()));
distinguisedNames = new string[rdn.Count];
{
base.UpdateSession();
- Session.HandshakeFinished = true;
+ this.Session.Context.HandshakeFinished = true;
}
#endregion
protected override void ProcessAsTls1()
{
- byte[] serverPRF = ReadBytes((int)Length);
+ byte[] serverPRF = this.ReadBytes((int)Length);
TlsStream hashes = new TlsStream();
- hashes.Write(Session.Context.HandshakeHashes.GetMD5Hash());
- hashes.Write(Session.Context.HandshakeHashes.GetSHAHash());
+ hashes.Write(this.Session.Context.HandshakeHashes.GetMD5Hash());
+ hashes.Write(this.Session.Context.HandshakeHashes.GetSHAHash());
- byte[] clientPRF = Session.Context.Cipher.PRF(Session.Context.MasterSecret, "server finished", hashes.ToArray(), 12);
+ byte[] clientPRF = this.Session.Context.Cipher.PRF(this.Session.Context.MasterSecret, "server finished", hashes.ToArray(), 12);
hashes.Reset();
}
}
- Session.Context.HandshakeHashes.Clear();
+ this.Session.Context.HandshakeHashes.Clear();
}
#endregion
private TlsCompressionMethod compressionMethod;
private byte[] random;
private byte[] sessionId;
- private TlsCipherSuite cipherSuite;
+ private CipherSuite cipherSuite;
#endregion
{
base.UpdateSession();
- Session.SetSessionId(this.sessionId);
- Session.Context.ServerRandom = this.random;
- Session.Context.Cipher = this.cipherSuite;
- Session.Context.CompressionMethod = this.compressionMethod;
- Session.Context.Cipher.Context = this.Session.Context;
+ this.Session.SetSessionId(this.sessionId);
+ this.Session.Context.ServerRandom = this.random;
+ this.Session.Context.Cipher = this.cipherSuite;
+ this.Session.Context.CompressionMethod = this.compressionMethod;
+ this.Session.Context.Cipher.Context = this.Session.Context;
+
+ // Compute ClientRandom + ServerRandom
+ TlsStream random = new TlsStream();
+ random.Write(this.Session.Context.ClientRandom);
+ random.Write(this.Session.Context.ServerRandom);
+ this.Session.Context.RandomCS = random.ToArray();
+
+ // Server Random + Client Random
+ random.Reset();
+ random.Write(this.Session.Context.ServerRandom);
+ random.Write(this.Session.Context.ClientRandom);
+
+ this.Session.Context.RandomSC = random.ToArray();
+ random.Reset();
}
#endregion
protected override void ProcessAsSsl3()
{
- throw new NotSupportedException();
+ #warning "Check that the protocol sent by the server is supported"
+ // Read protocol version
+ this.protocol = (TlsProtocol)this.ReadInt16();
+
+ // Read random - Unix time + Random bytes
+ this.random = this.ReadBytes(32);
+
+ // Read Session id
+ int length = (int)ReadByte();
+ if (length > 0)
+ {
+ this.sessionId = this.ReadBytes(length);
+ }
+
+ // Read cipher suite
+ short cipherCode = this.ReadInt16();
+ if (this.Session.Context.SupportedCiphers.IndexOf(cipherCode) == -1)
+ {
+ // The server has sent an invalid ciphersuite
+ throw new TlsException("Invalid cipher suite received from server");
+ }
+ this.cipherSuite = this.Session.Context.SupportedCiphers[cipherCode];
+
+ // Read compression methods ( always 0 )
+ this.compressionMethod = (TlsCompressionMethod)this.ReadByte();
}
protected override void ProcessAsTls1()
// Read cipher suite
short cipherCode = this.ReadInt16();
- if (this.Session.SupportedCiphers.IndexOf(cipherCode) == -1)
+ if (this.Session.Context.SupportedCiphers.IndexOf(cipherCode) == -1)
{
// The server has sent an invalid ciphersuite
throw new TlsException("Invalid cipher suite received from server");
}
- this.cipherSuite = this.Session.SupportedCiphers[cipherCode];
+ this.cipherSuite = this.Session.Context.SupportedCiphers[cipherCode];
// Read compression methods ( always 0 )
this.compressionMethod = (TlsCompressionMethod)this.ReadByte();
{
base.UpdateSession();
- Session.HelloDone = true;
+ this.Session.Context.HelloDone = true;
}
#endregion
protected override void ProcessAsTls1()
{
- rsaParams = new RSAParameters();
+ this.rsaParams = new RSAParameters();
// Read modulus
- short length = ReadInt16();
- rsaParams.Modulus = ReadBytes(length);
+ short length = this.ReadInt16();
+ rsaParams.Modulus = this.ReadBytes(length);
// Read exponent
- length = ReadInt16();
- rsaParams.Exponent = ReadBytes(length);
+ length = this.ReadInt16();
+ rsaParams.Exponent = this.ReadBytes(length);
// Read signed params
- length = ReadInt16();
- signedParams = ReadBytes(length);
+ length = this.ReadInt16();
+ signedParams = this.ReadBytes(length);
}
#endregion
// Create server params array
TlsStream stream = new TlsStream();
- stream.Write(Session.Context.ClientRandom);
- stream.Write(Session.Context.ServerRandom);
+ stream.Write(this.Session.Context.RandomCS);
stream.Write(rsaParams.Modulus.Length);
stream.Write(rsaParams.Modulus);
stream.Write(rsaParams.Exponent.Length);
#endregion
+ #region PROPERTIES
+
+ internal byte[] Messages
+ {
+ get { return messages.ToArray(); }
+ }
+
+ #endregion
+
#region CONSTRUCTORS
public TlsHandshakeHashes()
CertificateVerify = 15,
ClientKeyExchange = 16,
Finished = 20,
- Unknown = 255
}
}
+2003-10-23 Carlos Guzmán Álvarez <carlosga@telefonica.net>
+
+ * Added partial implementation of SSL3 protocol ( not finished yet ).
+
+ * TlsAbstractCipherSuite.cs: Renamed to CipherSuite.cs.
+
+ * Removed AssemblyInfo.cs file.
+
2003-10-21 Carlos Guzmán Álvarez <carlosga@telefonica.net>
TlsCipherSuiteFactory.cs: Changed names of private methods.
namespace Mono.Security.Protocol.Tls
{
- internal class TlsCipherSuite : TlsAbstractCipherSuite
+ internal class TlsCipherSuite : CipherSuite
{
#region CONSTRUCTORS
#endregion
- #region METHODS
+ #region MAC_GENERATION_METHOD
- public override byte[] EncryptRecord(byte[] fragment, byte[] mac)
+ public override byte[] ComputeServerRecordMAC(TlsContentType contentType, byte[] fragment)
{
- // Encryption ( fragment + mac [+ padding + padding_length] )
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, encryptionCipher, CryptoStreamMode.Write);
+ TlsStream data = new TlsStream();
+ byte[] result = null;
- cs.Write(fragment, 0, fragment.Length);
- cs.Write(mac, 0, mac.Length);
- if (cipherMode == CipherMode.CBC)
- {
- // Calculate padding_length
- int fragmentLength = fragment.Length + mac.Length + 1;
- int paddingLength = (((fragmentLength/blockSize)*blockSize) + blockSize) - fragmentLength;
+ data.Write(this.Context.ReadSequenceNumber);
+ data.Write((byte)contentType);
+ data.Write((short)this.Context.Protocol);
+ data.Write((short)fragment.Length);
+ data.Write(fragment);
- // Write padding length byte
- cs.WriteByte((byte)paddingLength);
- }
- //cs.FlushFinalBlock();
- cs.Close();
+ result = this.ServerHMAC.ComputeHash(data.ToArray());
+
+ data.Reset();
- return ms.ToArray();
+ return result;
}
- public override void DecryptRecord(byte[] fragment, ref byte[] dcrFragment, ref byte[] dcrMAC)
+ public override byte[] ComputeClientRecordMAC(TlsContentType contentType, byte[] fragment)
{
- int fragmentSize = 0;
- int paddingLength = 0;
+ TlsStream data = new TlsStream();
+ byte[] result = null;
- // Decrypt message fragment ( fragment + mac [+ padding + padding_length] )
- byte[] buffer = new byte[fragment.Length];
- decryptionCipher.TransformBlock(fragment, 0, fragment.Length, buffer, 0);
+ data.Write(this.Context.WriteSequenceNumber);
+ data.Write((byte)contentType);
+ data.Write((short)this.Context.Protocol);
+ data.Write((short)fragment.Length);
+ data.Write(fragment);
- // Calculate fragment size
- if (cipherMode == CipherMode.CBC)
- {
- // Calculate padding_length
- paddingLength = buffer[buffer.Length - 1];
- 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;
- }
+ result = this.ClientHMAC.ComputeHash(data.ToArray());
- dcrFragment = new byte[fragmentSize];
- dcrMAC = new byte[HashSize];
+ data.Reset();
- Buffer.BlockCopy(buffer, 0, dcrFragment, 0, dcrFragment.Length);
- Buffer.BlockCopy(buffer, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);
+ return result;
}
#endregion
#region KEY_GENERATION_METODS
- public override void CreateMasterSecret(byte[] preMasterSecret)
+ public override void ComputeMasterSecret(byte[] preMasterSecret)
{
- TlsStream seed = new TlsStream();
-
- // Seed
- seed.Write(context.ClientRandom);
- seed.Write(context.ServerRandom);
-
// Create master secret
- context.MasterSecret = new byte[preMasterSecret.Length];
- context.MasterSecret = PRF(preMasterSecret, "master secret", seed.ToArray(), 48);
-
- seed.Reset();
+ this.Context.MasterSecret = new byte[preMasterSecret.Length];
+ this.Context.MasterSecret = this.PRF(
+ preMasterSecret, "master secret", this.Context.RandomCS, 48);
}
- public override void CreateKeys()
+ public override void ComputeKeys()
{
- TlsStream seed = new TlsStream();
-
- // Seed
- seed.Write(context.ServerRandom);
- seed.Write(context.ClientRandom);
-
// Create keyblock
TlsStream keyBlock = new TlsStream(
- PRF(this.Context.MasterSecret,
+ this.PRF(
+ this.Context.MasterSecret,
"key expansion",
- seed.ToArray(),
+ this.Context.RandomSC,
this.KeyBlockSize));
this.Context.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize);
}
else
{
- // Seed
- seed.Reset();
- seed.Write(this.Context.ClientRandom);
- seed.Write(this.Context.ServerRandom);
-
// Generate final write keys
- byte[] finalClientWriteKey = PRF(this.Context.ClientWriteKey, "client write key", seed.ToArray(), this.KeyMaterialSize);
- byte[] finalServerWriteKey = PRF(this.Context.ServerWriteKey, "server write key", seed.ToArray(), this.KeyMaterialSize);
+ byte[] finalClientWriteKey = PRF(this.Context.ClientWriteKey, "client write key", this.Context.RandomCS, this.KeyMaterialSize);
+ byte[] finalServerWriteKey = PRF(this.Context.ServerWriteKey, "server write key", this.Context.RandomCS, this.KeyMaterialSize);
this.Context.ClientWriteKey = finalClientWriteKey;
this.Context.ServerWriteKey = finalServerWriteKey;
// Generate IV block
- byte[] ivBlock = PRF(new byte[]{}, "IV block", seed.ToArray(), this.IvSize*2);
+ byte[] ivBlock = PRF(new byte[]{}, "IV block", this.Context.RandomCS, this.IvSize*2);
// Generate IV keys
this.Context.ClientWriteIV = new byte[this.IvSize];
System.Array.Copy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length);
+
this.Context.ServerWriteIV = new byte[this.IvSize];
System.Array.Copy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length);
}
// Clear no more needed data
- seed.Reset();
keyBlock.Reset();
}
{
internal sealed class TlsCipherSuiteCollection : ArrayList
{
+ #region FIELDS
+
+ private TlsProtocol protocol;
+
+ #endregion
+
#region PROPERTIES
- public TlsCipherSuite this[string name]
+ public CipherSuite this[string name]
+ {
+ get { return (CipherSuite)this[IndexOf(name)]; }
+ set { this[IndexOf(name)] = (CipherSuite)value; }
+ }
+
+ public CipherSuite this[short code]
{
- get { return (TlsCipherSuite)this[IndexOf(name)]; }
- set { this[IndexOf(name)] = (TlsCipherSuite)value; }
+ get { return (CipherSuite)base[IndexOf(code)]; }
+ set { base[IndexOf(code)] = (CipherSuite)value; }
}
- public TlsCipherSuite this[short code]
+ public new CipherSuite this[int code]
{
- get { return (TlsCipherSuite)base[IndexOf(code)]; }
- set { base[IndexOf(code)] = (TlsCipherSuite)value; }
+ get { return (CipherSuite)base[code]; }
+ set { base[code] = (CipherSuite)value; }
}
- public new TlsCipherSuite this[int code]
+ #endregion
+
+ #region CONSTRUCTORS
+
+ public TlsCipherSuiteCollection(TlsProtocol protocol) : base()
{
- get { return (TlsCipherSuite)base[code]; }
- set { base[code] = (TlsCipherSuite)value; }
+ this.protocol = protocol;
}
#endregion
public int IndexOf(string name)
{
int index = 0;
- foreach(TlsCipherSuite suite in this)
+ foreach (CipherSuite suite in this)
{
if (cultureAwareCompare(suite.Name, name))
{
public int IndexOf(short code)
{
int index = 0;
- foreach(TlsCipherSuite suite in this)
+ foreach (CipherSuite suite in this)
{
if (suite.Code == code)
{
RemoveAt(IndexOf(errorMessage));
}
- public TlsCipherSuite Add(TlsCipherSuite cipherSuite)
+ public CipherSuite Add(short code, string name, string algName, string hashName, bool exportable, bool blockMode, byte keyMaterialSize, byte expandedKeyMaterialSize, short effectiveKeyBytes, byte ivSize, byte blockSize)
+ {
+ switch (this.protocol)
+ {
+ case TlsProtocol.Tls1:
+ return this.add(
+ new TlsCipherSuite(code, name, algName, hashName, exportable, blockMode, keyMaterialSize, expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize));
+
+ case TlsProtocol.Ssl3:
+ return this.add(
+ new TlsSslCipherSuite(code, name, algName, hashName, exportable, blockMode, keyMaterialSize, expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize));
+
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ private TlsCipherSuite add(TlsCipherSuite cipherSuite)
{
base.Add(cipherSuite);
return cipherSuite;
}
- public TlsCipherSuite Add(short code, string name, string algName, string hashName, bool exportable, bool blockMode, byte keyMaterialSize, byte expandedKeyMaterialSize, short effectiveKeyBytes, byte ivSize, byte blockSize)
+ private TlsSslCipherSuite add(TlsSslCipherSuite cipherSuite)
{
- TlsCipherSuite cipherSuite = new TlsCipherSuite(code, name, algName, hashName, exportable, blockMode, keyMaterialSize, expandedKeyMaterialSize, effectiveKeyBytes, ivSize, blockSize);
+ base.Add(cipherSuite);
- return Add(cipherSuite);
+ return cipherSuite;
}
private bool cultureAwareCompare(string strA, string strB)
private static TlsCipherSuiteCollection GetTls1SupportedCiphers()
{
- TlsCipherSuiteCollection scs = new TlsCipherSuiteCollection();
+ TlsCipherSuiteCollection scs = new TlsCipherSuiteCollection(TlsProtocol.Tls1);
// Supported ciphers
scs.Add((0x00 << 0x08) | 0x35, "TLS_RSA_WITH_AES_256_CBC_SHA", "Rijndael", "SHA", false, true, 32, 32, 256, 16, 16);
private static TlsCipherSuiteCollection GetSsl3SupportedCiphers()
{
- TlsCipherSuiteCollection scs = new TlsCipherSuiteCollection();
+ TlsCipherSuiteCollection scs = new TlsCipherSuiteCollection(TlsProtocol.Ssl3);
// Supported ciphers
scs.Add((0x00 << 0x08) | 0x0A, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "3DES", "SHA", false, true, 24, 24, 168, 8, 8);
Alert = 21,
Handshake = 22,
ApplicationData = 23,
- Unknown = 255
}
}
private byte[] sessionId;
private TlsSessionContext context;
- private bool helloDone;
- private bool handshakeFinished;
private TlsSessionSettings settings;
- private TlsCipherSuiteCollection supportedCiphers;
private TlsSocket socket;
private TlsNetworkStream networkStream;
private bool isSecure;
get { return context; }
}
- internal TlsCipherSuiteCollection SupportedCiphers
- {
- get { return supportedCiphers; }
- }
-
- internal bool HelloDone
- {
- get { return helloDone; }
- set { helloDone = value; }
- }
-
- internal bool HandshakeFinished
- {
- get { return handshakeFinished; }
- set { handshakeFinished = value; }
- }
-
internal bool IsSecure
{
get { return isSecure; }
{
this.context.Protocol = settings.Protocol;
this.context.CompressionMethod = settings.CompressionMethod;
- this.state = TlsSessionState.OpeningSecure;
- this.supportedCiphers = TlsCipherSuiteFactory.GetSupportedCiphers(context.Protocol);
+ this.context.SupportedCiphers = TlsCipherSuiteFactory.GetSupportedCiphers(context.Protocol);
+ this.state = TlsSessionState.OpeningSecure;
this.socket.DoHandshake();
- this.state = TlsSessionState.OpenSecure;
+ this.state = TlsSessionState.OpenSecure;
}
catch (TlsException ex)
{
// Reset session information
this.isSecure = false;
- this.helloDone = false;
- this.handshakeFinished = false;
this.context = new TlsSessionContext();
this.sessionId = new byte[0];
}
// Information sent and request by the server in the Handshake protocol
private TlsServerSettings serverSettings;
+ // Cipher suite information
+ private CipherSuite cipher;
+ private TlsCipherSuiteCollection supportedCiphers;
+
// Misc
private bool isActual;
+ private bool helloDone;
+ private bool handshakeFinished;
private bool connectionEnd;
- private TlsCipherSuite cipher;
-
+
// Sequence numbers
private long writeSequenceNumber;
private long readSequenceNumber;
// Random data
private byte[] clientRandom;
private byte[] serverRandom;
+ private byte[] randomCS;
+ private byte[] randomSC;
// Key information
private byte[] masterSecret;
public TlsProtocol Protocol
{
- get { return protocol; }
- set { protocol = value; }
+ get { return this.protocol; }
+ set { this.protocol = value; }
}
public TlsCompressionMethod CompressionMethod
{
- get { return compressionMethod; }
- set { compressionMethod = value; }
+ get { return this.compressionMethod; }
+ set { this.compressionMethod = value; }
}
public TlsServerSettings ServerSettings
{
- get { return serverSettings; }
- set { serverSettings = value; }
+ get { return this.serverSettings; }
+ set { this.serverSettings = value; }
}
public bool IsActual
{
- get { return isActual; }
- set { isActual = value; }
+ get { return this.isActual; }
+ set { this.isActual = value; }
+ }
+
+ public bool HelloDone
+ {
+ get { return helloDone; }
+ set { helloDone = value; }
+ }
+
+ public bool HandshakeFinished
+ {
+ get { return handshakeFinished; }
+ set { handshakeFinished = value; }
}
public bool ConnectionEnd
{
- get { return connectionEnd; }
- set { connectionEnd = value; }
+ get { return this.connectionEnd; }
+ set { this.connectionEnd = value; }
}
- public TlsCipherSuite Cipher
+ public CipherSuite Cipher
{
- get { return cipher; }
- set { cipher = value; }
+ get { return this.cipher; }
+ set { this.cipher = value; }
+ }
+
+ public TlsCipherSuiteCollection SupportedCiphers
+ {
+ get { return supportedCiphers; }
+ set { supportedCiphers = value; }
}
public TlsHandshakeHashes HandshakeHashes
{
- get { return handshakeHashes; }
+ get { return this.handshakeHashes; }
}
public long WriteSequenceNumber
{
- get { return writeSequenceNumber; }
- set { writeSequenceNumber = value; }
+ get { return this.writeSequenceNumber; }
+ set { this.writeSequenceNumber = value; }
}
public long ReadSequenceNumber
{
- get { return readSequenceNumber; }
- set { readSequenceNumber = value; }
+ get { return this.readSequenceNumber; }
+ set { this.readSequenceNumber = value; }
}
public byte[] ClientRandom
{
- get { return clientRandom; }
- set { clientRandom = value; }
+ get { return this.clientRandom; }
+ set { this.clientRandom = value; }
}
public byte[] ServerRandom
{
- get { return serverRandom; }
- set { serverRandom = value; }
+ get { return this.serverRandom; }
+ set { this.serverRandom = value; }
+ }
+
+ public byte[] RandomCS
+ {
+ get { return this.randomCS; }
+ set { this.randomCS = value; }
+ }
+
+ public byte[] RandomSC
+ {
+ get { return this.randomSC; }
+ set { this.randomSC = value; }
}
public byte[] MasterSecret
{
- get { return masterSecret; }
- set { masterSecret = value; }
+ get { return this.masterSecret; }
+ set { this.masterSecret = value; }
}
public byte[] ClientWriteMAC
{
- get { return clientWriteMAC; }
- set { clientWriteMAC = value; }
+ get { return this.clientWriteMAC; }
+ set { this.clientWriteMAC = value; }
}
public byte[] ServerWriteMAC
{
- get { return serverWriteMAC; }
- set { serverWriteMAC = value; }
+ get { return this.serverWriteMAC; }
+ set { this.serverWriteMAC = value; }
}
public byte[] ClientWriteKey
{
- get { return clientWriteKey; }
- set { clientWriteKey = value; }
+ get { return this.clientWriteKey; }
+ set { this.clientWriteKey = value; }
}
public byte[] ServerWriteKey
{
- get { return serverWriteKey; }
- set { serverWriteKey = value; }
+ get { return this.serverWriteKey; }
+ set { this.serverWriteKey = value; }
}
public byte[] ClientWriteIV
{
- get { return clientWriteIV; }
- set { clientWriteIV = value; }
+ get { return this.clientWriteIV; }
+ set { this.clientWriteIV = value; }
}
public byte[] ServerWriteIV
{
- get { return serverWriteIV; }
- set { serverWriteIV = value; }
+ get { return this.serverWriteIV; }
+ set { this.serverWriteIV = value; }
}
#endregion
public void ClearKeyInfo()
{
// Clear Master Secret
- masterSecret = null;
+ this.masterSecret = null;
// Clear client and server random
- clientRandom = null;
- serverRandom = null;
+ this.clientRandom = null;
+ this.serverRandom = null;
+ this.randomCS = null;
+ this.randomSC = null;
// Clear client keys
- clientWriteKey = null;
- clientWriteIV = null;
- clientWriteMAC = null;
+ this.clientWriteKey = null;
+ this.clientWriteIV = null;
+ this.clientWriteMAC = null;
// Clear server keys
- serverWriteKey = null;
- serverWriteIV = null;
- serverWriteMAC = null;
-
- // Force the GC to recollect the memory ??
+ this.serverWriteKey = null;
+ this.serverWriteIV = null;
+ this.serverWriteMAC = null;
}
#endregion
get { return protocol; }
set
{
- if (value != TlsProtocol.Tls1)
+ if (value != TlsProtocol.Tls1 &&
+ value != TlsProtocol.Ssl3)
{
throw new NotSupportedException("Specified protocol is not supported");
}
internal BufferedStream InputBuffer
{
- get { return inputBuffer; }
+ get { return this.inputBuffer; }
}
#endregion
public new int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags)
{
- if (!session.IsSecure)
+ if (!this.session.IsSecure)
{
return base.Receive(buffer, offset, size, socketFlags);
}
// If actual buffer is full readed reset it
- if (inputBuffer.Position == inputBuffer.Length)
+ if (this.inputBuffer.Position == this.inputBuffer.Length)
{
this.resetBuffer();
}
// Check if we have space in the middle buffer
// if not Read next TLS record and update the inputBuffer
- while ((inputBuffer.Length - inputBuffer.Position) < size)
+ while ((this.inputBuffer.Length - this.inputBuffer.Position) < size)
{
// Read next record and write it into the inputBuffer
- long position = inputBuffer.Position;
+ long position = this.inputBuffer.Position;
byte[] record = this.receiveRecord();
if (record.Length > 0)
{
// Write new data to the inputBuffer
- inputBuffer.Seek(0, SeekOrigin.End);
- inputBuffer.Write(record, 0, record.Length);
+ this.inputBuffer.Seek(0, SeekOrigin.End);
+ this.inputBuffer.Write(record, 0, record.Length);
// Restore buffer position
- inputBuffer.Seek(position, SeekOrigin.Begin);
+ this.inputBuffer.Seek(position, SeekOrigin.Begin);
}
if (base.Available == 0)
}
}
- return inputBuffer.Read(buffer, offset, size);
+ return this.inputBuffer.Read(buffer, offset, size);
}
public new int Send(byte[] buffer)
public new int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags)
{
- if (!session.IsSecure)
+ if (!this.session.IsSecure)
{
return base.Send(buffer, offset, size, socketFlags);
}
private byte[] receiveRecord()
{
- if (session.Context.ConnectionEnd)
+ if (this.session.Context.ConnectionEnd)
{
- throw session.CreateException("The session is finished and it's no longer valid.");
+ throw this.session.CreateException("The session is finished and it's no longer valid.");
}
TlsContentType contentType = (TlsContentType)this.ReadByte();
TlsProtocol protocol = (TlsProtocol)this.ReadShort();
- int length = this.ReadShort();
+ short length = this.ReadShort();
// Read Record data
int received = 0;
buffer, received, buffer.Length - received, SocketFlags.None);
}
- TlsStream message = new TlsStream(buffer);
+ TlsStream message = new TlsStream(buffer);
- // Check that the message as a valid protocol version
- if (protocol != session.Context.Protocol)
+ // Check that the message has a valid protocol version
+ if (protocol != this.session.Context.Protocol)
{
throw session.CreateException("Invalid protocol version on message received from server");
}
// Decrypt message contents if needed
- if (contentType == TlsContentType.Alert &&
- length == 2)
+ if (contentType == TlsContentType.Alert && length == 2)
{
}
else
if (session.Context.IsActual &&
contentType != TlsContentType.ChangeCipherSpec)
{
- message = decryptRecordFragment(
+ message = this.decryptRecordFragment(
contentType,
- protocol,
+ protocol,
message.ToArray());
}
}
switch (contentType)
{
case TlsContentType.Alert:
- processAlert((TlsAlertLevel)message.ReadByte(),
+ this.processAlert((TlsAlertLevel)message.ReadByte(),
(TlsAlertDescription)message.ReadByte());
break;
case TlsContentType.ChangeCipherSpec:
// Reset sequence numbers
- session.Context.ReadSequenceNumber = 0;
+ this.session.Context.ReadSequenceNumber = 0;
break;
case TlsContentType.ApplicationData:
case TlsContentType.Handshake:
while (!message.EOF)
{
- processHandshakeMessage(message);
+ this.processHandshakeMessage(message);
}
// Update handshakes of current messages
this.session.Context.HandshakeHashes.Update(message.ToArray());
private byte[] encryptRecordFragment(TlsContentType contentType, byte[] fragment)
{
// Calculate message MAC
- byte[] mac = encodeClientRecordMAC(contentType, fragment);
+ byte[] mac = this.session.Context.Cipher.ComputeClientRecordMAC(contentType, fragment);
// Encrypt the message
- byte[] ecr = session.Context.Cipher.EncryptRecord(fragment, mac);
+ byte[] ecr = this.session.Context.Cipher.EncryptRecord(fragment, mac);
// Set new IV
- if (session.Context.Cipher.CipherMode == CipherMode.CBC)
+ if (this.session.Context.Cipher.CipherMode == CipherMode.CBC)
{
- byte[] iv = new byte[session.Context.Cipher.IvSize];
+ byte[] iv = new byte[this.session.Context.Cipher.IvSize];
System.Array.Copy(ecr, ecr.Length - iv.Length, iv, 0, iv.Length);
- session.Context.Cipher.UpdateClientCipherIV(iv);
+ this.session.Context.Cipher.UpdateClientCipherIV(iv);
}
// Update sequence number
- session.Context.WriteSequenceNumber++;
+ this.session.Context.WriteSequenceNumber++;
return ecr;
}
byte[] dcrMAC = null;
// Decrypt message
- session.Context.Cipher.DecryptRecord(fragment, ref dcrFragment, ref dcrMAC);
+ this.session.Context.Cipher.DecryptRecord(fragment, ref dcrFragment, ref dcrMAC);
// Set new IV
- if (session.Context.Cipher.CipherMode == CipherMode.CBC)
+ if (this.session.Context.Cipher.CipherMode == CipherMode.CBC)
{
byte[] iv = new byte[session.Context.Cipher.IvSize];
System.Array.Copy(fragment, fragment.Length - iv.Length, iv, 0, iv.Length);
- session.Context.Cipher.UpdateServerCipherIV(iv);
+ this.session.Context.Cipher.UpdateServerCipherIV(iv);
}
// Check MAC code
- byte[] mac = this.encodeServerRecordMAC(contentType, dcrFragment);
+ byte[] mac = this.session.Context.Cipher.ComputeServerRecordMAC(contentType, dcrFragment);
// Check that the mac is correct
if (mac.Length != dcrMAC.Length)
}
// Update sequence number
- session.Context.ReadSequenceNumber++;
+ this.session.Context.ReadSequenceNumber++;
return new TlsStream(dcrFragment);
}
int bytesSent = this.sendRecord(TlsContentType.ChangeCipherSpec, new byte[] {1});
// Reset sequence numbers
- session.Context.WriteSequenceNumber = 0;
+ this.session.Context.WriteSequenceNumber = 0;
// Make the pending state to be the current state
- session.Context.IsActual = true;
+ this.session.Context.IsActual = true;
// Send Finished message
bytesSent += this.sendRecord(TlsHandshakeType.Finished);
private int sendRecord(TlsContentType contentType, byte[] recordData)
{
- if (session.Context.ConnectionEnd)
+ if (this.session.Context.ConnectionEnd)
{
- throw session.CreateException("The session is finished and it's no longer valid.");
+ throw this.session.CreateException("The session is finished and it's no longer valid.");
}
int bytesSent = 0;
{
byte[] fragment = fragments[i];
- if (session.Context.IsActual)
+ if (this.session.Context.IsActual)
{
// Encrypt fragment
- fragment = encryptRecordFragment(contentType, fragment);
+ fragment = this.encryptRecordFragment(contentType, fragment);
}
// Write tls message
TlsStream record = new TlsStream();
record.Write((byte)contentType);
- record.Write((short)TlsProtocol.Tls1);
+ record.Write((short)this.session.Context.Protocol);
record.Write((short)fragment.Length);
record.Write(fragment);
handMsg.Read(data, 0, length);
// Create and process the server message
- message = createServerHandshakeMessage(handshakeType, data);
+ message = this.createServerHandshakeMessage(handshakeType, data);
// Update session
if (message != null)
}
}
- private void processAlert(TlsAlertLevel alertLevel,
- TlsAlertDescription alertDesc)
+ private void processAlert(TlsAlertLevel alertLevel, TlsAlertDescription alertDesc)
{
switch (alertLevel)
{
case TlsAlertLevel.Fatal:
- throw session.CreateException(alertLevel, alertDesc);
+ throw this.session.CreateException(alertLevel, alertDesc);
case TlsAlertLevel.Warning:
default:
switch (alertDesc)
{
case TlsAlertDescription.CloseNotify:
- session.Context.ConnectionEnd = true;
+ this.session.Context.ConnectionEnd = true;
break;
default:
- session.RaiseWarningAlert(alertLevel, alertDesc);
+ this.session.RaiseWarningAlert(alertLevel, alertDesc);
break;
}
- break;
+ break;
}
}
this.inputBuffer.Position = 0;
}
- private byte[] encodeServerRecordMAC(TlsContentType contentType, byte[] fragment)
- {
- TlsStream data = new TlsStream();
- byte[] result = null;
-
- data.Write(session.Context.ReadSequenceNumber);
- data.Write((byte)contentType);
- data.Write((short)TlsProtocol.Tls1);
- data.Write((short)fragment.Length);
- data.Write(fragment);
-
- result = session.Context.Cipher.ServerHMAC.ComputeHash(data.ToArray());
-
- data.Reset();
-
- return result;
- }
-
- private byte[] encodeClientRecordMAC(TlsContentType contentType, byte[] fragment)
- {
- TlsStream data = new TlsStream();
- byte[] result = null;
-
- data.Write(session.Context.WriteSequenceNumber);
- data.Write((byte)contentType);
- data.Write((short)TlsProtocol.Tls1);
- data.Write((short)fragment.Length);
- data.Write(fragment);
-
- result = session.Context.Cipher.ClientHMAC.ComputeHash(data.ToArray());
-
- data.Reset();
-
- return result;
- }
-
private byte ReadByte()
{
byte[] b = new byte[1];
this.sendRecord(TlsHandshakeType.ClientHello);
// Read server response
- while (!session.HelloDone)
+ while (!this.session.Context.HelloDone)
{
// Read next record
this.receiveRecord();
}
// Send client certificate if requested
- if (session.Context.ServerSettings.CertificateRequest)
+ if (this.session.Context.ServerSettings.CertificateRequest)
{
this.sendRecord(TlsHandshakeType.Certificate);
}
this.session.Context.Cipher.InitializeCipher();
// Send certificate verify if requested
- if (session.Context.ServerSettings.CertificateRequest)
+ if (this.session.Context.ServerSettings.CertificateRequest)
{
this.sendRecord(TlsHandshakeType.CertificateVerify);
}
this.receiveRecord();
// Read server finished
- if (!session.HandshakeFinished)
+ if (!this.session.Context.HandshakeFinished)
{
this.receiveRecord();
}
return new TlsServerFinished(session, buffer);
default:
- throw session.CreateException("Unknown server handshake message received ({0})", type.ToString());
+ throw this.session.CreateException("Unknown server handshake message received ({0})", type.ToString());
}
}
namespace Mono.Security.Protocol.Tls
{
- internal class TlsSslCipherSuite : TlsAbstractCipherSuite
+ internal class TlsSslCipherSuite : CipherSuite
{
+ #region FIELDS
+
+ private byte[] pad1;
+ private byte[] pad2;
+
+ #endregion
+
+ #region PROPERTIES
+
+ public byte[] Pad1
+ {
+ get { return pad1; }
+ }
+
+ public byte[] Pad2
+ {
+ get { return pad2; }
+ }
+
+ #endregion
+
#region CONSTRUCTORS
public TlsSslCipherSuite(short code, string name, string algName,
keyMaterialSize, expandedKeyMaterialSize, effectiveKeyBytes,
ivSize, blockSize)
{
+ this.GeneratePad(hashName, ref this.pad1, ref this.pad2);
}
#endregion
- #region METHODS
+ #region MAC_GENERATION_METHOD
- public override byte[] EncryptRecord(byte[] fragment, byte[] mac)
+ public override byte[] ComputeServerRecordMAC(TlsContentType contentType, byte[] fragment)
{
- // Encryption ( fragment + mac [+ padding + padding_length] )
- MemoryStream ms = new MemoryStream();
- CryptoStream cs = new CryptoStream(ms, encryptionCipher, CryptoStreamMode.Write);
+ HashAlgorithm hash = HashAlgorithm.Create(this.HashName);
+ TlsStream block = new TlsStream();
+
+ block.Write(this.Context.ServerWriteMAC);
+ block.Write(this.pad1);
+ block.Write(this.Context.ReadSequenceNumber);
+ block.Write((byte)contentType);
+ block.Write((short)fragment.Length);
+ block.Write(fragment);
+
+ byte[] blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ block.Write(this.Context.ServerWriteMAC);
+ block.Write(this.pad2);
+ block.Write(blockHash);
- cs.Write(fragment, 0, fragment.Length);
- cs.Write(mac, 0, mac.Length);
- if (cipherMode == CipherMode.CBC)
+ blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ return blockHash;
+ }
+
+ public override byte[] ComputeClientRecordMAC(TlsContentType contentType, byte[] fragment)
+ {
+ HashAlgorithm hash = HashAlgorithm.Create(this.HashName);
+ TlsStream block = new TlsStream();
+
+ block.Write(this.Context.ClientWriteMAC);
+ block.Write(this.pad1);
+ block.Write(this.Context.WriteSequenceNumber);
+ block.Write((byte)contentType);
+ block.Write((short)fragment.Length);
+ block.Write(fragment);
+
+ byte[] blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ block.Write(this.Context.ClientWriteMAC);
+ block.Write(this.pad2);
+ block.Write(blockHash);
+
+ blockHash = hash.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ return blockHash;
+ }
+
+ public void GeneratePad(string hashName, ref byte[] pad1, ref byte[] pad2)
+ {
+ switch (hashName)
{
- // Calculate padding_length
- int fragmentLength = fragment.Length + mac.Length + 1;
- int paddingLength = (((fragmentLength/blockSize)*8) + blockSize) - fragmentLength;
+ case "MD5":
+ pad1 = new byte[48];
+ pad2 = new byte[48];
+ break;
- // Write padding length byte
- cs.WriteByte((byte)paddingLength);
+ case "SHA":
+ case "SHA1":
+ pad1 = new byte[40];
+ pad2 = new byte[40];
+ break;
}
- //cs.FlushFinalBlock();
- cs.Close();
- return ms.ToArray();
+ for (int i = 0; i < pad1.Length; i++)
+ {
+ pad1[i] = (byte)0x36;
+ pad2[i] = (byte)0x5C;
+ }
}
- public override void DecryptRecord(byte[] fragment, ref byte[] dcrFragment, ref byte[] dcrMAC)
+ #endregion
+
+ #region KEY_GENERATION_METODS
+
+ public override void ComputeMasterSecret(byte[] preMasterSecret)
{
- int fragmentSize = 0;
- int paddingLength = 0;
+ TlsStream masterSecret = new TlsStream();
+
+ masterSecret.Write(this.prf(preMasterSecret, "A", this.Context.RandomCS));
+ masterSecret.Write(this.prf(preMasterSecret, "BB", this.Context.RandomCS));
+ masterSecret.Write(this.prf(preMasterSecret, "CCC", this.Context.RandomCS));
- // Decrypt message fragment ( fragment + mac [+ padding + padding_length] )
- byte[] buffer = new byte[fragment.Length];
- decryptionCipher.TransformBlock(fragment, 0, fragment.Length, buffer, 0);
+ this.Context.MasterSecret = masterSecret.ToArray();
+ }
- // Calculate fragment size
- if (cipherMode == CipherMode.CBC)
+ public override void ComputeKeys()
+ {
+ // Compute KeyBlock
+ TlsStream tmp = new TlsStream();
+
+ char labelChar = 'A';
+ int count = 1;
+ while (tmp.Length < this.KeyBlockSize)
{
- // Calculate padding_length
- paddingLength = buffer[buffer.Length - 1];
- for (int i = (buffer.Length - 1); i > (buffer.Length - (paddingLength + 1)); i--)
+ string label = String.Empty;
+
+ for (int i = 0; i < count; i++)
{
- if (buffer[i] != paddingLength)
- {
- paddingLength = 0;
- break;
- }
+ label += labelChar.ToString();
}
+
+ byte[] block = this.prf(this.Context.MasterSecret, label.ToString(), this.Context.RandomSC);
+
+ int size = (tmp.Length + block.Length) > this.KeyBlockSize ? (this.KeyBlockSize - (int)tmp.Length) : block.Length;
+
+ tmp.Write(block, 0, size);
- fragmentSize = (buffer.Length - (paddingLength + 1)) - HashSize;
+ labelChar++;
+ count++;
}
- else
+
+ // Create keyblock
+ TlsStream keyBlock = new TlsStream(tmp.ToArray());
+
+ this.Context.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize);
+ this.Context.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize);
+ this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
+ this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize);
+
+ if (!this.IsExportable)
{
- fragmentSize = buffer.Length - HashSize;
+ if (this.IvSize != 0)
+ {
+ this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize);
+ this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize);
+ }
+ else
+ {
+ this.Context.ClientWriteIV = new byte[0];
+ this.Context.ServerWriteIV = new byte[0];
+ }
}
+ else
+ {
+ MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
- dcrFragment = new byte[fragmentSize];
- dcrMAC = new byte[HashSize];
+ // Generate final write keys
+ byte[] finalClientWriteKey = new byte[md5.HashSize];
+ md5.TransformBlock(this.Context.ClientWriteKey, 0, this.Context.ClientWriteKey.Length, finalClientWriteKey, 0);
+ finalClientWriteKey = md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length);
- Buffer.BlockCopy(buffer, 0, dcrFragment, 0, dcrFragment.Length);
- Buffer.BlockCopy(buffer, dcrFragment.Length, dcrMAC, 0, dcrMAC.Length);
+ byte[] finalServerWriteKey = new byte[md5.HashSize];
+ md5.TransformBlock(this.Context.ServerWriteKey, 0, this.Context.ServerWriteKey.Length, finalServerWriteKey, 0);
+ finalClientWriteKey = md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length);
+
+ this.Context.ClientWriteKey = finalClientWriteKey;
+ this.Context.ServerWriteKey = finalServerWriteKey;
+
+ // Generate IV keys
+ this.Context.ClientWriteIV = md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length);
+ this.Context.ServerWriteIV = md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length);
+ }
+
+ // Clear no more needed data
+ keyBlock.Reset();
+ tmp.Reset();
}
#endregion
- #region KEY_GENERATION_METODS
+ #region PRIVATE_METHODS
- public override void CreateMasterSecret(byte[] preMasterSecret)
+ private byte[] prf(byte[] secret, string label, byte[] random)
{
- throw new NotSupportedException();
- }
+ MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
+ SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
- public override void CreateKeys()
- {
- throw new NotSupportedException();
+ // Compute SHA hash
+ TlsStream block = new TlsStream();
+ block.Write(Encoding.ASCII.GetBytes(label));
+ block.Write(secret);
+ block.Write(random);
+
+ byte[] shaHash = sha.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ block.Reset();
+
+ // Compute MD5 hash
+ block.Write(secret);
+ block.Write(shaHash);
+
+ byte[] result = md5.ComputeHash(block.ToArray(), 0, (int)block.Length);
+
+ // Free resources
+ block.Reset();
+
+ return result;
}
#endregion