private void NetworkLoop() { while (!Cancellator.IsCancellationRequested) { try { if (!Socket.Poll(100000, SelectMode.SelectRead)) { continue; } } catch (SocketException) { break; } byte[] Data; try { byte[] Buffer = new byte[8]; Stream.Read(Buffer, 0, 8); int PacketLength = ToInt32(Buffer, 0); if (ToUInt32(Buffer, 4) != 0x31305456U) { break; } Data = new byte[PacketLength]; int Offset = 0; do { int BytesRead = Stream.Read(Data, Offset, PacketLength); if (BytesRead == 0) { break; } Offset += BytesRead; PacketLength -= BytesRead; } while (PacketLength > 0); if (PacketLength != 0) { break; } } catch (IOException) { break; } try { if (State == EncryptionState.Encrypted) { MessageReceived(Encryptor.Decrypt(Data)); } else { MessageType Type = MessageType.Invalid; if (Data.Length > 3) { Type = (MessageType)(ToUInt32(Data, 0) & ~0x80000000U); } if (State == EncryptionState.Connected && Type == MessageType.ChannelEncrypt) { RawMessage <ChannelEncrypt> Message = new RawMessage <ChannelEncrypt>(Data); if (Message.Payload.Length >= 16) { RawMessage <ChannelEncrypt> Response = new RawMessage <ChannelEncrypt>(MessageType.ChannelEncryptResponse); byte[] Challenge = Message.Payload, EncryptedBlob, SessionKey = new byte[32]; using (RandomNumberGenerator RNG = RandomNumberGenerator.Create()) RNG.GetBytes(SessionKey); using (RSA RSA = RSA.Create()) { RSA.ImportParameters(Parameters); byte[] BlobToEncrypt = new byte[32 + Challenge.Length]; Copy(SessionKey, BlobToEncrypt, 32); Copy(Challenge, 0, BlobToEncrypt, 32, Challenge.Length); EncryptedBlob = RSA.Encrypt(BlobToEncrypt, RSAEncryptionPadding.OaepSHA1); } byte[] CRCHash; using (CRC32 CRC = new CRC32()) CRCHash = CRC.ComputeHash(EncryptedBlob); int Length = EncryptedBlob.Length; Response.Payload = new byte[Length + 8]; Copy(EncryptedBlob, Response.Payload, Length); Copy(CRCHash, 0, Response.Payload, Length, 4); Encryptor = new EncryptionFilter(SessionKey); State = EncryptionState.Challenged; Send(Response.Serialize()); } else { Disconnect(false); } } else if (State == EncryptionState.Challenged && Type == MessageType.ChannelEncryptResult) { if (new RawMessage <ChannelEncryptResult>(Data).Body.Success) { State = EncryptionState.Encrypted; Log($"Established encrypted TCP connection to {EndpointAddress}"); Connected?.Invoke(); } else { Disconnect(false); } } else { Disconnect(false); } } } catch { } } bool UserInitiated = Cancellator.IsCancellationRequested; if (UserInitiated) { Shutdown(); } Release(UserInitiated); }