diff --git a/Minecraft.World/UUID.cpp b/Minecraft.World/UUID.cpp new file mode 100644 index 00000000..45e1bf9b --- /dev/null +++ b/Minecraft.World/UUID.cpp @@ -0,0 +1,160 @@ +#include "stdafx.h" +#include "UUID.h" +#include "Random.h" +#include +static void sha1(const uint8_t* data, size_t len, uint8_t out[20]) +{ + uint32_t h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; + uint64_t bitLen = len * 8; + size_t fullBlocks = len / 64; + for (size_t blk = 0; blk < fullBlocks; blk++) { + const uint8_t* p = data + blk * 64; + uint32_t w[80]; + for (int i = 0; i < 16; i++) + w[i] = (p[i * 4] << 24) | (p[i * 4 + 1] << 16) | (p[i * 4 + 2] << 8) | p[i * 4 + 3]; + for (int i = 16; i < 80; i++) { + uint32_t x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; + w[i] = (x << 1) | (x >> 31); + } + uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4]; + for (int i = 0; i < 80; i++) { + uint32_t f, k; + if (i < 20) { f = (b & c) | (~b & d); k = 0x5A827999; } + else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } + else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } + else { f = b ^ c ^ d; k = 0xCA62C1D6; } + uint32_t tmp = ((a << 5) | (a >> 27)) + f + e + k + w[i]; + e = d; d = c; c = (b << 30) | (b >> 2); b = a; a = tmp; + } + h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; + } + uint8_t tail[128] = {}; + size_t rem = len - fullBlocks * 64; + if (rem) memcpy(tail, data + fullBlocks * 64, rem); + tail[rem] = 0x80; + size_t tailLen = (rem < 56) ? 64 : 128; + for (int i = 0; i < 8; i++) + tail[tailLen - 1 - i] = (uint8_t)(bitLen >> (i * 8)); + + for (size_t off = 0; off < tailLen; off += 64) { + uint32_t w[80]; + for (int i = 0; i < 16; i++) + w[i] = (tail[off + i * 4] << 24) | (tail[off + i * 4 + 1] << 16) | + (tail[off + i * 4 + 2] << 8) | tail[off + i * 4 + 3]; + for (int i = 16; i < 80; i++) { + uint32_t x = w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]; + w[i] = (x << 1) | (x >> 31); + } + uint32_t a = h[0], b = h[1], c = h[2], d = h[3], e = h[4]; + for (int i = 0; i < 80; i++) { + uint32_t f, k; + if (i < 20) { f = (b & c) | (~b & d); k = 0x5A827999; } + else if (i < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } + else if (i < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } + else { f = b ^ c ^ d; k = 0xCA62C1D6; } + uint32_t tmp = ((a << 5) | (a >> 27)) + f + e + k + w[i]; + e = d; d = c; c = (b << 30) | (b >> 2); b = a; a = tmp; + } + h[0] += a; h[1] += b; h[2] += c; h[3] += d; h[4] += e; + } + + for (int i = 0; i < 5; i++) { + out[i * 4] = (uint8_t)(h[i] >> 24); + out[i * 4 + 1] = (uint8_t)(h[i] >> 16); + out[i * 4 + 2] = (uint8_t)(h[i] >> 8); + out[i * 4 + 3] = (uint8_t)(h[i]); + } +} +static constexpr char HEX[] = "0123456789abcdef"; +static constexpr uint8_t hexVal(char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + return 0; +} + +void GameUUID::toBytes(uint8_t out[16]) const +{ + for (int i = 7; i >= 0; i--) out[7 - i] = (uint8_t)(msb >> (i * 8)); + for (int i = 7; i >= 0; i--) out[15 - i] = (uint8_t)(lsb >> (i * 8)); +} + +GameUUID GameUUID::fromBytes(const uint8_t b[16]) +{ + GameUUID u; + for (int i = 0; i < 8; i++) u.msb = (u.msb << 8) | b[i]; + for (int i = 0; i < 8; i++) u.lsb = (u.lsb << 8) | b[8 + i]; + return u; +} +std::string GameUUID::toString() const +{ + uint8_t b[16]; + toBytes(b); + char buf[37]; + int p = 0; + for (int i = 0; i < 16; i++) { + if (i == 4 || i == 6 || i == 8 || i == 10) buf[p++] = '-'; + buf[p++] = HEX[b[i] >> 4]; + buf[p++] = HEX[b[i] & 0xf]; + } + buf[p] = '\0'; + return buf; +} + +std::wstring GameUUID::toWString() const +{ + std::string s = toString(); + return { s.begin(), s.end() }; +} + +GameUUID GameUUID::fromString(const std::string& s) +{ + uint8_t b[16] = {}; + int bi = 0; + for (size_t i = 0; i < s.size() && bi < 16; i++) { + if (s[i] == '-') continue; + if (i + 1 >= s.size()) break; + b[bi++] = (hexVal(s[i]) << 4) | hexVal(s[i + 1]); + i++; + } + return fromBytes(b); +} + +GameUUID GameUUID::fromWString(const std::wstring& s) +{ + return fromString({ s.begin(), s.end() }); +} + +GameUUID GameUUID::v4(uint64_t high, uint64_t low) +{ + return { (high & ~0xF000ULL) | 0x4000ULL, (low & ~0xC000000000000000ULL) | 0x8000000000000000ULL }; +} + +GameUUID GameUUID::v5(const GameUUID& ns, const std::string& name) +{ + uint8_t input[256]; + ns.toBytes(input); + size_t total = 16 + name.size(); + // names over 240 chars would be insane but just in case + if (name.size() <= sizeof(input) - 16) + memcpy(input + 16, name.data(), name.size()); + + uint8_t hash[20]; + sha1(input, total, hash); + GameUUID u = fromBytes(hash); + u.msb = (u.msb & ~0xF000ULL) | 0x5000ULL; + u.lsb = (u.lsb & ~0xC000000000000000ULL) | 0x8000000000000000ULL; + return u; +} + +GameUUID GameUUID::fromXuid(uint64_t xuid) +{ + return v5(MCCONSOLES_NAMESPACE_UUID, std::to_string(xuid)); +} + +GameUUID GameUUID::random() +{ + Random r; + return v4(r.nextLong(), r.nextLong()); +} diff --git a/Minecraft.World/UUID.h b/Minecraft.World/UUID.h new file mode 100644 index 00000000..3bce7773 --- /dev/null +++ b/Minecraft.World/UUID.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +struct GameUUID { + uint64_t msb = 0; + uint64_t lsb = 0; + + constexpr bool isNil() const { return msb == 0 && lsb == 0; } + constexpr bool operator==(const GameUUID& o) const { return msb == o.msb && lsb == o.lsb; } + constexpr bool operator!=(const GameUUID& o) const { return !(*this == o); } + constexpr bool operator<(const GameUUID& o) const { return msb < o.msb || (msb == o.msb && lsb < o.lsb); } + + void toBytes(uint8_t out[16]) const; + std::string toString() const; + std::wstring toWString() const; + + static GameUUID fromBytes(const uint8_t b[16]); + static GameUUID fromString(const std::string& s); + static GameUUID fromWString(const std::wstring& s); + static GameUUID v4(uint64_t high, uint64_t low); + static GameUUID v5(const GameUUID& ns, const std::string& name); + static GameUUID fromXuid(uint64_t xuid); + static GameUUID random(); +}; + +inline constexpr GameUUID MCCONSOLES_NAMESPACE_UUID = { 0x4d696e6563726166ULL, 0x74436f6e736f6c65ULL }; diff --git a/Minecraft.World/cmake/sources/Common.cmake b/Minecraft.World/cmake/sources/Common.cmake index 07b322d9..ae1fad9d 100644 --- a/Minecraft.World/cmake/sources/Common.cmake +++ b/Minecraft.World/cmake/sources/Common.cmake @@ -263,6 +263,8 @@ set(_MINECRAFT_WORLD_COMMON_NET_MINECRAFT_NETWORK_PACKET "${CMAKE_CURRENT_SOURCE_DIR}/AuthModule.h" "${CMAKE_CURRENT_SOURCE_DIR}/AuthPackets.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AuthPackets.h" + "${CMAKE_CURRENT_SOURCE_DIR}/UUID.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/UUID.h" "${CMAKE_CURRENT_SOURCE_DIR}/AwardStatPacket.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/AwardStatPacket.h" "${CMAKE_CURRENT_SOURCE_DIR}/BlockRegionUpdatePacket.cpp"