This commit is contained in:
Anon 2026-04-04 00:32:07 +02:00
parent 1ca023be36
commit 3a4d8951d5
20 changed files with 1511 additions and 389 deletions

View file

@ -2,6 +2,8 @@
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace MinecraftClient.Crypto
{
@ -59,6 +61,11 @@ namespace MinecraftClient.Crypto
BaseStream.Flush();
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
return BaseStream.FlushAsync(cancellationToken);
}
public override long Length
{
get { throw new NotSupportedException(); }
@ -101,6 +108,15 @@ namespace MinecraftClient.Crypto
return (byte)(blockOutput[0] ^ inputBuf);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EncryptBlock(ReadOnlySpan<byte> blockInput, Span<byte> blockOutput)
{
if (FastAes is not null)
FastAes.EncryptEcb(blockInput, blockOutput);
else
Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None);
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public override int Read(byte[] buffer, int outOffset, int required)
{
@ -122,23 +138,11 @@ namespace MinecraftClient.Crypto
}
int processEnd = readed + curRead;
if (FastAes is not null)
for (int idx = readed; idx < processEnd; idx++)
{
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]);
}
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
EncryptBlock(blockInput, blockOutput);
buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
}
}
@ -161,10 +165,7 @@ namespace MinecraftClient.Crypto
{
Span<byte> blockOutput = stackalloc byte[blockSize];
if (FastAes is not null)
FastAes.EncryptEcb(WriteStreamIV, blockOutput);
else
Aes!.EncryptEcb(WriteStreamIV, blockOutput, PaddingMode.None);
EncryptBlock(WriteStreamIV, blockOutput);
byte outputBuf = (byte)(blockOutput[0] ^ b);
@ -185,15 +186,88 @@ namespace MinecraftClient.Crypto
for (int wirtten = 0; wirtten < required; ++wirtten)
{
ReadOnlySpan<byte> blockInput = new(outputBuf, wirtten, blockSize);
if (FastAes is not null)
FastAes.EncryptEcb(blockInput, blockOutput);
else
Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None);
EncryptBlock(blockInput, blockOutput);
outputBuf[blockSize + wirtten] = (byte)(blockOutput[0] ^ input[offset + wirtten]);
}
BaseStream.WriteAsync(outputBuf, blockSize, required);
BaseStream.Write(outputBuf, blockSize, required);
Array.Copy(outputBuf, required, WriteStreamIV, 0, blockSize);
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
if (inStreamEnded || buffer.Length == 0)
return 0;
byte[] inputBuf = new byte[blockSize + buffer.Length];
Array.Copy(ReadStreamIV, inputBuf, blockSize);
for (int readed = 0; readed < buffer.Length;)
{
int curRead = await BaseStream.ReadAsync(inputBuf.AsMemory(blockSize + readed, buffer.Length - readed), cancellationToken);
if (curRead == 0)
{
inStreamEnded = true;
Array.Copy(inputBuf, readed, ReadStreamIV, 0, blockSize);
return readed;
}
int processEnd = readed + curRead;
DecryptToOutputBuffer(inputBuf, buffer, readed, processEnd);
readed = processEnd;
}
Array.Copy(inputBuf, buffer.Length, ReadStreamIV, 0, blockSize);
return buffer.Length;
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
if (buffer.Length == 0)
return;
byte[] outputBuf = new byte[blockSize + buffer.Length];
Array.Copy(WriteStreamIV, outputBuf, blockSize);
EncryptToOutputBuffer(buffer, outputBuf);
await BaseStream.WriteAsync(outputBuf.AsMemory(blockSize, buffer.Length), cancellationToken);
Array.Copy(outputBuf, buffer.Length, WriteStreamIV, 0, blockSize);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask();
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private void DecryptToOutputBuffer(byte[] inputBuf, Memory<byte> output, int start, int end)
{
Span<byte> blockOutput = stackalloc byte[blockSize];
for (int idx = start; idx < end; idx++)
{
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
EncryptBlock(blockInput, blockOutput);
output.Span[idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
}
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private void EncryptToOutputBuffer(ReadOnlyMemory<byte> input, byte[] outputBuf)
{
Span<byte> blockOutput = stackalloc byte[blockSize];
for (int written = 0; written < input.Length; ++written)
{
ReadOnlySpan<byte> blockInput = new(outputBuf, written, blockSize);
EncryptBlock(blockInput, blockOutput);
outputBuf[blockSize + written] = (byte)(blockOutput[0] ^ input.Span[written]);
}
}
}
}