예제 #1
0
        private static async Task Client()
        {
            // Connect to the server using the named pipe.
            using (var client = new NamedPipeClientStream(ServerName, PipeName, PipeDirection.InOut))
            {
                await client.ConnectAsync();

                // Select the initial Noise protocol and configuration.
                var initial = Protocol.Parse("Noise_NN_25519_ChaChaPoly_SHA256".AsSpan());
                var config  = new ProtocolConfig(initiator: true);

                using (var noise = new NoiseSocket(initial, config, client))
                {
                    // Send the initial handshake message to the server. In the real world the
                    // negotiation data would contain the initial protocol, supported protocols
                    // for the switch and retry cases, and maybe some other negotiation options.
                    await noise.WriteHandshakeMessageAsync(negotiationData : null);

                    // Receive the negotiation data from the server. In this example we will
                    // assume that the server decided to retry with Noise_XX_25519_AESGCM_BLAKE2b.
                    await noise.ReadNegotiationDataAsync();

                    // New protocol requires static key, so it's generated here.
                    using (var keyPair = KeyPair.Generate())
                    {
                        // The client again plays the role of the initiator.
                        config = new ProtocolConfig(initiator: true, s: keyPair.PrivateKey);

                        // Retry with a protocol different from the initial one.
                        noise.Retry(protocol, config);

                        // Ignore the empty handshake message.
                        await noise.IgnoreHandshakeMessageAsync();

                        // Finish the handshake using the new protocol.
                        await noise.WriteHandshakeMessageAsync();

                        await noise.ReadNegotiationDataAsync();

                        await noise.ReadHandshakeMessageAsync();

                        await noise.WriteHandshakeMessageAsync();

                        // Send the transport message to the server.
                        var request = Encoding.UTF8.GetBytes("I'm cooking MC's like a pound of bacon");
                        await noise.WriteMessageAsync(request);

                        // Receive the transport message from the
                        // server and print it to the standard output.
                        var response = await noise.ReadMessageAsync();

                        Console.WriteLine(Encoding.UTF8.GetString(response));
                    }
                }
            }
        }
예제 #2
0
        private static async Task Server()
        {
            // Listen for incoming TCP connections.
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                socket.Bind(new IPEndPoint(IPAddress.Loopback, Port));
                socket.Listen((int)SocketOptionName.MaxConnections);

                // Generate the static key pair.
                using (var keyPair = KeyPair.Generate())
                {
                    var config = new ProtocolConfig(initiator: false, s: keyPair.PrivateKey);

                    // Accept the connection and initialize the NoiseSocket with its network stream.
                    using (var client = await socket.AcceptAsync())
                        using (var stream = new NetworkStream(client))
                            using (var noise = new NoiseSocket(initial, config, stream))
                            {
                                // Receive the negotiation data from the client. In the real world the
                                // negotiation data would contain the initial protocol, supported protocols
                                // for the switch and retry cases, and maybe some other negotiation options.
                                await noise.ReadNegotiationDataAsync();

                                try
                                {
                                    await noise.ReadHandshakeMessageAsync();
                                }
                                catch (CryptographicException)
                                {
                                    // The decryption of the initial handshake message failed
                                    // because the client had an outdated remote static public key.
                                }

                                // The server decides to switch to a fallback protocol.
                                config = new ProtocolConfig(initiator: true, s: keyPair.PrivateKey);
                                noise.Switch(fallback, config);

                                // Send the first handshake message using the new protocol. In the
                                // real world the negotiation data would encode the details about
                                // the server's desicion to switch protocol.
                                await noise.WriteHandshakeMessageAsync(negotiationData : null, paddedLength : PaddedLength);

                                // Finish the handshake using the new protocol.
                                await noise.ReadNegotiationDataAsync();

                                await noise.ReadHandshakeMessageAsync();

                                // Receive the transport message from the client.
                                var request = await noise.ReadMessageAsync();

                                // Echo the message back to the client.
                                await noise.WriteMessageAsync(request, PaddedLength);
                            }
                }
            }
        }
예제 #3
0
        private static async Task Server()
        {
            // Listen for connections from TCP network clients.
            var listener = new TcpListener(IPAddress.Loopback, Port);

            listener.Start();

            try
            {
                // Accept the connection from the TCP client.
                using (var client = await listener.AcceptTcpClientAsync())
                {
                    // Generate the static key pair.
                    using (var keyPair = KeyPair.Generate())
                    {
                        var config = new ProtocolConfig(initiator: false, s: keyPair.PrivateKey);

                        // Initialize the NoiseSocket with the network stream.
                        using (var stream = client.GetStream())
                            using (var noise = new NoiseSocket(stream))
                            {
                                // Receive the negotiation data from the client. In the real world the
                                // negotiation data would contain the initial protocol, supported protocols
                                // for the switch and retry cases, and maybe some other negotiation options.
                                await noise.ReadNegotiationDataAsync();

                                // Accept the offered protocol.
                                noise.Accept(protocol, config);

                                // Finish the handshake.
                                await noise.ReadHandshakeMessageAsync();

                                await noise.WriteHandshakeMessageAsync(paddedLength : PaddedLength);

                                await noise.ReadNegotiationDataAsync();

                                await noise.ReadHandshakeMessageAsync();

                                // Receive the transport message from the client.
                                var request = await noise.ReadMessageAsync();

                                // Echo the message back to the client.
                                await noise.WriteMessageAsync(request, PaddedLength);
                            }
                    }
                }
            }
            finally
            {
                listener.Stop();
            }
        }
예제 #4
0
        private static async Task Server()
        {
            // Create the named pipe and wait for the client to connect to it.
            using (var server = new NamedPipeServerStream(PipeName, PipeDirection.InOut))
            {
                await server.WaitForConnectionAsync();

                // Initialize the NoiseSocket.
                using (var noise = new NoiseSocket(server))
                {
                    // Receive the negotiation data from the client. In the real world the
                    // negotiation data would contain the initial protocol, supported protocols
                    // for the switch and retry cases, and maybe some other negotiation options.
                    await noise.ReadNegotiationDataAsync();

                    // Read the handshake message from the client, but without decrypting it.
                    await noise.IgnoreHandshakeMessageAsync();

                    // New protocol requires static key, so we generate it here.
                    using (var keyPair = KeyPair.Generate())
                    {
                        // The server decides to retry with a new protocol.
                        // It again plays the role of the responder.
                        var config = new ProtocolConfig(initiator: false, s: keyPair.PrivateKey);
                        noise.Retry(protocol, config);

                        // Request a retry from the client. In the real world the negotiation data
                        // would encode the details about the server's desicion to make a retry request.
                        await noise.WriteEmptyHandshakeMessageAsync(negotiationData : null);

                        // Receive the negotiation data from the client. The client will
                        // usually just confirm the server's choice of the retry protocol.
                        await noise.ReadNegotiationDataAsync();

                        // Finish the handshake using the new protocol.
                        await noise.ReadHandshakeMessageAsync();

                        await noise.WriteHandshakeMessageAsync();

                        await noise.ReadNegotiationDataAsync();

                        await noise.ReadHandshakeMessageAsync();

                        // Receive the transport message from the client.
                        var request = await noise.ReadMessageAsync();

                        // Echo the message back to the client.
                        await noise.WriteMessageAsync(request);
                    }
                }
            }
        }
예제 #5
0
        public async Task WriteEmptyHandshakeMessageAsync(NoiseSocket socket, byte[] negotiationData)
        {
            await socket.WriteEmptyHandshakeMessageAsync(negotiationData);

            var message = new Message
            {
                NegotiationData = negotiationData,
                Value           = Utilities.ReadMessage(stream)
            };

            stream.Position = 0;
            Messages.Add(message);
        }
예제 #6
0
        private static async Task Client()
        {
            // Connect to the server using the TCP socket.
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                await socket.ConnectAsync(IPAddress.Loopback, Port);

                // Generate the static key pair.
                using (var keyPair = KeyPair.Generate())
                {
                    // In this example the client has an outdated remote static public key. The server will
                    // fail to decrypt the initial handshake message, which will trigger a fallback.
                    var config = new ProtocolConfig(initiator: true, s: keyPair.PrivateKey, rs: new byte[32]);

                    // Initialize the NoiseSocket with the network stream.
                    using (var stream = new NetworkStream(socket))
                        using (var noise = new NoiseSocket(initial, config, stream))
                        {
                            // Send the initial handshake message to the server. In the real world the
                            // negotiation data would contain the initial protocol, supported protocols
                            // for the switch and retry cases, and maybe some other negotiation options.
                            await noise.WriteHandshakeMessageAsync(negotiationData : null, paddedLength : PaddedLength);

                            // Receive the negotiation data from the server. In this example we will
                            // assume that the server decided to switch to Noise_XX_25519_AESGCM_BLAKE2b.
                            await noise.ReadNegotiationDataAsync();

                            // The client now plays the role of the responder.
                            config = new ProtocolConfig(initiator: false, s: keyPair.PrivateKey);

                            // Switch to a protocol different from the initial one.
                            noise.Switch(fallback, config);

                            // Finish the handshake using the new protocol.
                            await noise.ReadHandshakeMessageAsync();

                            await noise.WriteHandshakeMessageAsync(paddedLength : PaddedLength);

                            // Send the padded transport message to the server.
                            var request = Encoding.UTF8.GetBytes("I'm cooking MC's like a pound of bacon");
                            await noise.WriteMessageAsync(request, PaddedLength);

                            // Receive the transport message from the
                            // server and print it to the standard output.
                            var response = await noise.ReadMessageAsync();

                            Console.WriteLine(Encoding.UTF8.GetString(response));
                        }
                }
            }
        }
예제 #7
0
        public async Task WriteMessageAsync(NoiseSocket socket, byte[] messageBody)
        {
            await socket.WriteMessageAsync(messageBody, paddedLength);

            var message = new Message
            {
                MessageBody  = messageBody,
                PaddedLength = paddedLength,
                Value        = Utilities.ReadMessage(stream)
            };

            stream.Position = 0;
            Messages.Add(message);
        }
예제 #8
0
        public async Task WriteHandshakeMessageAsync(NoiseSocket socket, byte[] negotiationData, byte[] messageBody)
        {
            bool isNextMessageEncrypted = socket.IsNextMessageEncrypted;
            await socket.WriteHandshakeMessageAsync(negotiationData, messageBody, paddedLength);

            var message = new Message
            {
                NegotiationData = negotiationData,
                MessageBody     = messageBody,
                PaddedLength    = isNextMessageEncrypted ? paddedLength : default(ushort),
                Value           = Utilities.ReadMessage(stream)
            };

            stream.Position = 0;
            Messages.Add(message);
        }
예제 #9
0
        private static async Task Client()
        {
            // Open the TCP connection to the server.
            using (var client = new TcpClient())
            {
                await client.ConnectAsync(IPAddress.Loopback, Port);

                // Generate the static key pair.
                using (var keyPair = KeyPair.Generate())
                {
                    var config = new ProtocolConfig(initiator: true, s: keyPair.PrivateKey);

                    // Initialize the NoiseSocket with the network stream.
                    using (var stream = client.GetStream())
                        using (var noise = new NoiseSocket(protocol, config, stream))
                        {
                            // Send the initial handshake message to the server. In the real world the
                            // negotiation data would contain the initial protocol, supported protocols
                            // for the switch and retry cases, and maybe some other negotiation options.
                            await noise.WriteHandshakeMessageAsync(negotiationData : null, paddedLength : PaddedLength);

                            // Receive the negotiation data from the server. In this example we will
                            // assume that the server decided to accept the offered protocol.
                            await noise.ReadNegotiationDataAsync();

                            // Finish the handshake.
                            await noise.ReadHandshakeMessageAsync();

                            await noise.WriteHandshakeMessageAsync(paddedLength : PaddedLength);

                            // Send the padded transport message to the server.
                            var request = Encoding.UTF8.GetBytes("I'm cooking MC's like a pound of bacon");
                            await noise.WriteMessageAsync(request, PaddedLength);

                            // Receive the transport message from the
                            // server and print it to the standard output.
                            var response = await noise.ReadMessageAsync();

                            Console.WriteLine(Encoding.UTF8.GetString(response));
                        }
                }
            }
        }
예제 #10
0
        private static async Task Run()
        {
            using (var client = new TcpClient())
            {
                await client.ConnectAsync(IPAddress.Loopback, Port);

                using (var keyPair = KeyPair.Generate())
                {
                    var config = new ProtocolConfig(initiator: true, s: keyPair.PrivateKey);

                    using (var stream = client.GetStream())
                        using (var noise = new NoiseSocket(protocol, config, stream))
                        {
                            await noise.WriteHandshakeMessageAsync(negotiationData : clientNegotiationData, paddedLength : PaddedLength);

                            var serverNegotiationData = await noise.ReadNegotiationDataAsync();

                            if (serverNegotiationData.Length > 0)
                            {
                                throw new Exception("Unsupported Noise protocol.");
                            }

                            await noise.ReadHandshakeMessageAsync();

                            await noise.WriteHandshakeMessageAsync(paddedLength : PaddedLength);

                            var request = Encoding.UTF8.GetBytes("I'm cooking MC's like a pound of bacon");
                            await noise.WriteMessageAsync(request, PaddedLength);

                            var response = await noise.ReadMessageAsync();

                            Console.WriteLine(Encoding.UTF8.GetString(response));
                        }
                }
            }
        }
예제 #11
0
        public async Task TestVectors()
        {
            var s    = File.ReadAllText("Vectors/noisesocket.json");
            var json = JObject.Parse(s);

            using (var stream = new MemoryStream())
            {
                foreach (var vector in json["vectors"])
                {
                    var initialConfig = vector["initial"];
                    var switchConfig  = vector["switch"];
                    var retryConfig   = vector["retry"];

                    var alicePrologue = GetBytes(vector, "alice_prologue");
                    var alicePsks     = GetPsks(vector, "alice_psks");
                    var bobPrologue   = GetBytes(vector, "bob_prologue");
                    var bobPsks       = GetPsks(vector, "bob_psks");
                    var handshakeHash = GetBytes(vector, "handshake_hash");

                    var config      = vector["initial"].ToObject <Config>();
                    var aliceConfig = new ProtocolConfig(true, alicePrologue, config.AliceStatic, config.AliceRemoteStatic, alicePsks);
                    var bobConfig   = new ProtocolConfig(false, bobPrologue, config.BobStatic, config.BobRemoteStatic, bobPsks);

                    var protocol = Protocol.Parse(config.ProtocolName.AsSpan());
                    var queue    = ReadMessages(vector["messages"]);

                    var alice = new NoiseSocket(protocol, aliceConfig, stream, true);
                    var bob   = new NoiseSocket(protocol, bobConfig, stream, true);

                    var aliceEphemeral = config.AliceEphemeral;
                    var bobEphemeral   = config.BobEphemeral;

                    alice.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, aliceEphemeral));
                    bob.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, bobEphemeral));

                    var writer = alice;
                    var reader = bob;

                    if (switchConfig == null && retryConfig == null)
                    {
                        var message = queue.Dequeue();
                        stream.Position = 0;

                        await alice.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                        Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                        stream.Position = 0;
                        Assert.Equal(message.NegotiationData, await bob.ReadNegotiationDataAsync());

                        bob.Accept(protocol, bobConfig);
                        Assert.Equal(message.MessageBody, await bob.ReadHandshakeMessageAsync());

                        Utilities.Swap(ref writer, ref reader);
                    }
                    else if (switchConfig != null)
                    {
                        config   = switchConfig.ToObject <Config>();
                        protocol = Protocol.Parse(config.ProtocolName.AsSpan());

                        aliceConfig = new ProtocolConfig(false, alicePrologue, config.AliceStatic, config.AliceRemoteStatic, alicePsks);
                        bobConfig   = new ProtocolConfig(true, bobPrologue, config.BobStatic, config.BobRemoteStatic, bobPsks);

                        var message = queue.Dequeue();
                        stream.Position = 0;

                        await alice.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                        Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                        stream.Position = 0;
                        Assert.Equal(message.NegotiationData, await bob.ReadNegotiationDataAsync());

                        if ((protocol.Modifiers & PatternModifiers.Fallback) != 0)
                        {
                            await bob.ReadHandshakeMessageAsync();

                            bob.Switch(protocol, bobConfig);

                            message         = queue.Dequeue();
                            stream.Position = 0;

                            await bob.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                            Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                            stream.Position = 0;
                            Assert.Equal(message.NegotiationData, await alice.ReadNegotiationDataAsync());

                            alice.Switch(protocol, aliceConfig);
                            Assert.Equal(message.MessageBody, await alice.ReadHandshakeMessageAsync());
                        }
                        else
                        {
                            bob.Switch(protocol, bobConfig);
                            bob.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, config.BobEphemeral));
                            await bob.IgnoreHandshakeMessageAsync();

                            message         = queue.Dequeue();
                            stream.Position = 0;

                            await bob.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                            Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                            stream.Position = 0;
                            Assert.Equal(message.NegotiationData, await alice.ReadNegotiationDataAsync());

                            alice.Switch(protocol, aliceConfig);
                            alice.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, config.AliceEphemeral));
                            Assert.Equal(message.MessageBody, await alice.ReadHandshakeMessageAsync());
                        }
                    }
                    else if (retryConfig != null)
                    {
                        config   = retryConfig.ToObject <Config>();
                        protocol = Protocol.Parse(config.ProtocolName.AsSpan());

                        aliceConfig = new ProtocolConfig(true, alicePrologue, config.AliceStatic, config.AliceRemoteStatic, alicePsks);
                        bobConfig   = new ProtocolConfig(false, bobPrologue, config.BobStatic, config.BobRemoteStatic, bobPsks);

                        var message = queue.Dequeue();
                        stream.Position = 0;

                        await alice.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                        Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                        stream.Position = 0;
                        Assert.Equal(message.NegotiationData, await bob.ReadNegotiationDataAsync());

                        bob.Retry(protocol, bobConfig);
                        bob.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, config.BobEphemeral));
                        await bob.IgnoreHandshakeMessageAsync();

                        message         = queue.Dequeue();
                        stream.Position = 0;

                        await bob.WriteEmptyHandshakeMessageAsync(message.NegotiationData);

                        Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                        stream.Position = 0;
                        Assert.Equal(message.NegotiationData, await alice.ReadNegotiationDataAsync());

                        alice.Retry(protocol, aliceConfig);
                        alice.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, config.AliceEphemeral));
                        await alice.IgnoreHandshakeMessageAsync();
                    }

                    while (queue.Count > 0)
                    {
                        var message = queue.Dequeue();

                        if (writer.HandshakeHash.IsEmpty)
                        {
                            stream.Position = 0;
                            await writer.WriteHandshakeMessageAsync(message.NegotiationData, message.MessageBody, message.PaddedLength);

                            Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                            stream.Position = 0;
                            Assert.Empty(await reader.ReadNegotiationDataAsync());
                            Assert.Equal(message.MessageBody, await reader.ReadHandshakeMessageAsync());
                        }
                        else
                        {
                            stream.Position = 0;
                            await writer.WriteMessageAsync(message.MessageBody, message.PaddedLength);

                            Assert.Equal(message.Value, Utilities.ReadMessage(stream));

                            stream.Position = 0;
                            Assert.Equal(message.MessageBody, await reader.ReadMessageAsync());
                        }

                        Utilities.Swap(ref writer, ref reader);
                    }

                    Assert.Equal(handshakeHash, writer.HandshakeHash.ToArray());
                    Assert.Equal(handshakeHash, reader.HandshakeHash.ToArray());

                    alice.Dispose();
                    bob.Dispose();
                }
            }
        }
예제 #12
0
        public static async Task <IEnumerable <Vector> > Generate()
        {
            var vectors = new List <Vector>();

            using (var stream = new MemoryStream())
            {
                foreach (var test in GetTests())
                {
                    var aliceConfig = new ProtocolConfig(
                        initiator: true,
                        prologue: PrologueRaw,
                        s: test.InitStaticRequired ? AliceStaticRaw : null,
                        rs: test.InitRemoteStaticRequired ? BobStaticPublicRaw : null,
                        psks: test.PsksRequired ? psksRaw : null
                        );

                    var bobConfig = new ProtocolConfig(
                        initiator: false,
                        prologue: PrologueRaw,
                        s: test.RespStaticRequired ? BobStaticRaw : null,
                        rs: test.RespRemoteStaticRequired ? AliceStaticPublicRaw : null,
                        psks: test.PsksRequired ? psksRaw : null
                        );

                    var alice = new NoiseSocket(test.Protocol, aliceConfig, stream, true);
                    var bob   = new NoiseSocket(test.Protocol, bobConfig, stream, true);

                    alice.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, AliceEphemeralRaw.ToArray()));
                    bob.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, BobEphemeralRaw.ToArray()));

                    var proxy = new SocketProxy(stream, (ushort)test.PaddedLength);
                    var queue = new Queue <byte[]>(payloads);

                    var writer = alice;
                    var reader = bob;

                    if (test.Response == Response.Accept)
                    {
                        await proxy.WriteHandshakeMessageAsync(alice, InitialNegotiationData, queue.Dequeue());

                        await bob.ReadNegotiationDataAsync();

                        bob.Accept(test.Protocol, bobConfig);

                        await bob.ReadHandshakeMessageAsync();

                        stream.Position = 0;

                        Utilities.Swap(ref writer, ref reader);
                    }
                    else if (test.Response == Response.Switch)
                    {
                        await proxy.WriteHandshakeMessageAsync(alice, InitialNegotiationData, queue.Dequeue());

                        await bob.ReadNegotiationDataAsync();

                        if (test.Fallback != null)
                        {
                            await bob.ReadHandshakeMessageAsync();

                            stream.Position = 0;

                            bob.Switch(test.Fallback, new ProtocolConfig(true, PrologueRaw, BobStaticRaw));

                            await proxy.WriteHandshakeMessageAsync(bob, SwitchNegotiationData, queue.Dequeue());

                            await alice.ReadNegotiationDataAsync();

                            alice.Switch(test.Fallback, new ProtocolConfig(false, PrologueRaw, AliceStaticRaw));

                            await alice.ReadHandshakeMessageAsync();

                            stream.Position = 0;
                        }
                        else
                        {
                            bob.Switch(test.Protocol, aliceConfig);
                            bob.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, AliceEphemeralRaw.ToArray()));

                            await bob.IgnoreHandshakeMessageAsync();

                            stream.Position = 0;

                            await proxy.WriteHandshakeMessageAsync(bob, SwitchNegotiationData, queue.Dequeue());

                            await alice.ReadNegotiationDataAsync();

                            alice.Switch(test.Protocol, bobConfig);
                            alice.SetInitializer(handshakeState => Utilities.SetDh(handshakeState, BobEphemeralRaw.ToArray()));

                            await alice.ReadHandshakeMessageAsync();

                            stream.Position = 0;
                        }
                    }
                    else if (test.Response == Response.Retry)
                    {
                        await proxy.WriteHandshakeMessageAsync(alice, InitialNegotiationData, queue.Dequeue());

                        await bob.ReadNegotiationDataAsync();

                        bob.Retry(test.Protocol, bobConfig);

                        await bob.IgnoreHandshakeMessageAsync();

                        stream.Position = 0;

                        await proxy.WriteEmptyHandshakeMessageAsync(bob, RetryNegotiationData);

                        await alice.ReadNegotiationDataAsync();

                        alice.Retry(test.Protocol, aliceConfig);

                        await alice.IgnoreHandshakeMessageAsync();

                        stream.Position = 0;
                    }

                    while (queue.Count > 0)
                    {
                        if (writer.HandshakeHash.IsEmpty)
                        {
                            await proxy.WriteHandshakeMessageAsync(writer, null, queue.Dequeue());

                            await reader.ReadNegotiationDataAsync();

                            await reader.ReadHandshakeMessageAsync();

                            stream.Position = 0;
                        }
                        else
                        {
                            await proxy.WriteMessageAsync(writer, queue.Dequeue());
                        }

                        Utilities.Swap(ref writer, ref reader);
                    }

                    var initialConfig = new Config
                    {
                        ProtocolName      = Encoding.ASCII.GetString(test.Protocol.Name),
                        AliceStatic       = aliceConfig.LocalStatic,
                        AliceEphemeral    = AliceEphemeralRaw,
                        AliceRemoteStatic = aliceConfig.RemoteStatic,
                        BobStatic         = bobConfig.LocalStatic,
                        BobEphemeral      = BobEphemeralRaw,
                        BobRemoteStatic   = bobConfig.RemoteStatic
                    };

                    var switchConfig = new Config
                    {
                        ProtocolName      = Encoding.ASCII.GetString(test.Protocol.Name),
                        AliceStatic       = bobConfig.LocalStatic,
                        AliceEphemeral    = BobEphemeralRaw,
                        AliceRemoteStatic = bobConfig.RemoteStatic,
                        BobStatic         = aliceConfig.LocalStatic,
                        BobEphemeral      = AliceEphemeralRaw,
                        BobRemoteStatic   = aliceConfig.RemoteStatic
                    };

                    if (test.Fallback != null)
                    {
                        switchConfig = new Config
                        {
                            ProtocolName   = Encoding.ASCII.GetString(test.Fallback.Name),
                            AliceStatic    = AliceStaticRaw,
                            AliceEphemeral = AliceEphemeralRaw,
                            BobStatic      = BobStaticRaw,
                            BobEphemeral   = BobEphemeralRaw
                        };
                    }

                    var vector = new Vector
                    {
                        Initial       = initialConfig,
                        Switch        = test.Response == Response.Switch ? switchConfig : null,
                        Retry         = test.Response == Response.Retry ? initialConfig : null,
                        AlicePrologue = PrologueHex,
                        AlicePsks     = test.PsksRequired ? psksHex : null,
                        BobPrologue   = PrologueHex,
                        BobPsks       = test.PsksRequired ? psksHex : null,
                        HandshakeHash = Hex.Encode(writer.HandshakeHash.ToArray()),
                        Messages      = proxy.Messages
                    };

                    alice.Dispose();
                    bob.Dispose();

                    vectors.Add(vector);
                }
            }

            return(vectors);
        }