// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.OpenMU.Network.Tests; using System.Buffers; using System.IO.Pipelines; using MUnique.OpenMU.Network.SimpleModulus; using MUnique.OpenMU.Network.Xor; /// /// Tests the cycle of encrypting and decrypting a packet purely due pipes. /// [TestFixture] public class PipelinedEncryptDecryptCycleTests { /// /// Tests the encryption and decryption cycle of C3-packets from client to server. /// These packets get encrypted first by , then by using client-side keys. /// Then it gets decrypted by the using server-side keys and finally by the . /// /// The task. [Test] public async Task ClientToServerC3Async() { var packet = Convert.FromBase64String("w7kxFgK8hYpGGLgdXe7ZpTZViB+r3sRI3YSqZs7/Mh5Vmh2mXqs+3dqkvURmXrL57ASs+FkJz/236Tl9ER67R+WZyMLRMkeLF6tEBiB/4X7SsXrKUznES8of73RxwMy76HZezJbvJ7m9IOGuxcjcNwe6q1+k8fOs1Hz3sULSGlbfiB6qIBXo4onADTNYFoYCQrdtthVsF/aDsvcZ93V36gaKzzyqMhby0sjV4+TAU7719W6LZWNAcnA="); await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption of a packet where the final block doesn't have maximum size. /// /// /// The test uses a real ping packet which was captured from a real game client. /// /// The async task. [Test] public async Task ClientToServerC3WithNonMaximalFinalBlockSizeAsync() { var packet = new byte[] { 195, 12, 14, 0, 1, 51, 254, 39, 0, 0, 0, 0 }; await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption of a C3 packet where the size is lower than the maximum block size. /// /// /// The test uses a real ping packet which was captured from a real game client. /// /// The async task. [Test] public async Task ClientToServerC3WithSmallPacketAsync() { var packet = new byte[] { 195, 5, 14, 0, 1 }; await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption and decryption cycle of C1-packets from client to server. /// These packets get encrypted first by , then just forwards then as-is. /// Then the forwards them as well and finally it gets decrypted by the . /// /// The task. [Test] public async Task ClientToServerC1Async() { var packet = new byte[] { 0xC1, 0x06, 0x11, 0x01, 0x02, 0x03 }; await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption and decryption cycle of C3-packets from server to client. /// These packets get encrypted first by the using server-side keys. /// On the client side it gets decrypted by the using client-side keys. /// /// The task. [Test] public async Task ServerToClientC3Async() { var packet = Convert.FromBase64String("w7kxFgK8hYpGGLgdXe7ZpTZViB+r3sRI3YSqZs7/Mh5Vmh2mXqs+3dqkvURmXrL57ASs+FkJz/236Tl9ER67R+WZyMLRMkeLF6tEBiB/4X7SsXrKUznES8of73RxwMy76HZezJbvJ7m9IOGuxcjcNwe6q1+k8fOs1Hz3sULSGlbfiB6qIBXo4onADTNYFoYCQrdtthVsF/aDsvcZ93V36gaKzzyqMhby0sjV4+TAU7719W6LZWNAcnA="); await this.EncryptDecryptFromServerToClientAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption and decryption cycle of C1-packets from server to client. /// These packets are not encrypted at all, so all involved simple modulus encryptor/decryptors just forward them. /// /// The task. [Test] public async Task ServerToClientC1Async() { var packet = new byte[] { 0xC1, 0x06, 0x11, 0x01, 0x02, 0x03 }; await this.EncryptDecryptFromServerToClientAsync(packet).ConfigureAwait(false); } /// /// Tests the encryption-decryption cycle for the packet from server to client. The specified packet must be the same after the packet has passed this cycle. /// Packets from server to client are never encrypted by Xor32, so these encryptor/decryptors are not involved here. /// /// The packet. /// The task. private async Task EncryptDecryptFromServerToClientAsync(byte[] packet) { // this pipe connects the encryptor with the decryptor. You can imagine this as the server-to-client pipe of a network socket, for example. var pipe = new Pipe(); var encryptor = new PipelinedSimpleModulusEncryptor(pipe.Writer); var decryptor = new PipelinedSimpleModulusDecryptor(pipe.Reader, PipelinedSimpleModulusDecryptor.DefaultClientKey); encryptor.Writer.Write(packet); await encryptor.Writer.FlushAsync().ConfigureAwait(false); var readResult = await decryptor.Reader.ReadAsync().ConfigureAwait(false); var result = readResult.Buffer.ToArray(); Assert.That(result, Is.EquivalentTo(packet)); } /// /// Tests the encryption-decryption cycle for the packet. The specified packet must be the same after the packet has passed this cycle. /// /// The packet. /// The async task. private async Task EncryptDecryptFromClientToServerAsync(byte[] packet) { // this pipe connects the encryptor with the decryptor. You can imagine this as the client-to-server pipe of a network socket, for example. var pipe = new Pipe(); var encryptor = new PipelinedXor32Encryptor(new PipelinedSimpleModulusEncryptor(pipe.Writer, PipelinedSimpleModulusEncryptor.DefaultClientKey).Writer); var decryptor = new PipelinedXor32Decryptor(new PipelinedSimpleModulusDecryptor(pipe.Reader).Reader); encryptor.Writer.Write(packet); await encryptor.Writer.FlushAsync().ConfigureAwait(false); var readResult = await decryptor.Reader.ReadAsync().ConfigureAwait(false); var result = readResult.Buffer.ToArray(); Assert.That(result, Is.EquivalentTo(packet)); } }