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