public void Write_Encrypted_ResultBytesAreExpected()
        {
            //Arrange
            var expectedBytes      = GetProtectedMessageHex();
            var buffer             = new byte[PacketBuffer.MaxPacketSize];
            var version            = PacketVersion.CreateByDraft(32);
            var connectionIds      = GetConnectionIdsHex();
            var sourceConnectionId = PacketConnectionId.Parse(Utils.ParseHexString(connectionIds.SourceConnectionIdHex));
            var destConnectionId   = PacketConnectionId.Parse(Utils.ParseHexString(connectionIds.DestConnectionIdHex));
            var packetNumber       = PacketNumber.Parse(Utils.ParseHexString(GetPacketNumberHex()));
            var token            = PacketToken.Empty;
            var clientHelloBytes = Utils.ParseHexString(GetTlsClientHelloHex());
            var secrets          = GetSecrets();
            var aead             = Cipher.TLS_AES_128_GCM_SHA256.CreateAead(Utils.ParseHexString(secrets.Iv), Utils.ParseHexString(secrets.Key));
            var cipher           = Cipher.TLS_AES_128_GCM_SHA256.CreateCipher(Utils.ParseHexString(secrets.Hp));

            //Act
            var cursor = new MemoryCursor(buffer);

            using (InitialPacket.StartProtectedWriting(aead, cipher, cursor, version, destConnectionId, sourceConnectionId, packetNumber, token))
            {
                using (PaddingFrame.EnsureLength(cursor, 1162))
                {
                    using (CryptoFrame.StartWriting(cursor, 0))
                    {
                        clientHelloBytes.CopyTo(cursor);
                    }
                }
            }

            //Assert
            Assert.Equal(expectedBytes, Utils.ToHexString(cursor.PeekStart().ToArray()), true);
        }
Example #2
0
        public void TestDecode()
        {
            HexData samplePacket = new HexData("cfff00001712a2702fa91b97cb3db9d7736d32f2231932941156221f7eed93c8ea78b87c0c80a55c60c60044a30fe946ba0cec818cdf237ddb78c816ab1bdff71c509c797d8a93c8c2449bc10b3667f3a0bee0e9ea2990152054d336006fbddb38e1dc580004a819febadf22f21eb14c15687de9230b6b8bc4da592479215fe3e44eb3baece38c0c02e7294783ed01429aa40624b4d9cda7eef2d4520fb285ea1cbb3433324b10f8711a1277edbf34e82919a082f6a332d2a2d52ff956914d1dac7b482d40bc2854401df5309db5a8cc5b642ab9474885492ea99482cfd5483feaa1897cb5a33f1268bc8ca40fc5155d92a3f3868614faecff089691cf1965bcc6e0977ff8431327ab18bdb0013f4a9180bc90bc8fe3afb65782e2f21d67005be0c6d04a0a63f2738064d0fc538477a824e056cecf4b01a55e7ce86c8078a688198716c050aa7af2facca178f911e63d3bffd28339040f54c1b3b40f9794578f27d4c64aab38b4a23ee5bc1239711dcacad5a623506cd504394cc1673b83590877603d308a5c6b7febfd6af582a507477c64c16553056c23830ec391c198fb64190bc40cd33b05749b0e3abd0e75c60de0d3c6a8dd6280ca62fe10eb1900015f038e9911c64efb87e1c4a3d66700fd7b1247cc4f7f74beec3937d92c03a6489ecfb27e3974ecc50c2c79661291ba5dc3d10e4b8eb2f42bc28ebcc8578823e55d288c7efbf1ae434eed2c444d865953c1bf805cd793f528930096b6a473964e6706393ae9b934d4761b18741fcd6940e71a9c99e5b90eb8af0d62c6c39081b6aeb01083819741c7a09bb3bdf235f0622b286eb509f203370fe44da1386ea81ed51527d7d5f1368eb206113e5f2ca167c645506b3b6a7b59276fa49eedbfa3d81721ad68726492f50588b311c895478d89b48c336d0a87ccb84e3c7cf782450784124d720209df89241f589b5ca92c5d06aa9e313d6cd4d68d87b839ff9e0eebcc4f29399a98783aba5d540b549bd39aa3c541593af7f4c171bced1e1c72ddc6ad9985bf671ae1b1de1c178592b32f5a7fb60fadacaf8978b07360db0a0cd1f69138e8d883000f2a99d50ce64339d599076c2fdbd81d58642dc945594fd9e8eb38d341c8c3260c2c82c43065058fcd38fe028db6aefe16798afc8984748484da7ad4eff1302a5e939565e572ec2facb544cadf84a046a236359e2891e370c1bf8b16e28ed3e215527475db571b52e660ab711bc7e4e9e786c1d94ef5dd3ebe91f44abb0c167a86e959be54196e3f01a593ba34b37b5cc36fe8357c1d9b0bf0b817c6d7905efdbbf9f78e7ba196cffca2444a1cec3750b71b1fc866b2d15302e9c1a8285946e536a51a83d34fc695f11f4244fb925ab996913b8437f745140649840f26f6023e5dc29338d73ec6208bf3f8784a698f2f0867efb5d70041da4cf6a627f14fe3ac7bbaf90eeece28ac676e592a3d51921359bcc8905cdfc1610694144607fe43b1ea8a1ff03adacab409e66b8a4b795d87a6419c15bb92fc5c1ffd1ae7735e5d4612c42d35c009abe0e0d4d21676733cd1440656f291e21c10ed2db649e0ffbccb3fe8b021125a16c79f8f02734deb049a180855c0f21013a0921ef13b016e76c57599feb67a517bcb8bcb895f56d634ea5308f9c68ddeff22d57c9f9ec09c2fdd8f1ab273f1d9964bb2f211f408d67f252ddd665a3fb3a44ca98e9512a3d3d2c0453c244db31f79be0549c8");

            byte[] bytes = samplePacket.bytes;
            Packet p     = Packet.Unpack(samplePacket.bytes);

            Assert.AreEqual(p.GetType(), typeof(InitialPacket));
            InitialPacket recP = p as InitialPacket;

            Assert.AreEqual(0xff000017, recP.Version);
            Assert.AreEqual((UInt32)18, recP.DCIDLength);
            CollectionAssert.AreEqual((new HexData("a2702fa91b97cb3db9d7736d32f223193294")).bytes, recP.DCID);
            Assert.AreEqual((UInt32)17, recP.SCIDLength);
            CollectionAssert.AreEqual((new HexData("56221f7eed93c8ea78b87c0c80a55c60c6")).bytes, recP.SCID);

            // Wireshark translates the initial 0xCF to 0b11000000 while our code translates it to 0b11001111
            // Likely because of header protection, which we cannot have without QUIC-TLS
            // PacketNumberLength and PacketNumber thus cannot be computed correctly
            // Assert.AreEqual((UInt32)1, recP.PacketNumberLength);
            // Assert.AreEqual((UInt32)0, recP.PacketNumber);
            Assert.AreEqual((UInt64)0, recP.TokenLength.Value);
            CollectionAssert.AreEqual(new byte[] { }, recP.Token);
            Assert.AreEqual((UInt64)1187, recP.Length.Value);
            // TODO: assert payload content
        }
Example #3
0
        public void TestEncodeAndDecode()
        {
            // TODO: all the lengths fields should be set automatically (ex: DCIDLength should be auto computed from DCID)
            InitialPacket sentP = new InitialPacket
            {
                DCIDLength         = 2,
                DCID               = new byte[] { 0xab, 0xcd },
                PacketNumberLength = 2,
                SCIDLength         = 3,
                SCID               = new byte[] { 0x12, 0x23, 0xcf },
                PacketNumber       = 1234,
                TokenLength        = new VariableLengthInteger(2),
                Token              = new byte[] { 0x42, 0x42 }
            };

            byte[] b = sentP.Encode();

            Packet p = Packet.Unpack(b);

            Assert.AreEqual(p.GetType(), typeof(InitialPacket));
            InitialPacket recP = p as InitialPacket;

            Assert.AreEqual(sentP.DCIDLength, recP.DCIDLength);
            CollectionAssert.AreEqual(sentP.DCID, recP.DCID);
            Assert.AreEqual(sentP.SCIDLength, recP.SCIDLength);
            CollectionAssert.AreEqual(sentP.SCID, recP.SCID);
            Assert.AreEqual(sentP.PacketNumberLength, recP.PacketNumberLength);
            Assert.AreEqual(sentP.PacketNumber, recP.PacketNumber);
            Assert.AreEqual(sentP.TokenLength.Value, recP.TokenLength.Value);
            CollectionAssert.AreEqual(sentP.Token, recP.Token);
            Assert.AreEqual(sentP.PacketNumberLength + 1200, recP.Length.Value); // 4 = PacketNumberLength + Payload.Length
            // TODO: assert payload content
        }
Example #4
0
        static void Main(string[] args)
        {
            byte[]          bytes    = new VariableInteger(12345);
            VariableInteger integer  = bytes;
            UInt64          uinteger = integer;
            int             size     = VariableInteger.Size(bytes[0]);

            InitialPacket packet = new InitialPacket()
            {
                Version                 = 16,
                SourceConnectionId      = 124,
                DestinationConnectionId = 0,
                PacketNumber            = 777521,
                TokenLength             = 0
            };

            packet = new PacketCreator().CreateInitialPacket(124, 0);

            ConnectionCloseFrame frame     = new ConnectionCloseFrame(ErrorCode.SERVER_BUSY, "The server is too busy to process your request.");
            MaxStreamIdFrame     msidframe = new MaxStreamIdFrame(144123, StreamType.ClientUnidirectional);

            //packet.AttachFrame(frame);
            packet.AttachFrame(msidframe);

            byte[] data = packet.Encode();
            string b64  = ToBase64(data);

            byte[] shpdata1 = new byte[] { 1, 1, 2, 3, 5, 8 };
            byte[] shpdata2 = new byte[] { 13, 21, 34, 55, 89, 144 };

            ShortHeaderPacket shp = new ShortHeaderPacket();

            shp.DestinationConnectionId = 124;
            shp.PacketNumber            = 2;

            shp.AttachFrame(new StreamFrame()
            {
                StreamId = 1, Length = new VariableInteger((UInt64)shpdata2.Length), StreamData = shpdata2, Offset = 6, EndOfStream = true
            });
            shp.AttachFrame(new StreamFrame()
            {
                StreamId = 1, Length = new VariableInteger((UInt64)shpdata1.Length), StreamData = shpdata1, Offset = 0
            });

            string shpb64 = ToBase64(shp.Encode());

            packet.Decode(data);

            byte[] ccfData = frame.Encode();
            frame.Decode(new ByteArray(ccfData));

            byte[]   streamIdData = new StreamId(123, StreamType.ClientUnidirectional);
            StreamId streamId     = streamIdData;

            QuicListener listener = new QuicListener(11000);

            listener.OnClientConnected += Listener_OnClientConnected;
            listener.Start();
        }
Example #5
0
        /// <summary>
        /// Processes incomming initial packet and creates or halts a connection.
        /// </summary>
        /// <param name="packet">Initial Packet</param>
        /// <param name="endPoint">Peer's endpoint</param>
        /// <returns></returns>
        private QuicConnection ProcessInitialPacket(Packet packet, IPEndPoint endPoint)
        {
            QuicConnection result = null;
            UInt32         availableConnectionId;

            byte[] data;
            // Unsupported version. Version negotiation packet is sent only on initial connection. All other packets are dropped. (5.2.2 / 16th draft)
            if (packet.Version != QuicVersion.CurrentVersion || !QuicVersion.SupportedVersions.Contains(packet.Version))
            {
                VersionNegotiationPacket vnp = _packetCreator.CreateVersionNegotiationPacket();
                data = vnp.Encode();

                _client.Send(data, data.Length, endPoint);
                return(null);
            }

            InitialPacket cast = packet as InitialPacket;
            InitialPacket ip   = _packetCreator.CreateInitialPacket(0, cast.SourceConnectionId);

            // Protocol violation if the initial packet is smaller than the PMTU. (pt. 14 / 16th draft)
            if (cast.Encode().Length < QuicSettings.PMTU)
            {
                ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.PROTOCOL_VIOLATION, "PMTU have not been reached."));
            }
            else if (ConnectionPool.AddConnection(new ConnectionData(_pwt, cast.SourceConnectionId, 0), out availableConnectionId) == true)
            {
                // Tell the peer the available connection id
                ip.SourceConnectionId = (byte)availableConnectionId;

                // We're including the maximum possible stream id during the connection handshake. (4.5 / 16th draft)
                ip.AttachFrame(new MaxStreamsFrame(QuicSettings.MaximumStreamId, StreamType.ServerBidirectional));

                // Set the return result
                result = ConnectionPool.Find(availableConnectionId);
            }
            else
            {
                // Not accepting connections. Send initial packet with CONNECTION_CLOSE frame.
                // TODO: Buffering. The server might buffer incomming 0-RTT packets in anticipation of late delivery InitialPacket.
                // Maximum buffer size should be set in QuicSettings.
                ip.AttachFrame(new ConnectionCloseFrame(ErrorCode.SERVER_BUSY, "The server is too busy to process your request."));
            }

            data = ip.Encode();
            int dataSent = _client.Send(data, data.Length, endPoint);

            if (dataSent > 0)
            {
                return(result);
            }

            return(null);
        }
        public void Read_Protected_ResultsAreExpected()
        {
            //Arrange
            var messageBytes       = Utils.ParseHexString(GetProtectedMessageHex());
            var version            = PacketVersion.CreateByDraft(32);
            var connectionIds      = GetConnectionIdsHex();
            var sourceConnectionId = PacketConnectionId.Parse(Utils.ParseHexString(connectionIds.SourceConnectionIdHex));
            var destConnectionId   = PacketConnectionId.Parse(Utils.ParseHexString(connectionIds.DestConnectionIdHex));
            var packetNumber       = PacketNumber.Parse(Utils.ParseHexString(GetPacketNumberHex()));
            var token             = PacketToken.Empty;
            var clientHelloBytes  = GetTlsClientHelloHex();
            var cryptoFrame       = new CryptoFrame();
            var paddingFrameCount = 0;
            var secrets           = GetSecrets();
            var aead   = Cipher.TLS_AES_128_GCM_SHA256.CreateAead(Utils.ParseHexString(secrets.Iv), Utils.ParseHexString(secrets.Key));
            var cipher = Cipher.TLS_AES_128_GCM_SHA256.CreateCipher(Utils.ParseHexString(secrets.Hp));

            //Act
            var cursor = new MemoryCursor(messageBytes);
            var result = InitialPacket.TryParseProtected(aead, cipher, cursor, out var packet);

            using (packet.Payload.SetCursor(cursor))
            {
                result &= CryptoFrame.TryParse(cursor, out cryptoFrame);

                paddingFrameCount = PaddingFrame.SkipRange(cursor);

                result &= cursor.IsEnd();
            }

            result &= cursor.IsEnd();

            //Assert
            Assert.True(result);
            Assert.Equal(917, paddingFrameCount);
            Assert.Equal(version, packet.Version);
            Assert.Equal(sourceConnectionId, packet.SourceConnectionId);
            Assert.Equal(destConnectionId, packet.DestinationConnectionId);
            Assert.Equal(packetNumber, packet.Number);
            Assert.Equal(token, packet.Token);
            Assert.Equal(0, cryptoFrame.Offset);
            Assert.Equal(clientHelloBytes, Utils.ToHexString(cryptoFrame.Data.Read(cursor).ToArray()), true);
        }
        public InitialPacket CreateInitialPacket(GranularInteger sourceConnectionId, GranularInteger destinationConnectionId)
        {
            InitialPacket packet = new InitialPacket(destinationConnectionId, sourceConnectionId);

            packet.PacketNumber            = 0;
            packet.SourceConnectionId      = sourceConnectionId;
            packet.DestinationConnectionId = destinationConnectionId;
            packet.Version = QuicVersion.CurrentVersion;

            int length  = packet.Encode().Length;
            int padding = QuicSettings.PMTU - length;

            for (int i = 0; i < padding; i++)
            {
                packet.AttachFrame(new PaddingFrame());
            }

            return(packet);
        }
Example #8
0
        public InitialPacket CreateInitialPacket(byte sourceConnectionId, byte destinationConnectionId)
        {
            var packet = new InitialPacket
            {
                PacketNumber            = 0,
                SourceConnectionId      = sourceConnectionId,
                DestinationConnectionId = destinationConnectionId,
                Version = QuicVersion.CurrentVersion
            };

            var length  = packet.Encode().Length;
            var padding = QuicSettings.PMTU - length;

            for (var i = 0; i < padding; i++)
            {
                packet.AttachFrame(new PaddingFrame());
            }

            return(packet);
        }
Example #9
0
        public QuicContext Connect(string ip, int port)
        {
            // Establish socket connection
            _peerIp = new IPEndPoint(IPAddress.Parse(ip), port);

            // Start initial protocol process
            InitialPacket connectionPacket = _packetCreator.CreateInitialPacket(0, 0);

            byte[] data = connectionPacket.Encode();

            // Send the initial packet
            _client.Send(data, data.Length, _peerIp);

            // Await response for sucessfull connection creation by the server
            byte[] peerData = _client.Receive(ref _peerIp);
            if (peerData == null)
            {
                throw new QuicConnectivityException("Server did not respond properly.");
            }

            Packet packet = _unpacker.Unpack(peerData);

            if ((packet is InitialPacket) == false)
            {
                throw new QuicConnectivityException("Server did not respond properly.");
            }

            InitialPacket ini = (InitialPacket)packet;

            HandleInitialFrames(packet);
            EstablishConnection(ini.SourceConnectionId, ini.SourceConnectionId);

            // Create the QuicContext
            QuicContext context = new QuicContext(_client, _peerIp);

            // Cross reference with Connection
            _connection.AttachContext(context);

            return(context);
        }
Example #10
0
        public Packet Unpack(byte[] data)
        {
            Packet result = null;

            var type = GetPacketType(data);

            switch (type)
            {
            case QuicPacketType.Initial: result = new InitialPacket(); break;

            case QuicPacketType.ShortHeader: result = new ShortHeaderPacket(); break;
            }

            if (result == null)
            {
                return(null);
            }

            result.Decode(data);

            return(result);
        }
Example #11
0
        public static void Handle(byte[] packet)
        {
            PacketReader pr     = new PacketReader(packet);
            Header       header = (Header)pr.ReadUInt16();

            Debug.Log(DateTime.Now + " | Received packet: " + header);

            switch (header)
            {
            case Header.Init:
            {
                InitialPacket pc = new InitialPacket(pr);
            }
            break;

            case Header.Login:
            {
                LoginAuthorizationPacket pc = new LoginAuthorizationPacket(pr);
            }
            break;
            }
        }
Example #12
0
        /// <summary>
        /// Connect to a remote server.
        /// </summary>
        /// <param name="ip">Ip Address</param>
        /// <param name="port">Port</param>
        /// <returns></returns>
        public QuicConnection Connect(string ip, int port)
        {
            // Establish socket connection
            _peerIp = new IPEndPoint(IPAddress.Parse(ip), port);

            // Initialize packet reader
            _pwt = new PacketWireTransfer(_client, _peerIp);

            // Start initial protocol process
            InitialPacket connectionPacket = _packetCreator.CreateInitialPacket(0, 0);

            // Send the initial packet
            _pwt.SendPacket(connectionPacket);

            // Await response for sucessfull connection creation by the server
            InitialPacket packet = (InitialPacket)_pwt.ReadPacket();

            HandleInitialFrames(packet);
            EstablishConnection(packet.SourceConnectionId, packet.SourceConnectionId);

            return(_connection);
        }
Example #13
0
        //[Fact]
        public void Test1()
        {
            var buff  = new byte[PacketBuffer.MaxPacketSize];
            var pBuff = Utils.ParseHexString("060040f1010000ed0303ebf8fa56f12939b9584a3896472ec40bb863cfd3e86804fe3a47f06a2b69484c00000413011302010000c000000010000e00000b6578616d706c652e636f6dff01000100000a00080006001d0017001800100007000504616c706e000500050100000000003300260024001d00209370b2c9caa47fbabaf4559fedba753de171fa71f50f1ce15d43e994ec74d748002b0003020304000d0010000e0403050306030203080408050806002d00020101001c00024001ffa500320408ffffffffffffffff05048000ffff07048000ffff0801100104800075300901100f088394c8f03e51570806048000ffff");
            var hBuff = Utils.ParseHexString("c3ff000020088394c8f03e5157080000449e00000002");

            Array.Resize(ref pBuff, 1162);
            Array.Copy(hBuff, buff, hBuff.Length);
            Array.Copy(pBuff, 0, buff, hBuff.Length, pBuff.Length);
            Array.Resize(ref buff, hBuff.Length + pBuff.Length);

            var encryptedBuff = new byte[PacketBuffer.MaxPacketSize];
            var aead          = Cipher.TLS_AES_128_GCM_SHA256.CreateAead(Utils.ParseHexString("6b26114b9cba2b63a9e8dd4f"), Utils.ParseHexString("175257a31eb09dea9366d8bb79ad80ba"));
            //var token = aead.StartEncryption(pBuff, encryptedBuff);
            //token.UseSequenceNumber(2);
            //token.UseAssociatedData(hBuff);
            //aead.Finish(token);
            //var encryptedHex = Utils.ToHexString(token.Result.ToArray());

            var c    = new MemoryCursor(buff);
            var res1 = InitialPacket.TryParse(c, out var p);

            using (p.Payload.SetCursor(c))
            {
                var res2 = CryptoFrame.TryParse(c, out var f);
            }
            var res3 = c.IsEnd();

            var buffer = new byte[PacketBuffer.MaxPacketSize];
            var cursor = new MemoryCursor(buffer);

            using (InitialPacket.StartWriting(
                       cursor,
                       PacketVersion.CreateByDraft(29),
                       PacketConnectionId.Generate(),
                       PacketConnectionId.Generate(),
                       PacketNumber.Initial,
                       PacketToken.Empty))
            {
                using (CryptoFrame.StartWriting(cursor, 0))
                {
                    using (ClientHello.StartWriting(cursor, HandshakeRandom.Generate(), Cipher.Supported, SessionId.Generate()))
                    {
                        using (cursor.StartSupportedGroupsWriting())
                        {
                            foreach (var group in NamedGroup.Supported.Span)
                            {
                                group.WriteBytes(cursor);
                            }
                        }

                        using (cursor.StartSignatureAlgorithmsWriting())
                        {
                            foreach (var scheme in SignatureScheme.Supported.Span)
                            {
                                scheme.WriteBytes(cursor);
                            }
                        }

                        using (cursor.StartKeySharesWriting())
                        {
                            using (KeyShareEntry.StartWriting(cursor, NamedGroup.X25519))
                            {
                                Utils.ParseHexString("358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254").CopyTo(cursor);
                            }
                        }

                        using (cursor.StartPskKeyExchangeModesWriting())
                        {
                            PskKeyExchangeMode.PskDheKe.WriteBytes(cursor);
                        }

                        using (cursor.StartSupportedVersionsWriting())
                        {
                            ProtocolVersion.Tls13.WriteBytes(cursor);
                        }

                        cursor.StartTransportParametersWriting().Dispose();
                    }

                    for (int i = 0; i < 1000; i++)
                    {
                        PaddingFrame.WriteBytes(cursor);
                    }
                }
            }

            var t = Utils.ParseHexString("c0ff00001d08d0076f25b832934b0841f39c4f6381d72e0044ba00060041060100010203036e3828a258f4a7488d105acd6da670a41b28c2b601c58c4530486df585ec54a6000006130213011303010000d30033004700450017004104e46de65fb3e4fa258e1f03c551fa6a4507411e09bdc32e4dc597084db1852caf9d5b783243ebc748bf644ca31e108f4fdea2c19ae3c94ad99714dfa38a6a244500000021001f00001c68747470332d746573742e6c6974657370656564746563682e636f6d0010000800060568332d3239002b0003020304000d000a00080804040304010201000a000600040017001dffa5002d050480004000070480004000040480008000080101090103010267100e0104030245c00f0841f39c4f6381d72e002d000302000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");

            var client   = new UdpClient(0);
            var endPoint = new IPEndPoint(IPAddress.Parse("52.55.120.73"), 443);

            client.Send(t, t.Length, endPoint);

            IPEndPoint ep       = null;
            var        response = client.Receive(ref ep);

            var h1 = Utils.ToHexString(response);

            cursor = new MemoryCursor(response);

            var result = InitialPacket.TryParse(cursor, out var packet);

            using (packet.Payload.SetCursor(cursor))
            {
                var h2 = Utils.ToHexString(cursor.PeekEnd().ToArray());

                CryptoFrame.TryParse(cursor, out var cryptoFrame);

                using (cryptoFrame.Data.SetCursor(cursor))
                {
                    ServerHello.TryParse(cursor, out var sh);
                }
            }

            Assert.True(true);

            //var snBuff = new byte[100];
            //var snIter = snBuff.AsSpan();
            //ServerNameExtension.WriteHostName(ref snIter, "example.ulfheim.net");
            //var snResult = Parse(snBuff.AsSpan().Slice(0, snBuff.Length - snIter.Length).ToArray());

            //var keyShareBuff = new byte[1000];
            //var keyShareSpan = keyShareBuff.AsSpan();
            //var privateKey = Parse("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f");
            //var publicKey = NamedGroup.X25519.GeneratePublicKey(privateKey);
            //KeyShareExtension.WriteClientEntry(ref keyShareSpan, NamedGroup.X25519, publicKey);
            //var keyShareData = Parse(keyShareBuff.AsSpan().Slice(0, keyShareBuff.Length - keyShareSpan.Length).ToArray());

            //var secret = Parse("ff0e5b965291c608c1e8cd267eefc0afcc5e98a2786373f0db47b04786d72aea");
            //var hash = Parse("22844b930e5e0a59a09d5ac35fc032fc91163b193874a265236e568077378d8b");
            //var expected = Parse("976017a77ae47f1658e28f7085fe37d149d1e9c91f56e1aebbe0c6bb054bd92b");

            //var verifyData = Hash.Sha256.CreateVerifyData(secret, hash);
            //var result = verifyData.Span.SequenceEqual(expected);

            //var bytes = GetData();

            //InitialPacket.TryParse(bytes, out var initial, out var remainings);

            //CryptoFrame.TryParse(initial.Payload, out var crypto, out var afterCrypto);

            //ClientHello.TryParse(crypto.Data, out var hello, out var afterHello);

            //KeyShareExtension.TryParse(hello.Payload, out var keyShare, out var afterKeyShare);

            //var unknownBytes = UnknownExtension.SliceBytes(afterKeyShare, out var afterUnknown);

            //AlpnExtension.TryParse(afterUnknown, out var alpn, out var afterAlpn);

            //SupportedVersionExtension.TryParse(afterAlpn, out var supportedVersion, out var afterSupportedVersion);

            //SignatureAlgorithmsExtension.TryParse(afterSupportedVersion, out var signatureAlgorithms, out var afterSignatureAlgorithms);

            //SupportedGroupsExtension.TryParse(afterSignatureAlgorithms, out var supportedGroups, out var afterSupportedGroups);

            //TransportParametersExtension.TryParse(afterSupportedGroups, out var transportParametersExtension, out var afterTransportParametersExtension);

            //PskKeyExchangeModesExtension.TryParse(afterTransportParametersExtension, out var pskKeyExchangeModes, out var afterPsk);

            ////----------------------------------------------------------------

            //var buffer = new byte[65000];
            //var destination = buffer.AsSpan();

            //var initialContext = InitialPacket.StartWriting(ref destination, initial.Version, initial.DestinationConnectionId, initial.SourceConnectionId, initial.Number, initial.Token);
            //var cryptoContext = CryptoFrame.StartWriting(ref destination, 0);
            //var clientHelloContext = ClientHello.StartWriting(ref destination, hello.Random, hello.CipherSuite, hello.SessionId);

            //keyShare.WriteBytes(ref destination);

            //unknownBytes.Span.CopyTo(destination);
            //destination = destination.Slice(unknownBytes.Length);

            //alpn.WriteBytes(ref destination);

            //supportedVersion.WriteBytes(ref destination);

            //signatureAlgorithms.WriteBytes(ref destination);

            //supportedGroups.WriteBytes(ref destination);

            //var transportParametersContext = TransportParametersExtension.StartWriting(ref destination);
            //transportParametersExtension.Data.Span.CopyTo(destination);
            //destination = destination.Slice(transportParametersExtension.Data.Length);
            //transportParametersContext.Complete(ref destination);

            //pskKeyExchangeModes.WriteBytes(ref destination);

            //clientHelloContext.Complete(ref destination);
            //cryptoContext.Complete(ref destination);

            //for (int i = 0; i < 1000; i++)
            //{
            //    PaddingFrame.WriteBytes(ref destination);
            //}

            //initialContext.Complete(ref destination);

            ////----------------------------------------------------------------

            //InitialPacket.TryParse(buffer.ToArray(), out var initial1, out var remainings1);

            //CryptoFrame.TryParse(initial1.Payload, out var crypto1, out var afterCrypto1);

            //ClientHello.TryParse(crypto1.Data, out var hello1, out var afterHello1);

            //KeyShareExtension.TryParse(hello1.Payload, out var keyShare1, out var afterKeyShare1);

            //var unknownBytes1 = UnknownExtension.SliceBytes(afterKeyShare1, out var afterUnknown1);

            //AlpnExtension.TryParse(afterUnknown1, out var alpn1, out var afterAlpn1);

            //SupportedVersionExtension.TryParse(afterAlpn1, out var supportedVersion1, out var afterSupportedVersion1);

            //SignatureAlgorithmsExtension.TryParse(afterSupportedVersion1, out var signatureAlgorithms1, out var afterSignatureAlgorithms1);

            //SupportedGroupsExtension.TryParse(afterSignatureAlgorithms1, out var supportedGroups1, out var afterSupportedGroups1);

            //TransportParametersExtension.TryParse(afterSupportedGroups1, out var transportParametersExtension1, out var afterTransportParametersExtension1);

            //PskKeyExchangeModesExtension.TryParse(afterTransportParametersExtension1, out var pskKeyExchangeModes1, out var afterPsk1);

            //var client = DatagramChannel.Start(opt =>
            //{
            //    opt.ListeningPoint = new IPEndPoint(IPAddress.Any, 50000);
            //});

            //var addr = Dns.GetHostAddresses("litespeedtech.com"); //443
            ////var addr = Dns.GetHostAddresses("test.privateoctopus.com"); //4433
            ////var addr = Dns.GetHostAddresses("quant.eggert.org"); //4433
            ////var addr = Dns.GetHostAddresses("f5quic.com"); //4433

            //var dgram = new Datagram().WithAddress(addr[0]).WithPort(443).WithBuffer(buffer.ToArray());

            //client.Writer.TryWrite(dgram);

            //var response = client.Reader.ReadAsync().AsTask().Result;
        }