Exemple #1
0
        static async Task <EncryptorResult> DoCheckOutgoingConnectionAsync(IConnection connection, EncryptionTypes encryption, EngineSettings settings, InfoHash infoHash)
        {
            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);
                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");
                }

                var data = encSocket.InitialData?.Length > 0 ? encSocket.InitialData : null;
                return(new EncryptorResult(encSocket.Decryptor, encSocket.Encryptor, data));
            }
            else if (supportsPlainText)
            {
                return(new EncryptorResult(PlainTextEncryption.Instance, PlainTextEncryption.Instance, null));
            }
            throw new EncryptionException("Invalid handshake received and no decryption works");
        }
        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);
            }
        }
        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);
            }
        }
        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");
        }
        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");
        }
        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.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));
            }

            var received = conn.Outgoing.EndReceive(conn.Outgoing.BeginReceive(buffer, 0, buffer.Length, null, null));
            Assert.Equal(68, received);

            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);
        }
Exemple #8
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 byte[][] { 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);
            }
        }
Exemple #9
0
        static async Task <byte[]> CheckEncryptionAsync(PeerId id, int bytesToReceive, InfoHash[] sKeys, CancellationToken token)
        {
            IConnection connection        = id.Connection;
            var         allowedEncryption = (id.Engine?.Settings.AllowedEncryption ?? EncryptionTypes.All) & id.Peer.Encryption;
            var         supportsRC4Header = allowedEncryption.HasFlag(EncryptionTypes.RC4Header);
            var         supportsRC4Full   = allowedEncryption.HasFlag(EncryptionTypes.RC4Full);
            var         supportsPlainText = allowedEncryption.HasFlag(EncryptionTypes.PlainText);

            // If the connection is incoming, receive the handshake before
            // trying to decide what encryption to use
            if (connection.IsIncoming)
            {
                var buffer = new byte[bytesToReceive];
                await NetworkIO.ReceiveAsync(connection, buffer, 0, bytesToReceive, null, null, null).ConfigureAwait(false);

                HandshakeMessage message = new HandshakeMessage();
                message.Decode(buffer, 0, buffer.Length);

                if (message.ProtocolString == VersionInfo.ProtocolStringV100)
                {
                    if (supportsPlainText)
                    {
                        id.Encryptor = id.Decryptor = PlainTextEncryption.Instance;
                        return(buffer);
                    }
                }
                else if (supportsRC4Header || supportsRC4Full)
                {
                    // The data we just received was part of an encrypted handshake and was *not* the BitTorrent handshake
                    var encSocket = new PeerBEncryption(sKeys, EncryptionTypes.All);
                    await encSocket.HandshakeAsync(connection, buffer, 0, buffer.Length);

                    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");
                    }

                    id.Decryptor = encSocket.Decryptor;
                    id.Encryptor = encSocket.Encryptor;
                    return(encSocket.InitialData?.Length > 0 ? encSocket.InitialData : null);
                }
            }
            else
            {
                if ((id.Engine.Settings.PreferEncryption || !supportsPlainText) && (supportsRC4Header || supportsRC4Full))
                {
                    var encSocket = new PeerAEncryption(id.TorrentManager.InfoHash, allowedEncryption);
                    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");
                    }

                    id.Decryptor = encSocket.Decryptor;
                    id.Encryptor = encSocket.Encryptor;
                    return(encSocket.InitialData?.Length > 0 ? encSocket.InitialData : null);
                }
                else if (supportsPlainText)
                {
                    id.Encryptor = id.Decryptor = PlainTextEncryption.Instance;
                    return(null);
                }
            }

            throw new EncryptionException("Invalid handshake received and no decryption works");
        }