public void HandshakeDecoding()
        {
            byte[]           infohash = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 12, 15, 12, 52 };
            HandshakeMessage orig     = new HandshakeMessage(new InfoHash(infohash), "12312312345645645678", VersionInfo.ProtocolStringV100);

            orig.Encode(buffer, offset);
            HandshakeMessage dec = new HandshakeMessage();

            dec.Decode(buffer, offset, HandshakeMessage.HandshakeLength);
            Assert.IsTrue(orig.Equals(dec));
            Assert.AreEqual(orig.Encode(), dec.Encode());
        }
Example #2
0
        public void HandshakeDecoding()
        {
            var infohash = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 12, 15, 12, 52 };
            var orig     = new HandshakeMessage(new InfoHash(infohash), "12312312345645645678", VersionInfo.ProtocolStringV100);

            orig.Encode(_buffer, Offset);
            var dec = new HandshakeMessage();

            dec.Decode(_buffer, Offset, 68);
            Assert.IsTrue(orig.Equals(dec));
            Assert.AreEqual(orig.Encode(), dec.Encode());
        }
Example #3
0
        protected void OutputMessage(HandshakeMessage message)
        {
            byte[] data = message.Encode();
            _handshakeStream.Write(data, 0, data.Length);

            _outputMessages.Add(message);
        }
        protected override void ProcessCertificateVerify(HandshakeMessage verify)
        {
            if (_state != HandshakeState.ReceivedClientKeyExchange)
            {
                throw new AlertException(AlertDescription.UnexpectedMessage,
                                         "Certificate verify received at the wrong time");
            }
            if (!_clientCertificateReceived)
            {
                throw new AlertException(AlertDescription.UnexpectedMessage,
                                         "Certificate verify received even though client certificate not received");
            }

            // Get all handshake messages up to, but not including, this one
            byte[] allMessages       = _handshakeStream.ToArray();
            byte[] handshakeMessages = new byte[allMessages.Length - verify.Encode().Length];
            Buffer.BlockCopy(allMessages, 0, handshakeMessages, 0, handshakeMessages.Length);

            // Verify the signature of handshake messages
            CertificatePublicKey publicKey = new CertificatePublicKey(_clientCertificates[0]);
            bool signatureOk = VerifySignature(publicKey, handshakeMessages, verify.Data);

            if (!signatureOk)
            {
                throw new AlertException(AlertDescription.DecodeError,
                                         "Signature from client incorrect");
            }

            // Wait for changecipherspec+finished
            _state = HandshakeState.ReceivedClientKeyExchange;
        }
        protected override void ProcessFinished(HandshakeMessage finished)
        {
            if (_state != HandshakeState.ReceivedChangeCipherSpec)
            {
                throw new AlertException(AlertDescription.UnexpectedMessage,
                                         "Finished received at the wrong time");
            }

            byte[] allMessages       = _handshakeStream.ToArray();
            byte[] handshakeMessages = new byte[allMessages.Length - finished.Encode().Length];
            Buffer.BlockCopy(allMessages, 0, handshakeMessages, 0, handshakeMessages.Length);

            PseudoRandomFunction prf        = _cipherSuite.PseudoRandomFunction;
            HashAlgorithm        verifyHash = prf.CreateVerifyHashAlgorithm(_connectionState.MasterSecret);

            verifyHash.TransformBlock(handshakeMessages, 0, handshakeMessages.Length, handshakeMessages, 0);

            byte[] ourVerifyData;
            if (_version == ProtocolVersion.SSL3_0)
            {
                byte[] senderBytes = Encoding.ASCII.GetBytes("CLNT");
                verifyHash.TransformFinalBlock(senderBytes, 0, senderBytes.Length);
                ourVerifyData = verifyHash.Hash;
            }
            else
            {
                verifyHash.TransformFinalBlock(new byte[0], 0, 0);
                byte[] hash = verifyHash.Hash;

                int length = _cipherSuite.PseudoRandomFunction.VerifyDataLength;
                ourVerifyData = _cipherSuite.PseudoRandomFunction.GetBytes(_connectionState.MasterSecret, "client finished", hash, length);
            }

            // Verify that the received data matches ours
            bool verifyOk = false;

            if (ourVerifyData.Length == finished.Data.Length)
            {
                verifyOk = true;
                for (int i = 0; i < ourVerifyData.Length; i++)
                {
                    if (ourVerifyData[i] != finished.Data[i])
                    {
                        verifyOk = false;
                    }
                }
            }

            if (!verifyOk)
            {
                throw new AlertException(AlertDescription.DecryptError,
                                         "Finished packet contents incorrect");
            }
            _connectionState.ClientVerifyData = ourVerifyData;

            // Send our own change cipher spec
            _state = HandshakeState.SendChangeCipherSpec;
        }
Example #6
0
        private void Handshake(EncryptionTypes encryptionA, EncryptionTypes encryptionB, bool addInitial)
        {
            HandshakeMessage m = new HandshakeMessage(rig.Torrent.InfoHash, "12345123451234512345", VersionInfo.ProtocolStringV100);

            byte[] handshake = m.Encode();

            PeerAEncryption a = new PeerAEncryption(rig.Torrent.InfoHash, encryptionA);

            if (addInitial)
            {
                a.AddPayload(handshake);
            }

            PeerBEncryption b = new PeerBEncryption(new InfoHash[] { rig.Torrent.InfoHash }, encryptionB);

            var resultA = a.HandshakeAsync(conn.Outgoing);
            var resultB = b.HandshakeAsync(conn.Incoming);

            if (!Task.WhenAll(resultA, resultB).Wait(5000))
            {
                Assert.Fail("Could not handshake");
            }


            HandshakeMessage d = new HandshakeMessage();

            if (!addInitial)
            {
                a.Encrypt(handshake, 0, handshake.Length);
                b.Decrypt(handshake, 0, handshake.Length);
                d.Decode(handshake, 0, handshake.Length);
            }
            else
            {
                d.Decode(b.InitialData, 0, b.InitialData.Length);
            }
            Assert.AreEqual(m, d);


            if (encryptionA == EncryptionTypes.RC4Full || encryptionB == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
                Assert.IsTrue(b.Encryptor is RC4);
            }
            else if (encryptionA == EncryptionTypes.RC4Header || encryptionB == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
                Assert.IsTrue(b.Encryptor is RC4Header);
            }
            else if (encryptionA == EncryptionTypes.PlainText || encryptionB == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is PlainTextEncryption);
                Assert.IsTrue(b.Encryptor is PlainTextEncryption);
            }
        }
Example #7
0
        public void ProcessMessage(HandshakeMessage message)
        {
            byte[] msgData = message.Encode();
            _handshakeStream.Write(msgData, 0, msgData.Length);

            switch (message.Type)
            {
            case HandshakeMessageType.HelloRequest:
                ProcessHelloRequest();
                break;

            case HandshakeMessageType.ClientHello:
                ProcessClientHello((HandshakeClientHello)message);
                break;

            case HandshakeMessageType.ServerHello:
                ProcessServerHello((HandshakeServerHello)message);
                break;

            case HandshakeMessageType.NewSessionTicket:
                ProcessNewSessionTicket(message);
                break;

            case HandshakeMessageType.Certificate:
                ProcessCertificate((HandshakeCertificate)message);
                break;

            case HandshakeMessageType.ServerKeyExchange:
                ProcessServerKeyExchange(message);
                break;

            case HandshakeMessageType.CertificateRequest:
                ProcessCertificateRequest((HandshakeCertificateRequest)message);
                break;

            case HandshakeMessageType.ServerHelloDone:
                ProcessServerHelloDone(message);
                break;

            case HandshakeMessageType.CertificateVerify:
                ProcessCertificateVerify(message);
                break;

            case HandshakeMessageType.ClientKeyExchange:
                ProcessClientKeyExchange(message);
                break;

            case HandshakeMessageType.Finished:
                ProcessFinished(message);
                break;
            }
        }
Example #8
0
        private void PeerATest(EncryptionTypes encryption, bool addInitial)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();

            HandshakeMessage message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);

            byte[]          buffer = message.Encode();
            PeerAEncryption a      = new PeerAEncryption(rig.Manager.InfoHash, encryption);

            if (addInitial)
            {
                a.AddPayload(buffer);
            }

            rig.AddConnection(conn.Incoming);
            IAsyncResult result = a.BeginHandshake(conn.Outgoing, null, null);

#if NETSTANDARD1_5
            if (!result.AsyncWaitHandle.WaitOne(4000))
#else
            if (!result.AsyncWaitHandle.WaitOne(4000, true))
#endif
            { Assert.True(false, "Handshake timed out"); }
            a.EndHandshake(result);

            if (!addInitial)
            {
                a.Encryptor.Encrypt(buffer);
                conn.Outgoing.EndSend(conn.Outgoing.BeginSend(buffer, 0, buffer.Length, null, null));
            }

            int received = conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));
            Assert.True(68 == received, "Recived handshake");

            a.Decryptor.Decrypt(buffer);
            message.Decode(buffer, 0, buffer.Length);
            Assert.Equal(VersionInfo.ProtocolStringV100, message.ProtocolString);

            if (encryption == EncryptionTypes.RC4Full)
            {
                Assert.True(a.Encryptor is RC4);
            }
            else if (encryption == EncryptionTypes.RC4Header)
            {
                Assert.True(a.Encryptor is RC4Header);
            }
            else if (encryption == EncryptionTypes.PlainText)
            {
                Assert.True(a.Encryptor is RC4Header);
            }
        }
Example #9
0
        async Task PeerATest(EncryptionTypes encryption, bool addInitial)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            await rig.Engine.StartAll();

            HandshakeMessage message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);

            byte[]          buffer = message.Encode();
            PeerAEncryption a      = new PeerAEncryption(rig.Manager.InfoHash, encryption);

            if (addInitial)
            {
                a.AddPayload(buffer);
            }

            rig.AddConnection(conn.Incoming);
            var result = a.HandshakeAsync(conn.Outgoing);

            if (!result.Wait(4000))
            {
                Assert.Fail("Handshake timed out");
            }

            if (!addInitial)
            {
                a.Encryptor.Encrypt(buffer);
                await conn.Outgoing.SendAsync(buffer, 0, buffer.Length);
            }

            int received = await conn.Outgoing.ReceiveAsync(buffer, 0, buffer.Length);

            Assert.AreEqual(HandshakeMessage.HandshakeLength, received, "Recived handshake");

            a.Decryptor.Decrypt(buffer);
            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);

            if (encryption == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
            }
            else if (encryption == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
            else if (encryption == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
            }
        }
Example #10
0
        private void PeerATest(EncryptionTypes encryption, bool addInitial)
        {
            rig.Engine.Settings.AllowedEncryption = encryption;
            rig.Engine.StartAll();

            var message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);
            var buffer  = message.Encode();
            var a       = new PeerAEncryption(rig.Manager.InfoHash, encryption);

            if (addInitial)
            {
                a.AddPayload(buffer);
            }

            rig.AddConnection(conn.Incoming);
            var result = a.BeginHandshake(conn.Outgoing, null, null);

            if (!result.AsyncWaitHandle.WaitOne(4000, true))
            {
                Assert.Fail("Handshake timed out");
            }
            a.EndHandshake(result);

            if (!addInitial)
            {
                a.Encryptor.Encrypt(buffer);
                conn.Outgoing.EndSend(conn.Outgoing.BeginSend(buffer, 0, buffer.Length, null, null));
            }

            int received = conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));

            Assert.AreEqual(68, received, "Recived handshake");

            a.Decryptor.Decrypt(buffer);
            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);

            if (encryption == EncryptionTypes.RC4Full)
            {
                Assert.IsInstanceOf <RC4>(a.Encryptor);
            }
            else if (encryption == EncryptionTypes.RC4Header)
            {
                Assert.IsInstanceOf <RC4Header>(a.Encryptor);
            }
            else if (encryption == EncryptionTypes.PlainText)
            {
                Assert.IsInstanceOf <RC4Header>(a.Encryptor);
            }
        }
Example #11
0
        public void SendFinished(Stream stream)
        {
            Record record;

            /* change cipher spec */
            record          = new Record(20, VERSION);
            record.Fragment = new byte[] { 0x01 };
            _recordHandler.ProcessOutputRecord(record);
            SendRecord(stream, record);

            /* change our own cipher spec */
            _recordHandler.ChangeLocalState();


            ProtocolVersion version = VERSION;

            byte[] handshakeMessages = _handshakeStream.ToArray();
            Console.WriteLine("handshake messages length " + handshakeMessages.Length);

            PseudoRandomFunction prf        = _cipherSuite.PseudoRandomFunction;
            HashAlgorithm        verifyHash = prf.CreateVerifyHashAlgorithm(_masterSecret);

            verifyHash.TransformBlock(handshakeMessages, 0, handshakeMessages.Length, handshakeMessages, 0);

            byte[] verifyData;
            if (version == ProtocolVersion.SSL3_0)
            {
                byte[] senderBytes = Encoding.ASCII.GetBytes("CLNT");
                verifyHash.TransformFinalBlock(senderBytes, 0, senderBytes.Length);
                verifyData = verifyHash.Hash;
            }
            else
            {
                verifyHash.TransformFinalBlock(new byte[0], 0, 0);
                byte[] hash = verifyHash.Hash;

                int length = _cipherSuite.PseudoRandomFunction.VerifyDataLength;
                verifyData = _cipherSuite.PseudoRandomFunction.GetBytes(_masterSecret, "client finished", hash, length);
            }
            HandshakeMessage finished = new HandshakeMessage(HandshakeMessageType.Finished, VERSION, verifyData);

            PrintBytes("verify data", finished.Data);

            record          = new Record(22, VERSION);
            record.Fragment = finished.Encode();
            _recordHandler.ProcessOutputRecord(record);
            SendRecord(stream, record);

            Console.WriteLine("encrypted finished sent");
        }
Example #12
0
        public void EncryptorFactoryPeerAPlain()
        {
            rig.Engine.StartAll();

            rig.AddConnection(conn.Incoming);

            var message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);
            var buffer  = message.Encode();

            conn.Outgoing.EndSend(conn.Outgoing.BeginSend(buffer, 0, buffer.Length, null, null));
            conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));

            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);
        }
Example #13
0
        public async Task EncryptorFactoryPeerAPlain()
        {
            await rig.Engine.StartAll();

            rig.AddConnection(conn.Incoming);

            HandshakeMessage message = new HandshakeMessage(rig.Manager.InfoHash, "ABC123ABC123ABC123AB", VersionInfo.ProtocolStringV100);

            byte[] buffer = message.Encode();

            await conn.Outgoing.SendAsync(buffer, 0, buffer.Length);

            await conn.Outgoing.ReceiveAsync(buffer, 0, buffer.Length);

            message.Decode(buffer, 0, buffer.Length);
            Assert.AreEqual(VersionInfo.ProtocolStringV100, message.ProtocolString);
        }
Example #14
0
        static async ReusableTask <EncryptorResult> DoCheckOutgoingConnectionAsync(IConnection2 connection, EncryptionTypes encryption, EngineSettings settings, InfoHash infoHash, HandshakeMessage handshake)
        {
            EncryptionTypes allowedEncryption = settings.AllowedEncryption & encryption;
            bool            supportsRC4Header = allowedEncryption.HasFlag(EncryptionTypes.RC4Header);
            bool            supportsRC4Full   = allowedEncryption.HasFlag(EncryptionTypes.RC4Full);
            bool            supportsPlainText = allowedEncryption.HasFlag(EncryptionTypes.PlainText);

            if ((settings.PreferEncryption || !supportsPlainText) && (supportsRC4Header || supportsRC4Full))
            {
                // First switch to the threadpool as creating encrypted sockets runs expensive computations in the ctor
                await MainLoop.SwitchToThreadpool();

                var encSocket = new PeerAEncryption(infoHash, allowedEncryption, handshake?.Encode());
                await encSocket.HandshakeAsync(connection).ConfigureAwait(false);

                if (encSocket.Decryptor is RC4Header && !supportsRC4Header)
                {
                    throw new EncryptionException("Decryptor was RC4Header but that is not allowed");
                }
                if (encSocket.Decryptor is RC4 && !supportsRC4Full)
                {
                    throw new EncryptionException("Decryptor was RC4Full but that is not allowed");
                }

                return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, null));
            }
            else if (supportsPlainText)
            {
                if (handshake != null)
                {
                    int    length = handshake.ByteLength;
                    byte[] buffer = ClientEngine.BufferPool.Rent(length);
                    handshake.Encode(buffer, 0);
                    try {
                        await NetworkIO.SendAsync(connection, buffer, 0, length, null, null, null).ConfigureAwait(false);
                    } finally {
                        ClientEngine.BufferPool.Return(buffer);
                    }
                }
                return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null));
            }

            connection.Dispose();
            throw new EncryptionException("Invalid handshake received and no decryption works");
        }
        static async ReusableTask <EncryptorResult> DoCheckOutgoingConnectionAsync(IConnection2 connection, EncryptionTypes encryption, EngineSettings settings, InfoHash infoHash, HandshakeMessage handshake)
        {
            var allowedEncryption = settings.AllowedEncryption & encryption;
            var supportsRC4Header = allowedEncryption.HasFlag(EncryptionTypes.RC4Header);
            var supportsRC4Full   = allowedEncryption.HasFlag(EncryptionTypes.RC4Full);
            var supportsPlainText = allowedEncryption.HasFlag(EncryptionTypes.PlainText);

            if ((settings.PreferEncryption || !supportsPlainText) && (supportsRC4Header || supportsRC4Full))
            {
                var encSocket = new PeerAEncryption(infoHash, allowedEncryption, handshake?.Encode());

                await encSocket.HandshakeAsync(connection);

                if (encSocket.Decryptor is RC4Header && !supportsRC4Header)
                {
                    throw new EncryptionException("Decryptor was RC4Header but that is not allowed");
                }
                if (encSocket.Decryptor is RC4 && !supportsRC4Full)
                {
                    throw new EncryptionException("Decryptor was RC4Full but that is not allowed");
                }

                return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, null));
            }
            else if (supportsPlainText)
            {
                if (handshake != null)
                {
                    var length = handshake.ByteLength;
                    var buffer = ClientEngine.BufferPool.Rent(length);
                    handshake.Encode(buffer, 0);
                    try  {
                        await NetworkIO.SendAsync(connection, buffer, 0, length, null, null, null);
                    } finally  {
                        ClientEngine.BufferPool.Return(buffer);
                    }
                }
                return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null));
            }

            connection.Dispose();
            throw new EncryptionException("Invalid handshake received and no decryption works");
        }
Example #16
0
        public void SendClientKey(Stream stream)
        {
            byte[] clientKeys = _cipherSuite.KeyExchangeAlgorithm.GetClientKeys(VERSION, VERSION, _rsaPublicKey);
            if (VERSION != ProtocolVersion.SSL3_0)
            {
                byte[] tmpArray = new byte[clientKeys.Length + 2];
                tmpArray[0] = (byte)(clientKeys.Length >> 8);
                tmpArray[1] = (byte)(clientKeys.Length);
                Buffer.BlockCopy(clientKeys, 0, tmpArray, 2, clientKeys.Length);
                clientKeys = tmpArray;
            }
            HandshakeMessage keyex = new HandshakeMessage(HandshakeMessageType.ClientKeyExchange, VERSION, clientKeys);

            Record record = new Record(22, VERSION);

            record.Fragment = keyex.Encode();
            _recordHandler.ProcessOutputRecord(record);
            SendRecord(stream, record);
        }
        static async ReusableTask <EncryptorResult> DoCheckOutgoingConnectionAsync(IPeerConnection connection, IList <EncryptionType> preferredEncryption, InfoHash infoHash, HandshakeMessage?handshake, Factories factories)
        {
            bool supportsRC4Header = preferredEncryption.Contains(EncryptionType.RC4Header);
            bool supportsRC4Full   = preferredEncryption.Contains(EncryptionType.RC4Full);
            bool supportsPlainText = preferredEncryption.Contains(EncryptionType.PlainText);

            // First switch to the threadpool as creating encrypted sockets runs expensive computations in the ctor
            await MainLoop.SwitchToThreadpool();

            Memory <byte> handshakeBuffer = default;

            using var releaser = handshake == null ? default : NetworkIO.BufferPool.Rent(handshake.ByteLength, out handshakeBuffer);
                                 handshake?.Encode(handshakeBuffer.Span);

                                 if (preferredEncryption[0] != EncryptionType.PlainText)
                                 {
                                     using var encSocket = new PeerAEncryption(factories, infoHash, preferredEncryption, handshakeBuffer);
                                     await encSocket.HandshakeAsync(connection).ConfigureAwait(false);

                                     if (encSocket.Decryptor is RC4Header && !supportsRC4Header)
                                     {
                                         throw new EncryptionException("Decryptor was RC4Header but that is not allowed");
                                     }
                                     if (encSocket.Decryptor is RC4 && !supportsRC4Full)
                                     {
                                         throw new EncryptionException("Decryptor was RC4Full but that is not allowed");
                                     }

                                     return(new EncryptorResult(encSocket.Decryptor !, encSocket.Encryptor !, null));
                                 }
                                 else if (supportsPlainText)
                                 {
                                     if (handshakeBuffer.Length > 0)
                                     {
                                         await NetworkIO.SendAsync(connection, handshakeBuffer, null, null, null).ConfigureAwait(false);
                                     }
                                     return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null));
                                 }

                                 connection.Dispose();
                                 throw new EncryptionException("Invalid handshake received and no decryption works");
        }
Example #18
0
        static async ReusableTask <EncryptorResult> DoCheckOutgoingConnectionAsync(IConnection connection, IList <EncryptionType> preferredEncryption, InfoHash infoHash, HandshakeMessage handshake)
        {
            bool supportsRC4Header = preferredEncryption.Contains(EncryptionType.RC4Header);
            bool supportsRC4Full   = preferredEncryption.Contains(EncryptionType.RC4Full);
            bool supportsPlainText = preferredEncryption.Contains(EncryptionType.PlainText);

            // First switch to the threadpool as creating encrypted sockets runs expensive computations in the ctor
            await MainLoop.SwitchToThreadpool();

            if (preferredEncryption[0] != EncryptionType.PlainText)
            {
                var encSocket = new PeerAEncryption(infoHash, preferredEncryption, handshake?.Encode());
                await encSocket.HandshakeAsync(connection).ConfigureAwait(false);

                if (encSocket.Decryptor is RC4Header && !supportsRC4Header)
                {
                    throw new EncryptionException("Decryptor was RC4Header but that is not allowed");
                }
                if (encSocket.Decryptor is RC4 && !supportsRC4Full)
                {
                    throw new EncryptionException("Decryptor was RC4Full but that is not allowed");
                }

                return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, null));
            }
            else if (supportsPlainText)
            {
                if (handshake != null)
                {
                    int length = handshake.ByteLength;
                    using (NetworkIO.BufferPool.Rent(length, out ByteBuffer buffer)) {
                        handshake.Encode(buffer.Data, 0);
                        await NetworkIO.SendAsync(connection, buffer, 0, length, null, null, null).ConfigureAwait(false);
                    }
                }
                return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null));
            }

            connection.Dispose();
            throw new EncryptionException("Invalid handshake received and no decryption works");
        }
Example #19
0
        private void Handshake(EncryptionTypes encryptionA, EncryptionTypes encryptionB, bool addInitial)
        {
            bool doneA = false;
            bool doneB = false;

            HandshakeMessage m = new HandshakeMessage(rig.Torrent.InfoHash, "12345123451234512345", VersionInfo.ProtocolStringV100);

            byte[] handshake = m.Encode();

            PeerAEncryption a = new PeerAEncryption(rig.Torrent.InfoHash, encryptionA);

            if (addInitial)
            {
                a.AddPayload(handshake);
            }

            PeerBEncryption b = new PeerBEncryption(new InfoHash[] { rig.Torrent.InfoHash }, encryptionB);

            IAsyncResult resultA = a.BeginHandshake(conn.Outgoing, null, null);
            IAsyncResult resultB = b.BeginHandshake(conn.Incoming, null, null);

            WaitHandle[] handles = new WaitHandle[] { resultA.AsyncWaitHandle, resultB.AsyncWaitHandle };
            int          count   = 1000;

            while (!WaitHandle.WaitAll(handles, 5, true))
            {
                if (!doneA && (doneA = resultA.IsCompleted))
                {
                    a.EndHandshake(resultA);
                }
                if (!doneB && (doneB = resultB.IsCompleted))
                {
                    b.EndHandshake(resultB);
                }

                if (count-- == 0)
                {
                    Assert.Fail("Could not handshake");
                }
            }
            if (!doneA)
            {
                a.EndHandshake(resultA);
            }
            if (!doneB)
            {
                b.EndHandshake(resultB);
            }

            HandshakeMessage d = new HandshakeMessage();

            if (!addInitial)
            {
                a.Encrypt(handshake, 0, handshake.Length);
                b.Decrypt(handshake, 0, handshake.Length);
                d.Decode(handshake, 0, handshake.Length);
            }
            else
            {
                d.Decode(b.InitialData, 0, b.InitialData.Length);
            }
            Assert.AreEqual(m, d);


            if (encryptionA == EncryptionTypes.RC4Full || encryptionB == EncryptionTypes.RC4Full)
            {
                Assert.IsTrue(a.Encryptor is RC4);
                Assert.IsTrue(b.Encryptor is RC4);
            }
            else if (encryptionA == EncryptionTypes.RC4Header || encryptionB == EncryptionTypes.RC4Header)
            {
                Assert.IsTrue(a.Encryptor is RC4Header);
                Assert.IsTrue(b.Encryptor is RC4Header);
            }
            else if (encryptionA == EncryptionTypes.PlainText || encryptionB == EncryptionTypes.PlainText)
            {
                Assert.IsTrue(a.Encryptor is PlainTextEncryption);
                Assert.IsTrue(b.Encryptor is PlainTextEncryption);
            }
        }