Remove hash check, and document packet format inbound and out

This commit is contained in:
zontreck 2024-08-29 18:46:56 -07:00
parent d1ff953717
commit a126358c5f
4 changed files with 67 additions and 52 deletions

View file

@ -1,3 +1,3 @@
class Constants { class Constants {
static const VERSION = "1.2.082924+1625"; static const VERSION = "1.2.082924+1846";
} }

View file

@ -14,6 +14,21 @@ import '../nbt/impl/StringTag.dart';
class PacketServer { class PacketServer {
static ServerSocket? socket; static ServerSocket? socket;
static bool shouldRestart = true; static bool shouldRestart = true;
/// Packet Data Format:
///
/// 8 Bytes (Long) - Total expected bytes of packet minus the 8 bytes here.
/// 8 bytes (Long) - Sequence ID
/// 8 bytes (Long) - Number of bytes to read
/// <arbitrary> - NBT Data
///
/// Response Format:
///
/// 8 bytes (Long) - Total expected bytes in packet minus the 8 bytes here.
/// 1 byte - Success flag, Zero or 255 currently.
/// 8 byes (Long) - Packet Length
/// <arbitrary> - NBT Data
///
static Future<void> start(int port) async { static Future<void> start(int port) async {
socket = await ServerSocket.bind(InternetAddress.anyIPv4, port); socket = await ServerSocket.bind(InternetAddress.anyIPv4, port);
print("Server now listening on port ${port}"); print("Server now listening on port ${port}");
@ -41,7 +56,6 @@ class PacketServer {
layer.resetPosition(); layer.resetPosition();
layer.readLong(); // This is unused outside of the above sanity check. layer.readLong(); // This is unused outside of the above sanity check.
try { try {
List<int> dataHash = layer.readBytes(32); // Sha256
int sequenceID = layer.readLong(); int sequenceID = layer.readLong();
print("Sequence ID in request: $sequenceID"); print("Sequence ID in request: $sequenceID");
@ -49,53 +63,38 @@ class PacketServer {
List<int> remainingBytes = layer.readBytes(numBytes); List<int> remainingBytes = layer.readBytes(numBytes);
String sha256OriginalHash = Hashing.bytes2Hash(dataHash); CompoundTag tag =
String sha256Hash = await NbtIo.readFromStream(Uint8List.fromList(remainingBytes));
Hashing.bytes2Hash(Hashing.sha1Sum(remainingBytes)); StringBuilder builder = StringBuilder();
if (sha256OriginalHash == sha256Hash) { Tag.writeStringifiedNamedTag(tag, builder, 0);
CompoundTag tag = await NbtIo.readFromStream(
Uint8List.fromList(remainingBytes));
StringBuilder builder = StringBuilder();
Tag.writeStringifiedNamedTag(tag, builder, 0);
print("Request from client: \n${builder}"); print("Request from client: \n${builder}");
C2SRequestPacket request = C2SRequestPacket(); C2SRequestPacket request = C2SRequestPacket();
request.decodeTag(tag); request.decodeTag(tag);
PacketResponse reply = await request.handleServerPacket(); PacketResponse reply = await request.handleServerPacket();
// Server uses NBT to communicate // Server uses NBT to communicate
builder = StringBuilder(); builder = StringBuilder();
Tag.writeStringifiedNamedTag(reply.replyDataTag, builder, 0); Tag.writeStringifiedNamedTag(reply.replyDataTag, builder, 0);
print("Response to client: \n${builder}"); print("Response to client: \n${builder}");
Uint8List nbtData = await NbtIo.writeToStream(reply.replyDataTag); Uint8List nbtData = await NbtIo.writeToStream(reply.replyDataTag);
layer.clear(); layer.clear();
layer.writeLong(sequenceID); layer.writeLong(sequenceID);
layer.writeByte(0xFF); // Successful receipt layer.writeByte(0xFF); // Successful receipt
layer.writeBytes(Hashing.sha256Sum(nbtData)); layer.writeLong(nbtData.lengthInBytes);
layer.writeLong(nbtData.lengthInBytes); layer.writeBytes(nbtData);
layer.writeBytes(nbtData); nbtData = layer.bytes;
nbtData = layer.bytes;
// NOTE: Added a length indicator because SocketServer is apparently... really really dumb in its impl, and has no way to know when all data has been received, so no special event. We just have to check for it based on this initial value. // NOTE: Added a length indicator because SocketServer is apparently... really really dumb in its impl, and has no way to know when all data has been received, so no special event. We just have to check for it based on this initial value.
layer.clear(); layer.clear();
layer.writeLong(nbtData.lengthInBytes); layer.writeLong(nbtData.lengthInBytes);
layer.writeBytes(nbtData); layer.writeBytes(nbtData);
sock.add(layer.bytes); sock.add(layer.bytes);
} else {
// Return a failure packet
layer.clear();
layer.writeLong(sequenceID);
layer.writeByte(0x00);
sock.add(layer.bytes); // Failure code.
print(
"ERROR: The inbound hash did not match real hash: $sha256OriginalHash != $sha256Hash\n> REFUSING TO PROCESS PACKET. SENDING ERROR CODE TO CLIENT");
}
} catch (E, stack) { } catch (E, stack) {
response.contents response.contents
.put("error", StringTag.valueOf("Malformed request packet")); .put("error", StringTag.valueOf("Malformed request packet"));
@ -145,6 +144,21 @@ class PacketClient {
/// Tries to send a packet to the connected server /// Tries to send a packet to the connected server
/// ///
/// On success, returns either, the decoded [S2CResponse], or on error a S2CResponse containing an error and a stacktrace as [StringTag] /// On success, returns either, the decoded [S2CResponse], or on error a S2CResponse containing an error and a stacktrace as [StringTag]
///
/// Packet Data Format:
///
/// 8 Bytes (Long) - Total expected bytes of packet minus the 8 bytes here.
/// 8 bytes (Long) - Sequence ID
/// 8 bytes (Long) - Number of bytes to read
/// <arbitrary> - NBT Data
///
/// Response Format:
///
/// 8 bytes (Long) - Total expected bytes in packet minus the 8 bytes here.
/// 1 byte - Success flag, Zero or 255 currently.
/// 8 byes (Long) - Packet Length
/// <arbitrary> - NBT Data
///
Future<S2CResponse> send(IPacket packet, bool shouldReconnect) async { Future<S2CResponse> send(IPacket packet, bool shouldReconnect) async {
if (!connected) { if (!connected) {
return S2CResponse(); return S2CResponse();
@ -158,14 +172,12 @@ class PacketClient {
Uint8List nbtData = Uint8List nbtData =
await NbtIo.writeToStream(request.encodeTag().asCompoundTag()); await NbtIo.writeToStream(request.encodeTag().asCompoundTag());
List<int> nbtDataHash = Hashing.sha256Sum(nbtData);
ByteLayer reply = ByteLayer(); ByteLayer reply = ByteLayer();
CompoundTag NBTTag = CompoundTag(); CompoundTag NBTTag = CompoundTag();
while (!success) { while (!success) {
layer.clear(); layer.clear();
layer.writeBytes(nbtDataHash);
layer.writeLong(packetSequence); layer.writeLong(packetSequence);
layer.writeLong(nbtData.lengthInBytes); layer.writeLong(nbtData.lengthInBytes);
layer.writeBytes(nbtData); layer.writeBytes(nbtData);
@ -196,15 +208,11 @@ class PacketClient {
reply.readLong(); // This is unused outside of the sanity check above. reply.readLong(); // This is unused outside of the sanity check above.
int sequence = reply.readLong(); int sequence = reply.readLong();
int successReceipt = reply.readByte(); int successReceipt = reply.readByte();
List<int> serverHash = reply.readBytes(32);
String srvHashStr = Hashing.bytes2Hash(serverHash);
int numBytes = reply.readLong(); int numBytes = reply.readLong();
List<int> pktBytes = reply.readBytes(numBytes); List<int> pktBytes = reply.readBytes(numBytes);
String pktHash = Hashing.bytes2Hash(Hashing.sha256Sum(pktBytes));
if (successReceipt == 0xFF && if (successReceipt == 0xFF && packetSequence == sequence)
packetSequence == sequence && success = true;
srvHashStr == pktHash) success = true;
if (success) { if (success) {
NBTTag = await NbtIo.readFromStream(Uint8List.fromList(pktBytes)); NBTTag = await NbtIo.readFromStream(Uint8List.fromList(pktBytes));

View file

@ -1,6 +1,6 @@
name: libac_dart name: libac_dart
description: "Aria's Creations code library" description: "Aria's Creations code library"
version: 1.2.082924+1625 version: 1.2.082924+1846
homepage: "https://zontreck.com" homepage: "https://zontreck.com"

View file

@ -1,3 +1,6 @@
import 'dart:typed_data';
import 'package:libac_dart/nbt/Stream.dart';
import 'package:libac_dart/utils/Hashing.dart'; import 'package:libac_dart/utils/Hashing.dart';
import 'package:test/expect.dart'; import 'package:test/expect.dart';
import 'package:test/scaffolding.dart'; import 'package:test/scaffolding.dart';
@ -8,8 +11,12 @@ void main() {
}); });
test("Test sha256", () { test("Test sha256", () {
List<int> hsh = Hashing.sha256Sum([0x0A, 0x0B]); Uint8List hsh = Uint8List.fromList(Hashing.sha256Sum([0x0A, 0x0B]));
print("Sha256 Length: ${hsh.length}"); print("Sha256 Length: ${hsh.lengthInBytes}");
ByteLayer layer = ByteLayer();
layer.writeBytes(hsh);
print("Layer length: ${layer.bytes.lengthInBytes}");
print("Sha256 Hash: ${Hashing.bytes2Hash(hsh)}"); print("Sha256 Hash: ${Hashing.bytes2Hash(hsh)}");