diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index 178e7237..fb00bb7d 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -50,7 +50,8 @@ public: const std::string& accountName, uint32_t clientSeed, const std::vector& sessionKey, - uint32_t serverSeed); + uint32_t serverSeed, + uint32_t realmId = 1); private: /** @@ -83,29 +84,30 @@ public: * SMSG_AUTH_RESPONSE result codes */ enum class AuthResult : uint8_t { - OK = 0x00, // Success, proceed to character screen - FAILED = 0x01, // Generic failure - REJECT = 0x02, // Reject - BAD_SERVER_PROOF = 0x03, // Bad server proof - UNAVAILABLE = 0x04, // Unavailable - SYSTEM_ERROR = 0x05, // System error - BILLING_ERROR = 0x06, // Billing error - BILLING_EXPIRED = 0x07, // Billing expired - VERSION_MISMATCH = 0x08, // Version mismatch - UNKNOWN_ACCOUNT = 0x09, // Unknown account - INCORRECT_PASSWORD = 0x0A, // Incorrect password - SESSION_EXPIRED = 0x0B, // Session expired - SERVER_SHUTTING_DOWN = 0x0C, // Server shutting down - ALREADY_LOGGING_IN = 0x0D, // Already logging in - LOGIN_SERVER_NOT_FOUND = 0x0E, // Login server not found - WAIT_QUEUE = 0x0F, // Wait queue - BANNED = 0x10, // Banned - ALREADY_ONLINE = 0x11, // Already online - NO_TIME = 0x12, // No game time - DB_BUSY = 0x13, // DB busy - SUSPENDED = 0x14, // Suspended - PARENTAL_CONTROL = 0x15, // Parental control - LOCKED_ENFORCED = 0x16 // Account locked + // TrinityCore/AzerothCore auth response codes (3.3.5a) + OK = 0x0C, // Success, proceed to character screen + FAILED = 0x0D, // Generic failure + REJECT = 0x0E, // Reject + BAD_SERVER_PROOF = 0x0F, // Bad server proof + UNAVAILABLE = 0x10, // Unavailable + SYSTEM_ERROR = 0x11, // System error + BILLING_ERROR = 0x12, // Billing error + BILLING_EXPIRED = 0x13, // Billing expired + VERSION_MISMATCH = 0x14, // Version mismatch + UNKNOWN_ACCOUNT = 0x15, // Unknown account + INCORRECT_PASSWORD = 0x16, // Incorrect password + SESSION_EXPIRED = 0x17, // Session expired + SERVER_SHUTTING_DOWN = 0x18, // Server shutting down + ALREADY_LOGGING_IN = 0x19, // Already logging in + LOGIN_SERVER_NOT_FOUND = 0x1A, // Login server not found + WAIT_QUEUE = 0x1B, // Wait queue + BANNED = 0x1C, // Banned + ALREADY_ONLINE = 0x1D, // Already online + NO_TIME = 0x1E, // No game time + DB_BUSY = 0x1F, // DB busy + SUSPENDED = 0x20, // Suspended + PARENTAL_CONTROL = 0x21, // Parental control + LOCKED_ENFORCED = 0x22 // Account locked }; /** @@ -172,15 +174,54 @@ public: // Character Creation // ============================================================ +// WoW 3.3.5a ResponseCodes for character creation (from ResponseCodes enum) enum class CharCreateResult : uint8_t { - SUCCESS = 0x00, - ERROR = 0x01, - FAILED = 0x02, - NAME_IN_USE = 0x03, - DISABLED = 0x04, - PVP_TEAMS_VIOLATION = 0x05, - SERVER_LIMIT = 0x06, - ACCOUNT_LIMIT = 0x07, + // Success codes + SUCCESS = 0x2F, // CHAR_CREATE_SUCCESS + + // CHAR_CREATE error codes + IN_PROGRESS = 0x2E, // CHAR_CREATE_IN_PROGRESS + ERROR = 0x30, // CHAR_CREATE_ERROR + FAILED = 0x31, // CHAR_CREATE_FAILED + NAME_IN_USE = 0x32, // CHAR_CREATE_NAME_IN_USE + DISABLED = 0x33, // CHAR_CREATE_DISABLED + PVP_TEAMS_VIOLATION = 0x34, // CHAR_CREATE_PVP_TEAMS_VIOLATION + SERVER_LIMIT = 0x35, // CHAR_CREATE_SERVER_LIMIT + ACCOUNT_LIMIT = 0x36, // CHAR_CREATE_ACCOUNT_LIMIT + SERVER_QUEUE = 0x37, // CHAR_CREATE_SERVER_QUEUE + ONLY_EXISTING = 0x38, // CHAR_CREATE_ONLY_EXISTING + EXPANSION = 0x39, // CHAR_CREATE_EXPANSION + EXPANSION_CLASS = 0x3A, // CHAR_CREATE_EXPANSION_CLASS + LEVEL_REQUIREMENT = 0x3B, // CHAR_CREATE_LEVEL_REQUIREMENT + UNIQUE_CLASS_LIMIT = 0x3C, // CHAR_CREATE_UNIQUE_CLASS_LIMIT + CHARACTER_IN_GUILD = 0x3D, // CHAR_CREATE_CHARACTER_IN_GUILD + RESTRICTED_RACECLASS = 0x3E, // CHAR_CREATE_RESTRICTED_RACECLASS + CHARACTER_CHOOSE_RACE= 0x3F, // CHAR_CREATE_CHARACTER_CHOOSE_RACE + CHARACTER_ARENA_LEADER=0x40, // CHAR_CREATE_CHARACTER_ARENA_LEADER + CHARACTER_DELETE_MAIL= 0x41, // CHAR_CREATE_CHARACTER_DELETE_MAIL + CHARACTER_SWAP_FACTION=0x42, // CHAR_CREATE_CHARACTER_SWAP_FACTION + CHARACTER_RACE_ONLY = 0x43, // CHAR_CREATE_CHARACTER_RACE_ONLY + CHARACTER_GOLD_LIMIT = 0x44, // CHAR_CREATE_CHARACTER_GOLD_LIMIT + FORCE_LOGIN = 0x45, // CHAR_CREATE_FORCE_LOGIN + + // CHAR_NAME error codes (name validation failures) + NAME_SUCCESS = 0x57, // CHAR_NAME_SUCCESS + NAME_FAILURE = 0x58, // CHAR_NAME_FAILURE + NAME_NO_NAME = 0x59, // CHAR_NAME_NO_NAME + NAME_TOO_SHORT = 0x5A, // CHAR_NAME_TOO_SHORT + NAME_TOO_LONG = 0x5B, // CHAR_NAME_TOO_LONG + NAME_INVALID_CHARACTER = 0x5C, // CHAR_NAME_INVALID_CHARACTER + NAME_MIXED_LANGUAGES = 0x5D, // CHAR_NAME_MIXED_LANGUAGES + NAME_PROFANE = 0x5E, // CHAR_NAME_PROFANE + NAME_RESERVED = 0x5F, // CHAR_NAME_RESERVED + NAME_INVALID_APOSTROPHE = 0x60, // CHAR_NAME_INVALID_APOSTROPHE + NAME_MULTIPLE_APOSTROPHES = 0x61, // CHAR_NAME_MULTIPLE_APOSTROPHES + NAME_THREE_CONSECUTIVE = 0x62, // CHAR_NAME_THREE_CONSECUTIVE (98 decimal) + NAME_INVALID_SPACE = 0x63, // CHAR_NAME_INVALID_SPACE + NAME_CONSECUTIVE_SPACES = 0x64, // CHAR_NAME_CONSECUTIVE_SPACES + NAME_RUSSIAN_CONSECUTIVE_SILENT = 0x65, // CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS + NAME_RUSSIAN_SILENT_AT_BEGIN_OR_END = 0x66, // CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END + NAME_DECLENSION_DOESNT_MATCH = 0x67, // CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME }; struct CharCreateData { diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index b70bf0db..e645e47c 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1115,16 +1115,17 @@ void GameHandler::sendAuthSession() { LOG_DEBUG("CMSG_AUTH_SESSION packet size: ", packet.getSize(), " bytes"); - // Send packet (NOT encrypted yet) + // Send packet (unencrypted - this is the last unencrypted packet) socket->send(packet); - // CRITICAL: Initialize encryption AFTER sending AUTH_SESSION - // but BEFORE receiving AUTH_RESPONSE - LOG_INFO("Initializing RC4 header encryption..."); + // Enable encryption IMMEDIATELY after sending AUTH_SESSION + // AzerothCore enables encryption before sending AUTH_RESPONSE, + // so we need to be ready to decrypt the response + LOG_INFO("Enabling encryption immediately after AUTH_SESSION"); socket->initEncryption(sessionKey); setState(WorldState::AUTH_SENT); - LOG_INFO("CMSG_AUTH_SESSION sent, encryption initialized, waiting for response..."); + LOG_INFO("CMSG_AUTH_SESSION sent, encryption enabled, waiting for AUTH_RESPONSE..."); } void GameHandler::handleAuthResponse(network::Packet& packet) { @@ -1143,7 +1144,9 @@ void GameHandler::handleAuthResponse(network::Packet& packet) { return; } - // Authentication successful! + // Encryption was already enabled after sending AUTH_SESSION + LOG_INFO("AUTH_RESPONSE OK - world authentication successful"); + setState(WorldState::AUTHENTICATED); LOG_INFO("========================================"); @@ -1154,6 +1157,9 @@ void GameHandler::handleAuthResponse(network::Packet& packet) { setState(WorldState::READY); + // Request character list automatically + requestCharacterList(); + // Call success callback if (onSuccess) { onSuccess(); @@ -1166,7 +1172,8 @@ void GameHandler::requestCharacterList() { setState(WorldState::CHAR_LIST_RECEIVED); return; } - if (state != WorldState::READY && state != WorldState::AUTHENTICATED) { + if (state != WorldState::READY && state != WorldState::AUTHENTICATED && + state != WorldState::CHAR_LIST_RECEIVED) { LOG_WARNING("Cannot request character list in state: ", (int)state); return; } @@ -1335,13 +1342,37 @@ void GameHandler::handleCharCreateResponse(network::Packet& packet) { } else { std::string msg; switch (data.result) { + case CharCreateResult::ERROR: msg = "Server error"; break; + case CharCreateResult::FAILED: msg = "Creation failed"; break; case CharCreateResult::NAME_IN_USE: msg = "Name already in use"; break; case CharCreateResult::DISABLED: msg = "Character creation disabled"; break; + case CharCreateResult::PVP_TEAMS_VIOLATION: msg = "PvP faction violation"; break; case CharCreateResult::SERVER_LIMIT: msg = "Server character limit reached"; break; case CharCreateResult::ACCOUNT_LIMIT: msg = "Account character limit reached"; break; - default: msg = "Character creation failed"; break; + case CharCreateResult::SERVER_QUEUE: msg = "Server is queued"; break; + case CharCreateResult::ONLY_EXISTING: msg = "Only existing characters allowed"; break; + case CharCreateResult::EXPANSION: msg = "Expansion required"; break; + case CharCreateResult::EXPANSION_CLASS: msg = "Expansion required for this class"; break; + case CharCreateResult::LEVEL_REQUIREMENT: msg = "Level requirement not met"; break; + case CharCreateResult::UNIQUE_CLASS_LIMIT: msg = "Unique class limit reached"; break; + case CharCreateResult::RESTRICTED_RACECLASS: msg = "Race/class combination not allowed"; break; + // Name validation errors + case CharCreateResult::NAME_FAILURE: msg = "Invalid name"; break; + case CharCreateResult::NAME_NO_NAME: msg = "Please enter a name"; break; + case CharCreateResult::NAME_TOO_SHORT: msg = "Name is too short"; break; + case CharCreateResult::NAME_TOO_LONG: msg = "Name is too long"; break; + case CharCreateResult::NAME_INVALID_CHARACTER: msg = "Name contains invalid characters"; break; + case CharCreateResult::NAME_MIXED_LANGUAGES: msg = "Name mixes languages"; break; + case CharCreateResult::NAME_PROFANE: msg = "Name contains profanity"; break; + case CharCreateResult::NAME_RESERVED: msg = "Name is reserved"; break; + case CharCreateResult::NAME_INVALID_APOSTROPHE: msg = "Invalid apostrophe in name"; break; + case CharCreateResult::NAME_MULTIPLE_APOSTROPHES: msg = "Name has multiple apostrophes"; break; + case CharCreateResult::NAME_THREE_CONSECUTIVE: msg = "Name has 3+ consecutive same letters"; break; + case CharCreateResult::NAME_INVALID_SPACE: msg = "Invalid space in name"; break; + case CharCreateResult::NAME_CONSECUTIVE_SPACES: msg = "Name has consecutive spaces"; break; + default: msg = "Unknown error (code " + std::to_string(static_cast(data.result)) + ")"; break; } - LOG_WARNING("Character creation failed: ", msg); + LOG_WARNING("Character creation failed: ", msg, " (code=", static_cast(data.result), ")"); if (charCreateCallback_) { charCreateCallback_(false, msg); } diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index c7229515..aaf6061f 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace wowee { namespace game { @@ -14,7 +15,8 @@ network::Packet AuthSessionPacket::build(uint32_t build, const std::string& accountName, uint32_t clientSeed, const std::vector& sessionKey, - uint32_t serverSeed) { + uint32_t serverSeed, + uint32_t realmId) { if (sessionKey.size() != 40) { LOG_ERROR("Invalid session key size: ", sessionKey.size(), " (expected 40)"); } @@ -37,34 +39,80 @@ network::Packet AuthSessionPacket::build(uint32_t build, // Create packet (opcode will be added by WorldSocket) network::Packet packet(static_cast(Opcode::CMSG_AUTH_SESSION)); + // AzerothCore 3.3.5a expects this exact field order: + // Build, LoginServerID, Account, LoginServerType, LocalChallenge, + // RegionID, BattlegroupID, RealmID, DosResponse, Digest, AddonInfo + // Build number (uint32, little-endian) packet.writeUInt32(build); - // Unknown uint32 (always 0) + // Login server ID (uint32, always 0) packet.writeUInt32(0); // Account name (null-terminated string) packet.writeString(upperAccount); - // Unknown uint32 (always 0) + // Login server type (uint32, always 0) packet.writeUInt32(0); - // Client seed (uint32, little-endian) + // LocalChallenge / Client seed (uint32, little-endian) packet.writeUInt32(clientSeed); - // Unknown fields (5x uint32, all zeros) - for (int i = 0; i < 5; ++i) { + // Region ID (uint32) + packet.writeUInt32(0); + + // Battlegroup ID (uint32) + packet.writeUInt32(0); + + // Realm ID (uint32) + packet.writeUInt32(realmId); + LOG_DEBUG(" Realm ID: ", realmId); + + // DOS response (uint64) - required for 3.x + packet.writeUInt32(0); + packet.writeUInt32(0); + + // Authentication hash/digest (20 bytes) + packet.writeBytes(authHash.data(), authHash.size()); + + // Addon info - compressed block with 0 addons + // AzerothCore format: uint32 decompressedSize + zlib compressed data + // Decompressed format: uint32 addonCount + [addons...] + uint32 clientTime + uint8_t addonData[8] = { + 0, 0, 0, 0, // addon count = 0 + 0, 0, 0, 0 // client time = 0 + }; + uint32_t decompressedSize = 8; + + // Compress with zlib + uLongf compressedSize = compressBound(decompressedSize); + std::vector compressed(compressedSize); + int ret = compress(compressed.data(), &compressedSize, addonData, decompressedSize); + if (ret == Z_OK) { + compressed.resize(compressedSize); + // Write decompressedSize, then compressed bytes + packet.writeUInt32(decompressedSize); + packet.writeBytes(compressed.data(), compressed.size()); + LOG_DEBUG("Addon info: decompressedSize=", decompressedSize, + " compressedSize=", compressedSize); + } else { + LOG_ERROR("zlib compress failed with code: ", ret); packet.writeUInt32(0); } - // Authentication hash (20 bytes) - packet.writeBytes(authHash.data(), authHash.size()); - - // Addon CRC (uint32, can be 0) - packet.writeUInt32(0); - LOG_INFO("CMSG_AUTH_SESSION packet built: ", packet.getSize(), " bytes"); + // Dump full packet for protocol debugging + const auto& data = packet.getData(); + std::string hexDump; + for (size_t i = 0; i < data.size(); ++i) { + char buf[4]; + snprintf(buf, sizeof(buf), "%02x ", data[i]); + hexDump += buf; + if ((i + 1) % 16 == 0) hexDump += "\n"; + } + LOG_DEBUG("CMSG_AUTH_SESSION full dump:\n", hexDump); + return packet; } @@ -220,7 +268,25 @@ network::Packet CharCreatePacket::build(const CharCreateData& data) { packet.writeUInt8(data.facialHair); packet.writeUInt8(0); // outfitId, always 0 - LOG_DEBUG("Built CMSG_CHAR_CREATE: name=", data.name); + LOG_DEBUG("Built CMSG_CHAR_CREATE: name=", data.name, + " race=", static_cast(data.race), + " class=", static_cast(data.characterClass), + " gender=", static_cast(data.gender), + " skin=", static_cast(data.skin), + " face=", static_cast(data.face), + " hair=", static_cast(data.hairStyle), + " hairColor=", static_cast(data.hairColor), + " facial=", static_cast(data.facialHair)); + + // Dump full packet for protocol debugging + const auto& pktData = packet.getData(); + std::string hexDump; + for (size_t i = 0; i < pktData.size(); ++i) { + char buf[4]; + snprintf(buf, sizeof(buf), "%02x ", pktData[i]); + hexDump += buf; + } + LOG_DEBUG("CMSG_CHAR_CREATE full dump: ", hexDump); return packet; } diff --git a/src/network/world_socket.cpp b/src/network/world_socket.cpp index f6528681..95cddcf4 100644 --- a/src/network/world_socket.cpp +++ b/src/network/world_socket.cpp @@ -91,40 +91,79 @@ void WorldSocket::send(const Packet& packet) { const auto& data = packet.getData(); uint16_t opcode = packet.getOpcode(); - uint16_t size = static_cast(data.size()); + uint16_t payloadLen = static_cast(data.size()); + + // WotLK 3.3.5 CMSG header (6 bytes total): + // - size (2 bytes, big-endian) = payloadLen + 4 (opcode is 4 bytes for CMSG) + // - opcode (4 bytes, little-endian) + // Note: Client-to-server uses 4-byte opcode, server-to-client uses 2-byte + uint16_t sizeField = payloadLen + 4; - // Build header (6 bytes for outgoing): size(2) + opcode(4) std::vector sendData; - sendData.reserve(6 + size); + sendData.reserve(6 + payloadLen); - // Size (2 bytes, big-endian) - payload size only, does NOT include header - sendData.push_back((size >> 8) & 0xFF); - sendData.push_back(size & 0xFF); + // Size (2 bytes, big-endian) + uint8_t size_hi = (sizeField >> 8) & 0xFF; + uint8_t size_lo = sizeField & 0xFF; + sendData.push_back(size_hi); + sendData.push_back(size_lo); - // Opcode (4 bytes, big-endian) - sendData.push_back((opcode >> 24) & 0xFF); - sendData.push_back((opcode >> 16) & 0xFF); - sendData.push_back((opcode >> 8) & 0xFF); + // Opcode (4 bytes, little-endian) sendData.push_back(opcode & 0xFF); + sendData.push_back((opcode >> 8) & 0xFF); + sendData.push_back(0); // High bytes are 0 for all WoW opcodes + sendData.push_back(0); - // Encrypt header if encryption is enabled + // Debug: log encryption state and header + LOG_DEBUG("SEND opcode=0x", std::hex, opcode, std::dec, + " encryptionEnabled=", encryptionEnabled, + " header=[", std::hex, + (int)sendData[0], " ", (int)sendData[1], " ", + (int)sendData[2], " ", (int)sendData[3], " ", + (int)sendData[4], " ", (int)sendData[5], std::dec, "]", + " sizeField=", sizeField, " payloadLen=", payloadLen); + + // Encrypt header if encryption is enabled (all 6 bytes) if (encryptionEnabled) { + uint8_t plainHeader[6]; + memcpy(plainHeader, sendData.data(), 6); encryptCipher.process(sendData.data(), 6); - LOG_DEBUG("Encrypted outgoing header: opcode=0x", std::hex, opcode, std::dec); + LOG_DEBUG("Encrypted header: plain=[", std::hex, + (int)plainHeader[0], " ", (int)plainHeader[1], " ", + (int)plainHeader[2], " ", (int)plainHeader[3], " ", + (int)plainHeader[4], " ", (int)plainHeader[5], "] -> enc=[", + (int)sendData[0], " ", (int)sendData[1], " ", + (int)sendData[2], " ", (int)sendData[3], " ", + (int)sendData[4], " ", (int)sendData[5], "]", std::dec); } // Add payload (unencrypted) sendData.insert(sendData.end(), data.begin(), data.end()); LOG_DEBUG("Sending world packet: opcode=0x", std::hex, opcode, std::dec, - " size=", size, " bytes (", sendData.size(), " total)"); + " payload=", payloadLen, " bytes (", sendData.size(), " total)"); + + // Debug: dump packet bytes for AUTH_SESSION + if (opcode == 0x1ED) { + std::string hexDump = "AUTH_SESSION raw bytes: "; + for (size_t i = 0; i < sendData.size(); ++i) { + char buf[4]; + snprintf(buf, sizeof(buf), "%02x ", sendData[i]); + hexDump += buf; + if ((i + 1) % 32 == 0) hexDump += "\n"; + } + LOG_DEBUG(hexDump); + } // Send complete packet ssize_t sent = net::portableSend(sockfd, sendData.data(), sendData.size()); if (sent < 0) { LOG_ERROR("Send failed: ", net::errorString(net::lastError())); - } else if (static_cast(sent) != sendData.size()) { - LOG_WARNING("Partial send: ", sent, " of ", sendData.size(), " bytes"); + } else { + LOG_DEBUG("Actually sent ", sent, " bytes to server"); + if (static_cast(sent) != sendData.size()) { + LOG_WARNING("Partial send: ", sent, " of ", sendData.size(), " bytes"); + } } } @@ -167,12 +206,19 @@ void WorldSocket::tryParsePackets() { decryptCipher.process(header, 4); } - // Parse header (big-endian) + // Parse header + // Size: 2 bytes big-endian (includes opcode, so payload = size - 2) uint16_t size = (header[0] << 8) | header[1]; - uint16_t opcode = (header[2] << 8) | header[3]; + // Opcode: 2 bytes little-endian + uint16_t opcode = header[2] | (header[3] << 8); - // Total packet size: header(4) + payload(size) - size_t totalSize = 4 + size; + LOG_DEBUG("RECV encryptionEnabled=", encryptionEnabled, + " header=[", std::hex, (int)header[0], " ", (int)header[1], " ", + (int)header[2], " ", (int)header[3], std::dec, "]", + " -> size=", size, " opcode=0x", std::hex, opcode, std::dec); + + // Total packet size: size field (2) + size value (which includes opcode + payload) + size_t totalSize = 2 + size; if (receiveBuffer.size() < totalSize) { // Not enough data yet @@ -183,12 +229,23 @@ void WorldSocket::tryParsePackets() { // We have a complete packet! LOG_DEBUG("Parsing world packet: opcode=0x", std::hex, opcode, std::dec, - " size=", size, " bytes"); + " size=", size, " totalSize=", totalSize, " bytes"); // Extract payload (skip header) std::vector packetData(receiveBuffer.begin() + 4, receiveBuffer.begin() + totalSize); + // Log first few bytes of payload + if (!packetData.empty()) { + std::string payloadHex; + for (size_t i = 0; i < std::min(packetData.size(), size_t(16)); i++) { + char buf[4]; + snprintf(buf, sizeof(buf), "%02x ", packetData[i]); + payloadHex += buf; + } + LOG_DEBUG("Payload (first 16 bytes): ", payloadHex); + } + // Create packet with opcode and payload Packet packet(opcode, packetData); @@ -208,13 +265,14 @@ void WorldSocket::initEncryption(const std::vector& sessionKey) { return; } - LOG_INFO("Initializing world server header encryption"); + LOG_INFO(">>> ENABLING ENCRYPTION - encryptionEnabled will become true <<<"); // Convert hardcoded keys to vectors std::vector encryptKey(ENCRYPT_KEY, ENCRYPT_KEY + 16); std::vector decryptKey(DECRYPT_KEY, DECRYPT_KEY + 16); - // Compute HMAC-SHA1(key, sessionKey) for each cipher + // Compute HMAC-SHA1(seed, sessionKey) for each cipher + // The 16-byte seed is the HMAC key, session key is the message std::vector encryptHash = auth::Crypto::hmacSHA1(encryptKey, sessionKey); std::vector decryptHash = auth::Crypto::hmacSHA1(decryptKey, sessionKey);