baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
33
src/Network/Xor/DefaultKeys.cs
Normal file
33
src/Network/Xor/DefaultKeys.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
// <copyright file="DefaultKeys.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Xor;
|
||||
|
||||
/// <summary>
|
||||
/// The default xor keys for encryption and decryption.
|
||||
/// </summary>
|
||||
public static class DefaultKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default 3 byte long XOR key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The default 3 byte long XOR key.
|
||||
/// </value>
|
||||
public static byte[] Xor3Keys { get; } = { 0xFC, 0xCF, 0xAB };
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default 32 byte long XOR key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The default 32 byte long XOR key.
|
||||
/// </value>
|
||||
public static byte[] Xor32Key { get; } =
|
||||
{
|
||||
0xAB, 0x11, 0xCD, 0xFE, 0x18, 0x23, 0xC5, 0xA3,
|
||||
0xCA, 0x33, 0xC1, 0xCC, 0x66, 0x67, 0x21, 0xF3,
|
||||
0x32, 0x12, 0x15, 0x35, 0x29, 0xFF, 0xFE, 0x1D,
|
||||
0x44, 0xEF, 0xCD, 0x41, 0x26, 0x3C, 0x4E, 0x4D,
|
||||
};
|
||||
}
|
||||
85
src/Network/Xor/PipelinedXor32Decryptor.cs
Normal file
85
src/Network/Xor/PipelinedXor32Decryptor.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
// <copyright file="PipelinedXor32Decryptor.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Xor;
|
||||
|
||||
using System.Buffers;
|
||||
using System.IO.Pipelines;
|
||||
|
||||
/// <summary>
|
||||
/// Pipelined decryptor which uses a 32 byte key for a xor encryption.
|
||||
/// It's typically used to decrypt packets sent by the client to the server.
|
||||
/// </summary>
|
||||
public class PipelinedXor32Decryptor : PacketPipeReaderBase, IPipelinedDecryptor
|
||||
{
|
||||
private readonly Pipe _pipe = new();
|
||||
private readonly byte[] _xor32Key;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PipelinedXor32Decryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
public PipelinedXor32Decryptor(PipeReader source)
|
||||
: this(source, DefaultKeys.Xor32Key)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PipelinedXor32Decryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
/// <param name="xor32Key">The xor32 key.</param>
|
||||
public PipelinedXor32Decryptor(PipeReader source, byte[] xor32Key)
|
||||
{
|
||||
if (xor32Key.Length != 32)
|
||||
{
|
||||
throw new ArgumentException($"Xor32key must have a size of 32 bytes, but is {xor32Key.Length} bytes long.");
|
||||
}
|
||||
|
||||
this.Source = source;
|
||||
this._xor32Key = xor32Key;
|
||||
_ = this.ReadSourceAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PipeReader Reader => this._pipe.Reader;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override ValueTask OnCompleteAsync(Exception? exception)
|
||||
{
|
||||
return this._pipe.Writer.CompleteAsync(exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the mu online packet.
|
||||
/// Decrypts the packet and writes it into our pipe.
|
||||
/// </summary>
|
||||
/// <param name="packet">The mu online packet.</param>
|
||||
/// <returns><see langword="true" />, if the flush was successful or not required.<see langword="false" />, if the pipe reader is completed and no longer reading data.</returns>
|
||||
protected override async ValueTask<bool> ReadPacketAsync(ReadOnlySequence<byte> packet)
|
||||
{
|
||||
this.DecryptAndWrite(packet);
|
||||
return await this.TryFlushWriterAsync(this._pipe.Writer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void DecryptAndWrite(ReadOnlySequence<byte> packet)
|
||||
{
|
||||
// The next line is getting a span from the writer which is at least as big as the packet.
|
||||
// As I found out, it's initially about 2 kb in size and gets smaller within further
|
||||
// usage. If the previous span was used up, a new piece of memory is getting provided for us.
|
||||
var span = this._pipe.Writer.GetSpan((int)packet.Length);
|
||||
|
||||
// we just want to work on a span with the exact size of the packet.
|
||||
var target = span.Slice(0, (int)packet.Length);
|
||||
packet.CopyTo(target);
|
||||
|
||||
var headerSize = target.GetPacketHeaderSize();
|
||||
for (var i = target.Length - 1; i > headerSize; i--)
|
||||
{
|
||||
target[i] = (byte)(target[i] ^ target[i - 1] ^ this._xor32Key[i % 32]);
|
||||
}
|
||||
|
||||
this._pipe.Writer.Advance(target.Length);
|
||||
}
|
||||
}
|
||||
82
src/Network/Xor/PipelinedXor32Encryptor.cs
Normal file
82
src/Network/Xor/PipelinedXor32Encryptor.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
// <copyright file="PipelinedXor32Encryptor.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Xor;
|
||||
|
||||
using System.Buffers;
|
||||
using System.IO.Pipelines;
|
||||
|
||||
/// <summary>
|
||||
/// Pipelined encryptor which uses a 32 byte key for a xor encryption.
|
||||
/// It's typically used to encrypt packet sent by the client to the server.
|
||||
/// </summary>
|
||||
public class PipelinedXor32Encryptor : PacketPipeReaderBase, IPipelinedEncryptor
|
||||
{
|
||||
private readonly PipeWriter _target;
|
||||
private readonly Pipe _pipe = new();
|
||||
private readonly byte[] _xor32Key;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PipelinedXor32Encryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="target">The target.</param>
|
||||
public PipelinedXor32Encryptor(PipeWriter target)
|
||||
: this(target, DefaultKeys.Xor32Key)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PipelinedXor32Encryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="target">The target.</param>
|
||||
/// /// <param name="xor32Key">The xor32 key.</param>
|
||||
public PipelinedXor32Encryptor(PipeWriter target, byte[] xor32Key)
|
||||
{
|
||||
if (xor32Key.Length != 32)
|
||||
{
|
||||
throw new ArgumentException($"Xor32key must have a size of 32 bytes, but is {xor32Key.Length} bytes long.");
|
||||
}
|
||||
|
||||
this.Source = this._pipe.Reader;
|
||||
this._target = target;
|
||||
this._xor32Key = xor32Key;
|
||||
_ = this.ReadSourceAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PipeWriter Writer => this._pipe.Writer;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override ValueTask OnCompleteAsync(Exception? exception)
|
||||
{
|
||||
return this._target.CompleteAsync(exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the mu online packet.
|
||||
/// Encrypts the packet and writes it into the target.
|
||||
/// </summary>
|
||||
/// <param name="packet">The mu online packet.</param>
|
||||
/// <returns><see langword="true" />, if the flush was successful or not required.<see langword="false" />, if the pipe reader is completed and no longer reading data.</returns>
|
||||
protected override async ValueTask<bool> ReadPacketAsync(ReadOnlySequence<byte> packet)
|
||||
{
|
||||
this.EncryptAndWrite(packet);
|
||||
return await this.TryFlushWriterAsync(this._target).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void EncryptAndWrite(ReadOnlySequence<byte> packet)
|
||||
{
|
||||
var span = this._target.GetSpan((int)packet.Length);
|
||||
var result = span.Slice(0, (int)packet.Length);
|
||||
packet.CopyTo(result);
|
||||
|
||||
var headerSize = result.GetPacketHeaderSize();
|
||||
for (int i = headerSize + 1; i < packet.Length; i++)
|
||||
{
|
||||
result[i] = (byte)(result[i] ^ result[i - 1] ^ this._xor32Key[i % 32]);
|
||||
}
|
||||
|
||||
this._target.Advance(result.Length);
|
||||
}
|
||||
}
|
||||
26
src/Network/Xor/Xor3Decryptor.cs
Normal file
26
src/Network/Xor/Xor3Decryptor.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// <copyright file="Xor3Decryptor.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Xor;
|
||||
|
||||
/// <summary>
|
||||
/// A decryptor which XOR-decrypts data using a 3-byte key.
|
||||
/// </summary>
|
||||
public class Xor3Decryptor : Xor3Encryptor, ISpanDecryptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Xor3Decryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="startOffset">The start offset.</param>
|
||||
public Xor3Decryptor(int startOffset)
|
||||
: base(startOffset)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Decrypt(Span<byte> packet)
|
||||
{
|
||||
this.Encrypt(packet);
|
||||
}
|
||||
}
|
||||
43
src/Network/Xor/Xor3Encryptor.cs
Normal file
43
src/Network/Xor/Xor3Encryptor.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
// <copyright file="Xor3Encryptor.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Xor;
|
||||
|
||||
/// <summary>
|
||||
/// An encryptor which XOR-encrypts data using a 3-byte key.
|
||||
/// </summary>
|
||||
public class Xor3Encryptor : ISpanEncryptor
|
||||
{
|
||||
private readonly byte[] _xor3Keys;
|
||||
|
||||
private readonly int _startOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Xor3Encryptor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="startOffset">The start offset.</param>
|
||||
public Xor3Encryptor(int startOffset)
|
||||
{
|
||||
this._startOffset = startOffset;
|
||||
this._xor3Keys = DefaultKeys.Xor3Keys;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Encrypt(Span<byte> data)
|
||||
{
|
||||
this.InternalEncrypt(data.Slice(this._startOffset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal encrypt function. XORs each byte with one byte of the 3-byte key.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
protected void InternalEncrypt(Span<byte> data)
|
||||
{
|
||||
for (var i = 0; i < data.Length; i++)
|
||||
{
|
||||
data[i] ^= this._xor3Keys[i % 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user