예제 #1
0
        async Task Handshake(IList <EncryptionType> outgoingEncryption, IList <EncryptionType> incomingEncryption, bool appendInitialPayload)
        {
            var handshakeIn  = new HandshakeMessage(InfoHash, IncomingId, VersionInfo.ProtocolStringV100);
            var handshakeOut = new HandshakeMessage(InfoHash, OutgoingId, VersionInfo.ProtocolStringV100);

            var incomingTask = EncryptorFactory.CheckIncomingConnectionAsync(Incoming, incomingEncryption, SKeys);
            var outgoingTask = EncryptorFactory.CheckOutgoingConnectionAsync(Outgoing, outgoingEncryption, InfoHash, appendInitialPayload ? handshakeOut : null);

            // If the handshake was not part of the initial payload, send it now.
            var outgoingCrypto = await outgoingTask;

            if (!appendInitialPayload)
            {
                await PeerIO.SendMessageAsync(Outgoing, outgoingCrypto.Encryptor, handshakeOut, null, null, null);
            }

            // Receive the handshake and make sure it decrypted correctly.
            var incomingCrypto = await incomingTask;

            Assert.AreEqual(OutgoingId, incomingCrypto.Handshake.PeerId, "#1a");

            // Send the other handshake.
            await PeerIO.SendMessageAsync(Incoming, incomingCrypto.Encryptor, handshakeIn, null, null, null);

            // Receive the other handshake and make sure it decrypted ok on the other side.
            handshakeIn = await PeerIO.ReceiveHandshakeAsync(Outgoing, outgoingCrypto.Decryptor);

            Assert.AreEqual(IncomingId, handshakeIn.PeerId, "#1b");

            if (outgoingEncryption[0] == EncryptionType.PlainText)
            {
                // If the outgoing encryption is plain text, then the whole thing is plain text
                Assert.IsInstanceOf <PlainTextEncryption> (incomingCrypto.Decryptor, "#2a");
                Assert.IsInstanceOf <PlainTextEncryption> (outgoingCrypto.Decryptor, "#2b");
            }
            else
            {
                EncryptionType expected;

                if (outgoingEncryption.Contains(EncryptionType.RC4Full) && outgoingEncryption.Contains(EncryptionType.RC4Header))
                {
                    // If the outgoing encryption supports both RC4Full and RC4Header, the final type is determined by
                    // the priority associated with the 'Incoming' connection as it will decide between Header or Full if
                    // the Outgoing connection asks for both.
                    expected = EncryptionTypes.PreferredRC4(incomingEncryption).Value;
                }
                else
                {
                    // Otherwise the outgoing encryption will specify a single RC4 type, so the incoming connection
                    // will either accept it or close the connection.
                    expected = EncryptionTypes.PreferredRC4(outgoingEncryption).Value;
                }

                if (expected == EncryptionType.RC4Full)
                {
                    Assert.IsInstanceOf <RC4> (incomingCrypto.Decryptor, "#3a");
                    Assert.IsInstanceOf <RC4> (outgoingCrypto.Decryptor, "#3b");
                }
                else if (expected == EncryptionType.RC4Header)
                {
                    Assert.IsInstanceOf <RC4Header> (incomingCrypto.Decryptor, "#4a");
                    Assert.IsInstanceOf <RC4Header> (outgoingCrypto.Decryptor, "#4b");
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
        }