Example #1
0
        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);
        }