Minecraft-Console-Client/MinecraftClient/Crypto/AesCfb8Stream.cs

200 lines
6.1 KiB
C#
Raw Normal View History

using System;
using System.IO;
2022-08-28 10:50:52 +08:00
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
2022-08-28 13:18:07 +08:00
namespace MinecraftClient.Crypto
{
2022-08-28 13:18:07 +08:00
public class AesCfb8Stream : Stream
{
2022-12-14 14:45:51 +08:00
public const int blockSize = 16;
2022-08-28 10:50:52 +08:00
private readonly Aes? Aes = null;
2022-08-28 13:18:07 +08:00
private readonly FastAes? FastAes = null;
private bool inStreamEnded = false;
private readonly byte[] ReadStreamIV = new byte[16];
private readonly byte[] WriteStreamIV = new byte[16];
2022-08-28 14:57:44 +08:00
public Stream BaseStream { get; set; }
2022-08-28 13:18:07 +08:00
public AesCfb8Stream(Stream stream, byte[] key)
{
BaseStream = stream;
if (FastAes.IsSupported())
2022-08-28 13:18:07 +08:00
FastAes = new FastAes(key);
2022-08-28 10:50:52 +08:00
else
2022-08-28 13:18:07 +08:00
{
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()
{
2022-08-28 13:18:07 +08:00
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);
}
2022-08-28 10:50:52 +08:00
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public override int Read(byte[] buffer, int outOffset, int required)
{
2022-08-28 13:18:07 +08:00
if (inStreamEnded)
return 0;
2022-12-14 14:45:51 +08:00
Span<byte> blockOutput = stackalloc byte[blockSize];
2022-08-28 13:18:07 +08:00
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)
{
2022-08-28 13:18:07 +08:00
inStreamEnded = true;
return readed;
}
2022-08-28 13:18:07 +08:00
int processEnd = readed + curRead;
if (FastAes != null)
{
2022-08-28 13:18:07 +08:00
for (int idx = readed; idx < processEnd; idx++)
{
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
2022-08-28 13:18:07 +08:00
FastAes.EncryptEcb(blockInput, blockOutput);
buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
}
2022-08-28 13:18:07 +08:00
}
else
{
2022-12-14 14:45:51 +08:00
for (int idx = readed; idx < processEnd; idx++)
2022-08-28 13:18:07 +08:00
{
2022-12-14 14:45:51 +08:00
ReadOnlySpan<byte> blockInput = new(inputBuf, idx, blockSize);
Aes!.EncryptEcb(blockInput, blockOutput, PaddingMode.None);
buffer[outOffset + idx] = (byte)(blockOutput[0] ^ inputBuf[idx + blockSize]);
}
2022-08-28 13:18:07 +08:00
}
}
Array.Copy(inputBuf, required, ReadStreamIV, 0, blockSize);
return required;
}
2022-08-28 13:18:07 +08:00
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)
{
2022-08-28 13:18:07 +08:00
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;
}
2022-08-28 13:18:07 +08:00
[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);
2022-08-28 10:50:52 +08:00
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);
}
}
}