mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-11-07 17:36:07 +00:00
Refactoring to asynchronous. (partially completed)
This commit is contained in:
parent
7ee08092d4
commit
096ea0c70c
72 changed files with 6033 additions and 5080 deletions
|
|
@ -1,201 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Crypto
|
||||
{
|
||||
public class AesCfb8Stream : Stream
|
||||
{
|
||||
public const int blockSize = 16;
|
||||
|
||||
private readonly Aes? Aes = null;
|
||||
private readonly FastAes? FastAes = null;
|
||||
|
||||
private bool inStreamEnded = false;
|
||||
|
||||
private readonly byte[] ReadStreamIV = new byte[16];
|
||||
private readonly byte[] WriteStreamIV = new byte[16];
|
||||
|
||||
public Stream BaseStream { get; set; }
|
||||
|
||||
public AesCfb8Stream(Stream stream, byte[] key)
|
||||
{
|
||||
BaseStream = stream;
|
||||
|
||||
if (FastAes.IsSupported())
|
||||
FastAes = new FastAes(key);
|
||||
else
|
||||
{
|
||||
Aes = Aes.Create();
|
||||
Aes.BlockSize = 128;
|
||||
Aes.KeySize = 128;
|
||||
Aes.Key = key;
|
||||
Aes.Mode = CipherMode.ECB;
|
||||
Aes.Padding = PaddingMode.None;
|
||||
}
|
||||
|
||||
Array.Copy(key, ReadStreamIV, 16);
|
||||
Array.Copy(key, WriteStreamIV, 16);
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
BaseStream.Flush();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
if (inStreamEnded)
|
||||
return -1;
|
||||
|
||||
int inputBuf = BaseStream.ReadByte();
|
||||
if (inputBuf == -1)
|
||||
{
|
||||
inStreamEnded = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Span<byte> blockOutput = stackalloc byte[blockSize];
|
||||
if (FastAes != null)
|
||||
FastAes.EncryptEcb(ReadStreamIV, blockOutput);
|
||||
else
|
||||
Aes!.EncryptEcb(ReadStreamIV, blockOutput, PaddingMode.None);
|
||||
|
||||
// Shift left
|
||||
Array.Copy(ReadStreamIV, 1, ReadStreamIV, 0, blockSize - 1);
|
||||
ReadStreamIV[blockSize - 1] = (byte)inputBuf;
|
||||
|
||||
return (byte)(blockOutput[0] ^ inputBuf);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
public override int Read(byte[] buffer, int outOffset, int required)
|
||||
{
|
||||
if (inStreamEnded)
|
||||
return 0;
|
||||
|
||||
Span<byte> blockOutput = stackalloc byte[blockSize];
|
||||
|
||||
byte[] inputBuf = new byte[blockSize + required];
|
||||
Array.Copy(ReadStreamIV, inputBuf, blockSize);
|
||||
|
||||
for (int readed = 0, curRead; readed < required; readed += curRead)
|
||||
{
|
||||
curRead = BaseStream.Read(inputBuf, blockSize + readed, required - readed);
|
||||
if (curRead == 0)
|
||||
{
|
||||
inStreamEnded = true;
|
||||
return readed;
|
||||
}
|
||||
|
||||
int processEnd = readed + curRead;
|
||||
if (FastAes != null)
|
||||
{
|
||||
for (int idx = readed; idx < processEnd; idx++)
|
||||
{
|
||||
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
|
||||
FastAes.EncryptEcb(blockInput, blockOutput);
|
||||
buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int idx = readed; idx < processEnd; idx++)
|
||||
{
|
||||
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
|
||||
Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None);
|
||||
buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array.Copy(inputBuf, required, ReadStreamIV, 0, blockSize);
|
||||
|
||||
return required;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void WriteByte(byte b)
|
||||
{
|
||||
Span<byte> blockOutput = stackalloc byte[blockSize];
|
||||
|
||||
if (FastAes != null)
|
||||
FastAes.EncryptEcb(WriteStreamIV, blockOutput);
|
||||
else
|
||||
Aes!.EncryptEcb(WriteStreamIV, blockOutput, PaddingMode.None);
|
||||
|
||||
byte outputBuf = (byte)(blockOutput[0] ^ b);
|
||||
|
||||
BaseStream.WriteByte(outputBuf);
|
||||
|
||||
// Shift left
|
||||
Array.Copy(WriteStreamIV, 1, WriteStreamIV, 0, blockSize - 1);
|
||||
WriteStreamIV[blockSize - 1] = outputBuf;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
public override void Write(byte[] input, int offset, int required)
|
||||
{
|
||||
byte[] outputBuf = new byte[blockSize + required];
|
||||
Array.Copy(WriteStreamIV, outputBuf, blockSize);
|
||||
|
||||
Span<byte> blockOutput = stackalloc byte[blockSize];
|
||||
for (int wirtten = 0; wirtten < required; ++wirtten)
|
||||
{
|
||||
ReadOnlySpan<byte> blockInput = new(outputBuf, wirtten, blockSize);
|
||||
if (FastAes != null)
|
||||
FastAes.EncryptEcb(blockInput, blockOutput);
|
||||
else
|
||||
Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None);
|
||||
outputBuf[blockSize + wirtten] = (byte)(blockOutput[0] ^ input[offset + wirtten]);
|
||||
}
|
||||
BaseStream.WriteAsync(outputBuf, blockSize, required);
|
||||
|
||||
Array.Copy(outputBuf, required, WriteStreamIV, 0, blockSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
MinecraftClient/Crypto/AesHandler/BasicAes.cs
Normal file
29
MinecraftClient/Crypto/AesHandler/BasicAes.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Crypto.AesHandler
|
||||
{
|
||||
public class BasicAes : IAesHandler
|
||||
{
|
||||
private readonly Aes Aes;
|
||||
|
||||
public BasicAes(byte[] key)
|
||||
{
|
||||
Aes = Aes.Create();
|
||||
Aes.BlockSize = 128;
|
||||
Aes.KeySize = 128;
|
||||
Aes.Key = key;
|
||||
Aes.Mode = CipherMode.ECB;
|
||||
Aes.Padding = PaddingMode.None;
|
||||
}
|
||||
|
||||
public override void EncryptEcb(Span<byte> plaintext, Span<byte> destination)
|
||||
{
|
||||
Aes.EncryptEcb(plaintext, destination, PaddingMode.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
167
MinecraftClient/Crypto/AesHandler/FasterAesArm.cs
Normal file
167
MinecraftClient/Crypto/AesHandler/FasterAesArm.cs
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Crypto.AesHandler
|
||||
{
|
||||
// https://github.com/Metalnem/aes-armv8
|
||||
public class FasterAesArm : IAesHandler
|
||||
{
|
||||
private const int BlockSize = 16;
|
||||
private const int Rounds = 10;
|
||||
|
||||
private readonly byte[] enc;
|
||||
|
||||
public FasterAesArm(Span<byte> key)
|
||||
{
|
||||
enc = new byte[(Rounds + 1) * BlockSize];
|
||||
|
||||
int[] intKey = GenerateKeyExpansion(key);
|
||||
for (int i = 0; i < intKey.Length; ++i)
|
||||
{
|
||||
enc[i * 4 + 0] = (byte)((intKey[i] >> 0) & 0xff);
|
||||
enc[i * 4 + 1] = (byte)((intKey[i] >> 8) & 0xff);
|
||||
enc[i * 4 + 2] = (byte)((intKey[i] >> 16) & 0xff);
|
||||
enc[i * 4 + 3] = (byte)((intKey[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detects if the required instruction set is supported
|
||||
/// </summary>
|
||||
/// <returns>Is it supported</returns>
|
||||
public static bool IsSupported()
|
||||
{
|
||||
return Aes.IsSupported && AdvSimd.IsSupported;
|
||||
}
|
||||
|
||||
public override void EncryptEcb(Span<byte> plaintext, Span<byte> destination)
|
||||
{
|
||||
int position = 0;
|
||||
int left = plaintext.Length;
|
||||
|
||||
var key0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[0 * BlockSize]);
|
||||
var key1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[1 * BlockSize]);
|
||||
var key2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[2 * BlockSize]);
|
||||
var key3 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[3 * BlockSize]);
|
||||
var key4 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[4 * BlockSize]);
|
||||
var key5 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[5 * BlockSize]);
|
||||
var key6 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[6 * BlockSize]);
|
||||
var key7 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[7 * BlockSize]);
|
||||
var key8 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[8 * BlockSize]);
|
||||
var key9 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[9 * BlockSize]);
|
||||
var key10 = Unsafe.ReadUnaligned<Vector128<byte>>(ref enc[10 * BlockSize]);
|
||||
|
||||
while (left >= BlockSize)
|
||||
{
|
||||
var block = Unsafe.ReadUnaligned<Vector128<byte>>(ref plaintext[position]);
|
||||
|
||||
block = Aes.Encrypt(block, key0);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key1);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key2);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key3);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key4);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key5);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key6);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key7);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key8);
|
||||
block = Aes.MixColumns(block);
|
||||
|
||||
block = Aes.Encrypt(block, key9);
|
||||
block = AdvSimd.Xor(block, key10);
|
||||
|
||||
Unsafe.WriteUnaligned(ref destination[position], block);
|
||||
|
||||
position += BlockSize;
|
||||
left -= BlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
private int[] GenerateKeyExpansion(Span<byte> rgbKey)
|
||||
{
|
||||
var m_encryptKeyExpansion = new int[4 * (Rounds + 1)];
|
||||
|
||||
int index = 0;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int i0 = rgbKey[index++];
|
||||
int i1 = rgbKey[index++];
|
||||
int i2 = rgbKey[index++];
|
||||
int i3 = rgbKey[index++];
|
||||
m_encryptKeyExpansion[i] = i3 << 24 | i2 << 16 | i1 << 8 | i0;
|
||||
}
|
||||
|
||||
for (int i = 4; i < 4 * (Rounds + 1); ++i)
|
||||
{
|
||||
int iTemp = m_encryptKeyExpansion[i - 1];
|
||||
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
iTemp = SubWord(Rot3(iTemp));
|
||||
iTemp ^= s_Rcon[(i / 4) - 1];
|
||||
}
|
||||
|
||||
m_encryptKeyExpansion[i] = m_encryptKeyExpansion[i - 4] ^ iTemp;
|
||||
}
|
||||
|
||||
return m_encryptKeyExpansion;
|
||||
}
|
||||
|
||||
private static int SubWord(int a)
|
||||
{
|
||||
return s_Sbox[a & 0xFF] |
|
||||
s_Sbox[a >> 8 & 0xFF] << 8 |
|
||||
s_Sbox[a >> 16 & 0xFF] << 16 |
|
||||
s_Sbox[a >> 24 & 0xFF] << 24;
|
||||
}
|
||||
|
||||
private static int Rot3(int val)
|
||||
{
|
||||
return (val << 24 & unchecked((int)0xFF000000)) | (val >> 8 & unchecked((int)0x00FFFFFF));
|
||||
}
|
||||
|
||||
private static readonly byte[] s_Sbox = new byte[] {
|
||||
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
|
||||
202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
|
||||
183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
|
||||
4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
|
||||
9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
|
||||
83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
|
||||
208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
|
||||
81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
|
||||
205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
|
||||
96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
|
||||
224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
|
||||
231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
|
||||
186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
|
||||
112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
|
||||
225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
|
||||
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 };
|
||||
|
||||
private static readonly int[] s_Rcon = new int[] {
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
|
||||
0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
|
||||
0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
|
||||
}
|
||||
}
|
||||
|
|
@ -4,15 +4,15 @@ using System.Runtime.InteropServices;
|
|||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace MinecraftClient.Crypto
|
||||
namespace MinecraftClient.Crypto.AesHandler
|
||||
{
|
||||
// Using the AES-NI instruction set
|
||||
// https://gist.github.com/Thealexbarney/9f75883786a9f3100408ff795fb95d85
|
||||
public class FastAes
|
||||
public class FasterAesX86 : IAesHandler
|
||||
{
|
||||
private Vector128<byte>[] RoundKeys { get; }
|
||||
|
||||
public FastAes(Span<byte> key)
|
||||
public FasterAesX86(Span<byte> key)
|
||||
{
|
||||
RoundKeys = KeyExpansion(key);
|
||||
}
|
||||
|
|
@ -23,11 +23,10 @@ namespace MinecraftClient.Crypto
|
|||
/// <returns>Is it supported</returns>
|
||||
public static bool IsSupported()
|
||||
{
|
||||
return Sse2.IsSupported && Aes.IsSupported;
|
||||
return Aes.IsSupported && Sse2.IsSupported;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void EncryptEcb(ReadOnlySpan<byte> plaintext, Span<byte> destination)
|
||||
public override void EncryptEcb(Span<byte> plaintext, Span<byte> destination)
|
||||
{
|
||||
Vector128<byte>[] keys = RoundKeys;
|
||||
|
||||
13
MinecraftClient/Crypto/IAesHandler.cs
Normal file
13
MinecraftClient/Crypto/IAesHandler.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Crypto
|
||||
{
|
||||
public abstract class IAesHandler
|
||||
{
|
||||
public abstract void EncryptEcb(Span<byte> plaintext, Span<byte> destination);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue