-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add DotNetty network implementation with SpanNetty
- Loading branch information
Showing
29 changed files
with
1,936 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Security.Cryptography; | ||
|
||
namespace Edelstein.Common.Crypto; | ||
|
||
public class CipherAES | ||
{ | ||
private readonly ICryptoTransform _transformer; | ||
|
||
public CipherAES() : this(new byte[] { 0x13, 0x08, 0x06, 0xb4, 0x1b, 0x0f, 0x33, 0x52 }) | ||
{ | ||
} | ||
|
||
public CipherAES(ReadOnlySpan<byte> userKey) | ||
{ | ||
var expandedKey = new byte[userKey.Length * 4]; | ||
var cipher = Aes.Create(); | ||
|
||
for (var i = 0; i < userKey.Length; i++) | ||
expandedKey[i * 4] = userKey[i]; | ||
|
||
cipher.KeySize = 256; | ||
cipher.Key = expandedKey; | ||
cipher.Mode = CipherMode.ECB; | ||
_transformer = cipher.CreateEncryptor(); | ||
} | ||
|
||
public void Transform(Span<byte> input, int remaining, uint src) | ||
{ | ||
var length = 0x5B0; | ||
var start = 0; | ||
|
||
const int srcExpL = sizeof(int) * 4; | ||
var srcExp = ArrayPool<byte>.Shared.Rent(srcExpL); | ||
var srcBytes = BitConverter.GetBytes(src); | ||
|
||
while (remaining > 0) | ||
{ | ||
for (var i = 0; i < srcExpL; ++i) | ||
srcExp[i] = srcBytes[i % 4]; | ||
|
||
if (remaining < length) | ||
length = remaining; | ||
|
||
for (var i = start; i < start + length; ++i) | ||
{ | ||
var sub = i - start; | ||
|
||
if (sub % srcExpL == 0) | ||
_transformer.TransformBlock( | ||
srcExp, | ||
0, | ||
srcExpL, | ||
srcExp, | ||
0 | ||
); | ||
|
||
input[i] ^= srcExp[sub % srcExpL]; | ||
} | ||
|
||
start += length; | ||
remaining -= length; | ||
length = 0x5B4; | ||
} | ||
|
||
ArrayPool<byte>.Shared.Return(srcExp); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
namespace Edelstein.Common.Crypto; | ||
|
||
public class CipherIG | ||
{ | ||
private readonly byte[] _shuffle; | ||
private readonly uint _key; | ||
|
||
public CipherIG() : this(new byte[] | ||
{ | ||
0xEC, 0x3F, 0x77, 0xA4, 0x45, 0xD0, 0x71, 0xBF, 0xB7, 0x98, 0x20, 0xFC, 0x4B, 0xE9, 0xB3, 0xE1, | ||
0x5C, 0x22, 0xF7, 0x0C, 0x44, 0x1B, 0x81, 0xBD, 0x63, 0x8D, 0xD4, 0xC3, 0xF2, 0x10, 0x19, 0xE0, | ||
0xFB, 0xA1, 0x6E, 0x66, 0xEA, 0xAE, 0xD6, 0xCE, 0x06, 0x18, 0x4E, 0xEB, 0x78, 0x95, 0xDB, 0xBA, | ||
0xB6, 0x42, 0x7A, 0x2A, 0x83, 0x0B, 0x54, 0x67, 0x6D, 0xE8, 0x65, 0xE7, 0x2F, 0x07, 0xF3, 0xAA, | ||
0x27, 0x7B, 0x85, 0xB0, 0x26, 0xFD, 0x8B, 0xA9, 0xFA, 0xBE, 0xA8, 0xD7, 0xCB, 0xCC, 0x92, 0xDA, | ||
0xF9, 0x93, 0x60, 0x2D, 0xDD, 0xD2, 0xA2, 0x9B, 0x39, 0x5F, 0x82, 0x21, 0x4C, 0x69, 0xF8, 0x31, | ||
0x87, 0xEE, 0x8E, 0xAD, 0x8C, 0x6A, 0xBC, 0xB5, 0x6B, 0x59, 0x13, 0xF1, 0x04, 0x00, 0xF6, 0x5A, | ||
0x35, 0x79, 0x48, 0x8F, 0x15, 0xCD, 0x97, 0x57, 0x12, 0x3E, 0x37, 0xFF, 0x9D, 0x4F, 0x51, 0xF5, | ||
0xA3, 0x70, 0xBB, 0x14, 0x75, 0xC2, 0xB8, 0x72, 0xC0, 0xED, 0x7D, 0x68, 0xC9, 0x2E, 0x0D, 0x62, | ||
0x46, 0x17, 0x11, 0x4D, 0x6C, 0xC4, 0x7E, 0x53, 0xC1, 0x25, 0xC7, 0x9A, 0x1C, 0x88, 0x58, 0x2C, | ||
0x89, 0xDC, 0x02, 0x64, 0x40, 0x01, 0x5D, 0x38, 0xA5, 0xE2, 0xAF, 0x55, 0xD5, 0xEF, 0x1A, 0x7C, | ||
0xA7, 0x5B, 0xA6, 0x6F, 0x86, 0x9F, 0x73, 0xE6, 0x0A, 0xDE, 0x2B, 0x99, 0x4A, 0x47, 0x9C, 0xDF, | ||
0x09, 0x76, 0x9E, 0x30, 0x0E, 0xE4, 0xB2, 0x94, 0xA0, 0x3B, 0x34, 0x1D, 0x28, 0x0F, 0x36, 0xE3, | ||
0x23, 0xB4, 0x03, 0xD8, 0x90, 0xC8, 0x3C, 0xFE, 0x5E, 0x32, 0x24, 0x50, 0x1F, 0x3A, 0x43, 0x8A, | ||
0x96, 0x41, 0x74, 0xAC, 0x52, 0x33, 0xF0, 0xD9, 0x29, 0x80, 0xB1, 0x16, 0xD3, 0xAB, 0x91, 0xB9, | ||
0x84, 0x7F, 0x61, 0x1E, 0xCF, 0xC5, 0xD1, 0x56, 0x3D, 0xCA, 0xF4, 0x05, 0xC6, 0xE5, 0x08, 0x49 | ||
}) | ||
{ | ||
} | ||
|
||
public CipherIG(byte[] shuffle, uint key = 0xC65053F2) | ||
{ | ||
_shuffle = shuffle; | ||
_key = key; | ||
} | ||
|
||
public unsafe uint Hash(uint pSrc, int nLen, uint dwKey) | ||
{ | ||
if (dwKey == 0) dwKey = _key; | ||
if (nLen <= 0) return _key; | ||
|
||
var ptrDwKey = &dwKey; | ||
|
||
for (var i = 0; i < nLen; i++) | ||
{ | ||
var ptrPSrc = &pSrc; | ||
|
||
fixed (byte* pShuffle = _shuffle) | ||
{ | ||
*((byte*)ptrDwKey + 0) += | ||
(byte)(*(pShuffle + *((byte*)ptrDwKey + 1)) - *((byte*)ptrPSrc + i)); | ||
*((byte*)ptrDwKey + 1) -= | ||
(byte)(*((byte*)ptrDwKey + 2) ^ *(pShuffle + *((byte*)ptrPSrc + i))); | ||
*((byte*)ptrDwKey + 2) ^= | ||
(byte)(*((byte*)ptrPSrc + i) + *(pShuffle + *((byte*)ptrDwKey + 3))); | ||
*((byte*)ptrDwKey + 3) = | ||
(byte)(*((byte*)ptrDwKey + 3) - *(byte*)ptrDwKey + *(pShuffle + *((byte*)ptrPSrc + i))); | ||
*ptrDwKey = *ptrDwKey << 3 | *ptrDwKey >> 29; | ||
} | ||
} | ||
|
||
return dwKey; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using System; | ||
|
||
namespace Edelstein.Common.Crypto; | ||
|
||
public static class CipherShanda | ||
{ | ||
public static void EncryptTransform(Span<byte> input, int size) | ||
{ | ||
for (var i = 0; i < 3; i++) | ||
{ | ||
byte a = 0; | ||
byte c; | ||
for (var j = size; j > 0; j--) | ||
{ | ||
c = input[size - j]; | ||
c = RollLeft(c, 3); | ||
c = (byte)(c + j); | ||
c ^= a; | ||
a = c; | ||
c = RollRight(a, j); | ||
c ^= 0xFF; | ||
c += 0x48; | ||
input[size - j] = c; | ||
} | ||
|
||
a = 0; | ||
for (var j = size; j > 0; j--) | ||
{ | ||
c = input[j - 1]; | ||
c = RollLeft(c, 4); | ||
c = (byte)(c + j); | ||
c ^= a; | ||
a = c; | ||
c ^= 0x13; | ||
c = RollRight(c, 3); | ||
input[j - 1] = c; | ||
} | ||
} | ||
} | ||
|
||
public static void DecryptTransform(Span<byte> input, int size) | ||
{ | ||
for (var i = 0; i < 3; i++) | ||
{ | ||
byte a; | ||
byte b = 0; | ||
byte c; | ||
for (var j = size; j > 0; j--) | ||
{ | ||
c = input[j - 1]; | ||
c = RollLeft(c, 3); | ||
c ^= 0x13; | ||
a = c; | ||
c ^= b; | ||
c = (byte)(c - j); | ||
c = RollRight(c, 4); | ||
b = a; | ||
input[j - 1] = c; | ||
} | ||
|
||
b = 0; | ||
for (var j = size; j > 0; j--) | ||
{ | ||
c = input[size - j]; | ||
c -= 0x48; | ||
c ^= 0xFF; | ||
c = RollLeft(c, j); | ||
a = c; | ||
c ^= b; | ||
c = (byte)(c - j); | ||
c = RollRight(c, 3); | ||
b = a; | ||
input[size - j] = c; | ||
} | ||
} | ||
} | ||
|
||
private static byte RollLeft(byte value, int shift) | ||
{ | ||
var num = (uint)(value << shift % 8); | ||
return (byte)(num & 0xff | num >> 8); | ||
} | ||
|
||
private static byte RollRight(byte value, int shift) | ||
{ | ||
var num = (uint)(value << 8 >> shift % 8); | ||
return (byte)(num & 0xff | num >> 8); | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
src/common/Edelstein.Common.Crypto/Edelstein.Common.Crypto.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
<PropertyGroup> | ||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"version": 2, | ||
"dependencies": { | ||
"net9.0": { | ||
"MinVer": { | ||
"type": "Direct", | ||
"requested": "[5.0.0, )", | ||
"resolved": "5.0.0", | ||
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw==" | ||
} | ||
} | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
src/common/Edelstein.Common.Network.DotNetty/Codecs/NettyPacketDecoder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using CommunityToolkit.HighPerformance.Buffers; | ||
using DotNetty.Buffers; | ||
using DotNetty.Codecs; | ||
using DotNetty.Transport.Channels; | ||
using Edelstein.Common.Crypto; | ||
using Edelstein.Protocol.Network.Packets; | ||
using Edelstein.Protocol.Network.Transports; | ||
|
||
namespace Edelstein.Common.Network.DotNetty.Codecs; | ||
|
||
public class NettyPacketDecoder( | ||
TransportVersion transportVersion, | ||
CipherAES cipherAES, | ||
CipherIG cipherIG | ||
) : ReplayingDecoder<NettyPacketState>(NettyPacketState.DecodingHeader) | ||
{ | ||
private short _length; | ||
private short _sequence; | ||
|
||
protected override void Decode( | ||
IChannelHandlerContext context, | ||
IByteBuffer input, | ||
List<object> output | ||
) | ||
{ | ||
var socket = context.Channel.GetAttribute(NettyAttributes.SocketKey).Get(); | ||
|
||
switch (State) | ||
{ | ||
case NettyPacketState.DecodingHeader: | ||
if (socket != null) | ||
{ | ||
if (input.ReadableBytes < 4) | ||
{ | ||
RequestReplay(); | ||
return; | ||
} | ||
|
||
var sequence = input.ReadShortLE(); | ||
var length = input.ReadShortLE(); | ||
|
||
if (socket.IsDataEncrypted) length ^= sequence; | ||
|
||
_sequence = sequence; | ||
_length = length; | ||
} | ||
else | ||
{ | ||
if (input.ReadableBytes < 2) | ||
{ | ||
RequestReplay(); | ||
return; | ||
} | ||
|
||
_length = input.ReadShortLE(); | ||
} | ||
|
||
Checkpoint(NettyPacketState.DecodingPayload); | ||
return; | ||
case NettyPacketState.DecodingPayload: | ||
if (input.ReadableBytes < _length) | ||
{ | ||
RequestReplay(); | ||
return; | ||
} | ||
|
||
var owner = MemoryOwner<byte>.Allocate(_length); | ||
var buffer = owner.Span; | ||
|
||
input.ReadBytes(buffer); | ||
Checkpoint(NettyPacketState.DecodingHeader); | ||
|
||
if (_length < 0x2) return; | ||
|
||
if (socket != null) | ||
{ | ||
var seqRecv = socket.SeqRecv; | ||
var version = (short)(seqRecv >> 16) ^ _sequence; | ||
|
||
if (!(version == -(transportVersion.Major + 1) || | ||
version == transportVersion.Major)) return; | ||
|
||
if (socket.IsDataEncrypted) | ||
{ | ||
cipherAES.Transform(buffer, _length, seqRecv); | ||
CipherShanda.DecryptTransform(buffer, _length); | ||
} | ||
|
||
socket.SeqRecv = cipherIG.Hash(seqRecv, 4, 0); | ||
} | ||
|
||
output.Add(new RawPacket(owner)); | ||
return; | ||
default: | ||
throw new ArgumentOutOfRangeException(nameof(State)); | ||
} | ||
} | ||
} |
Oops, something went wrong.