protected override void ProcessHandshakeMessage(TlsStream handMsg) { HandshakeType handshakeType = (HandshakeType)handMsg.ReadByte(); HandshakeMessage message = null; // Read message length int length = handMsg.ReadInt24(); // Read message data byte[] data = new byte[length]; handMsg.Read(data, 0, length); // Create and process the server message message = this.createClientHandshakeMessage(handshakeType, data); message.Process(); // Update the last handshake message this.Context.LastHandshakeMsg = handshakeType; // Update session if (message != null) { message.Update(); this.Context.HandshakeMessages.WriteByte((byte)handshakeType); this.Context.HandshakeMessages.WriteInt24(length); this.Context.HandshakeMessages.Write(data, 0, data.Length); } }
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]; Buffer.BlockCopy(resMacs.ToArray(), 0, res, 0, res.Length); resMacs.Reset(); return(res); }
private byte[] prf(byte[] secret, string label, byte[] random) { HashAlgorithm md5 = MD5.Create(); HashAlgorithm sha = SHA1.Create(); // 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); }
public byte[] EncodeRecord( ContentType contentType, byte[] recordData, int offset, int count) { if (this.context.SentConnectionEnd) { throw new TlsException( AlertDescription.InternalError, "The session is finished and it's no longer valid."); } TlsStream record = new TlsStream(); int position = offset; while (position < (offset + count)) { short fragmentLength = 0; byte[] fragment; if ((count + offset - position) > Context.MAX_FRAGMENT_SIZE) { fragmentLength = Context.MAX_FRAGMENT_SIZE; } else { fragmentLength = (short)(count + offset - position); } // Fill the fragment data fragment = new byte[fragmentLength]; Buffer.BlockCopy(recordData, position, fragment, 0, fragmentLength); if ((this.Context.Write != null) && (this.Context.Write.Cipher != null)) { // Encrypt fragment fragment = this.encryptRecordFragment(contentType, fragment); } // Write tls message record.Write((byte)contentType); record.Write(this.context.Protocol); record.Write((short)fragment.Length); record.Write(fragment); DebugHelper.WriteLine("Record data", fragment); // Update buffer position position += fragmentLength; } return(record.ToArray()); }
public virtual void Clear() { this.compressionMethod = SecurityCompressionType.None; this.serverSettings = new TlsServerSettings(); this.clientSettings = new TlsClientSettings(); this.handshakeMessages = new TlsStream(); this.sessionId = null; this.handshakeState = HandshakeState.None; this.ClearKeyInfo(); }
public Context(SecurityProtocolType securityProtocolType) { this.SecurityProtocol = securityProtocolType; this.compressionMethod = SecurityCompressionType.None; this.serverSettings = new TlsServerSettings(); this.clientSettings = new TlsClientSettings(); this.handshakeMessages = new TlsStream(); this.sessionId = null; this.handshakeState = HandshakeState.None; this.random = RandomNumberGenerator.Create(); }
public override void ComputeMasterSecret(byte[] preMasterSecret) { 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)); this.Context.MasterSecret = masterSecret.ToArray(); DebugHelper.WriteLine(">>>> MasterSecret", this.Context.MasterSecret); }
public byte[] PRF(byte[] secret, string label, byte[] data, int length) { /* Secret Length calc exmplain from the RFC2246. Section 5 * * S1 and S2 are the two halves of the secret and each is the same * length. S1 is taken from the first half of the secret, S2 from the * second half. Their length is created by rounding up the length of the * overall secret divided by two; thus, if the original secret is an odd * number of bytes long, the last byte of S1 will be the same as the * first byte of S2. */ // split secret in 2 int secretLen = secret.Length >> 1; // rounding up if ((secret.Length & 0x1) == 0x1) { secretLen++; } // Seed TlsStream seedStream = new TlsStream(); seedStream.Write(Encoding.ASCII.GetBytes(label)); seedStream.Write(data); byte[] seed = seedStream.ToArray(); seedStream.Reset(); // Secret 1 byte[] secret1 = new byte[secretLen]; Buffer.BlockCopy(secret, 0, secret1, 0, secretLen); // Secret2 byte[] secret2 = new byte[secretLen]; Buffer.BlockCopy(secret, (secret.Length - secretLen), secret2, 0, secretLen); // Secret 1 processing byte[] p_md5 = Expand("MD5", 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); }
private void ProcessCipherSpecV2Buffer(SecurityProtocolType protocol, byte[] buffer) { TlsStream codes = new TlsStream(buffer); string prefix = (protocol == SecurityProtocolType.Ssl3) ? "SSL_" : "TLS_"; while (codes.Position < codes.Length) { byte check = codes.ReadByte(); if (check == 0) { // SSL/TLS cipher spec short code = codes.ReadInt16(); int index = this.Context.SupportedCiphers.IndexOf(code); if (index != -1) { this.Context.Negotiating.Cipher = this.Context.SupportedCiphers[index]; break; } } else { byte[] tmp = new byte[2]; codes.Read(tmp, 0, tmp.Length); int tmpCode = ((check & 0xff) << 16) | ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff); CipherSuite cipher = this.MapV2CipherCode(prefix, tmpCode); if (cipher != null) { this.Context.Negotiating.Cipher = cipher; break; } } } if (this.Context.Negotiating == null) { throw new TlsException(AlertDescription.InsuficientSecurity, "Insuficient Security"); } }
protected override void ProcessHandshakeMessage(TlsStream handMsg) { HandshakeType handshakeType = (HandshakeType)handMsg.ReadByte(); HandshakeMessage message = null; DebugHelper.WriteLine(">>>> Processing Handshake record ({0})", handshakeType); // Read message length int length = handMsg.ReadInt24(); // Read message data byte[] data = null; if (length > 0) { data = new byte[length]; handMsg.Read(data, 0, length); } // Create and process the server message message = this.createServerHandshakeMessage(handshakeType, data); if (message != null) { message.Process(); } // Update the last handshake message this.Context.LastHandshakeMsg = handshakeType; // Update session if (message != null) { message.Update(); this.Context.HandshakeMessages.WriteByte((byte)handshakeType); this.Context.HandshakeMessages.WriteInt24(length); if (length > 0) { this.Context.HandshakeMessages.Write(data, 0, data.Length); } } }
protected abstract void ProcessHandshakeMessage(TlsStream handMsg);
private void InternalReceiveRecordCallback(IAsyncResult asyncResult) { ReceiveRecordAsyncResult internalResult = asyncResult.AsyncState as ReceiveRecordAsyncResult; Stream record = internalResult.Record; try { int bytesRead = internalResult.Record.EndRead(asyncResult); //We're at the end of the stream. Time to bail. if (bytesRead == 0) { internalResult.SetComplete((byte[])null); return; } // Try to read the Record Content Type int type = internalResult.InitialBuffer[0]; // Set last handshake message received to None this.context.LastHandshakeMsg = HandshakeType.ClientHello; ContentType contentType = (ContentType)type; byte[] buffer = this.ReadRecordBuffer(type, record); if (buffer == null) { // record incomplete (at the moment) internalResult.SetComplete((byte[])null); return; } // Decrypt message contents if needed if (contentType == ContentType.Alert && buffer.Length == 2) { } else if ((this.Context.Read != null) && (this.Context.Read.Cipher != null)) { buffer = this.decryptRecordFragment(contentType, buffer); DebugHelper.WriteLine("Decrypted record data", buffer); } // Process record switch (contentType) { case ContentType.Alert: this.ProcessAlert((AlertLevel)buffer [0], (AlertDescription)buffer [1]); if (record.CanSeek) { // don't reprocess that memory block record.SetLength(0); } buffer = null; break; case ContentType.ChangeCipherSpec: this.ProcessChangeCipherSpec(); break; case ContentType.ApplicationData: break; case ContentType.Handshake: TlsStream message = new TlsStream(buffer); while (!message.EOF) { this.ProcessHandshakeMessage(message); } break; case (ContentType)0x80: this.context.HandshakeMessages.Write(buffer); break; default: throw new TlsException( AlertDescription.UnexpectedMessage, "Unknown record received from server."); } internalResult.SetComplete(buffer); } catch (Exception ex) { internalResult.SetComplete(ex); } }
public override void ComputeKeys() { // Compute KeyBlock TlsStream tmp = new TlsStream(); char labelChar = 'A'; int count = 1; while (tmp.Length < this.KeyBlockSize) { string label = String.Empty; for (int i = 0; i < count; i++) { 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); labelChar++; count++; } // Create keyblock TlsStream keyBlock = new TlsStream(tmp.ToArray()); this.Context.Negotiating.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.Negotiating.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); if (!this.IsExportable) { if (this.IvSize != 0) { this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize); this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } else { HashAlgorithm md5 = MD5.Create(); int keySize = (md5.HashSize >> 3); //in bytes not bits byte[] temp = new byte [keySize]; // Generate final write keys md5.TransformBlock(this.Context.ClientWriteKey, 0, this.Context.ClientWriteKey.Length, temp, 0); md5.TransformFinalBlock(this.Context.RandomCS, 0, this.Context.RandomCS.Length); byte[] finalClientWriteKey = new byte[this.ExpandedKeyMaterialSize]; Buffer.BlockCopy(md5.Hash, 0, finalClientWriteKey, 0, this.ExpandedKeyMaterialSize); md5.Initialize(); md5.TransformBlock(this.Context.ServerWriteKey, 0, this.Context.ServerWriteKey.Length, temp, 0); md5.TransformFinalBlock(this.Context.RandomSC, 0, this.Context.RandomSC.Length); byte[] finalServerWriteKey = new byte[this.ExpandedKeyMaterialSize]; Buffer.BlockCopy(md5.Hash, 0, finalServerWriteKey, 0, this.ExpandedKeyMaterialSize); this.Context.ClientWriteKey = finalClientWriteKey; this.Context.ServerWriteKey = finalServerWriteKey; // Generate IV keys if (this.IvSize > 0) { md5.Initialize(); temp = md5.ComputeHash(this.Context.RandomCS, 0, this.Context.RandomCS.Length); this.Context.ClientWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(temp, 0, this.Context.ClientWriteIV, 0, this.IvSize); md5.Initialize(); temp = md5.ComputeHash(this.Context.RandomSC, 0, this.Context.RandomSC.Length); this.Context.ServerWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(temp, 0, this.Context.ServerWriteIV, 0, this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } DebugHelper.WriteLine(">>>> KeyBlock", keyBlock.ToArray()); DebugHelper.WriteLine(">>>> ClientWriteKey", this.Context.ClientWriteKey); DebugHelper.WriteLine(">>>> ClientWriteIV", this.Context.ClientWriteIV); DebugHelper.WriteLine(">>>> ClientWriteMAC", this.Context.Negotiating.ClientWriteMAC); DebugHelper.WriteLine(">>>> ServerWriteKey", this.Context.ServerWriteKey); DebugHelper.WriteLine(">>>> ServerWriteIV", this.Context.ServerWriteIV); DebugHelper.WriteLine(">>>> ServerWriteMAC", this.Context.Negotiating.ServerWriteMAC); ClientSessionCache.SetContextInCache(this.Context); // Clear no more needed data keyBlock.Reset(); tmp.Reset(); }
public override void ComputeKeys() { // Create keyblock TlsStream keyBlock = new TlsStream( this.PRF( this.Context.MasterSecret, "key expansion", this.Context.RandomSC, this.KeyBlockSize)); this.Context.Negotiating.ClientWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.Negotiating.ServerWriteMAC = keyBlock.ReadBytes(this.HashSize); this.Context.ClientWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); this.Context.ServerWriteKey = keyBlock.ReadBytes(this.KeyMaterialSize); if (!this.IsExportable) { if (this.IvSize != 0) { this.Context.ClientWriteIV = keyBlock.ReadBytes(this.IvSize); this.Context.ServerWriteIV = keyBlock.ReadBytes(this.IvSize); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } else { // Generate final write keys byte[] finalClientWriteKey = PRF(this.Context.ClientWriteKey, "client write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize); byte[] finalServerWriteKey = PRF(this.Context.ServerWriteKey, "server write key", this.Context.RandomCS, this.ExpandedKeyMaterialSize); this.Context.ClientWriteKey = finalClientWriteKey; this.Context.ServerWriteKey = finalServerWriteKey; if (this.IvSize > 0) { // Generate IV block byte[] ivBlock = PRF(CipherSuite.EmptyArray, "IV block", this.Context.RandomCS, this.IvSize * 2); // Generate IV keys this.Context.ClientWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(ivBlock, 0, this.Context.ClientWriteIV, 0, this.Context.ClientWriteIV.Length); this.Context.ServerWriteIV = new byte[this.IvSize]; Buffer.BlockCopy(ivBlock, this.IvSize, this.Context.ServerWriteIV, 0, this.Context.ServerWriteIV.Length); } else { this.Context.ClientWriteIV = CipherSuite.EmptyArray; this.Context.ServerWriteIV = CipherSuite.EmptyArray; } } DebugHelper.WriteLine(">>>> KeyBlock", keyBlock.ToArray()); DebugHelper.WriteLine(">>>> ClientWriteKey", this.Context.ClientWriteKey); DebugHelper.WriteLine(">>>> ClientWriteIV", this.Context.ClientWriteIV); DebugHelper.WriteLine(">>>> ClientWriteMAC", this.Context.Negotiating.ClientWriteMAC); DebugHelper.WriteLine(">>>> ServerWriteKey", this.Context.ServerWriteKey); DebugHelper.WriteLine(">>>> ServerWriteIV", this.Context.ServerWriteIV); DebugHelper.WriteLine(">>>> ServerWriteMAC", this.Context.Negotiating.ServerWriteMAC); ClientSessionCache.SetContextInCache(this.Context); // Clear no more needed data keyBlock.Reset(); }