diff options
| author | Shauren <shauren.trinity@gmail.com> | 2019-07-12 20:42:49 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2019-07-14 19:20:45 +0200 |
| commit | 74a801182a39358d62b596642c82c5f6c6e242e9 (patch) | |
| tree | 1cbc1428e87cb63618fb1edd4d87d945797032af /src/server | |
| parent | 0e4c5697704359f648be4eab52eeb739528eb9d2 (diff) | |
Core/PacketIO: Updated packet encryption to 8.2
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/game/Server/Protocol/PacketLog.cpp | 9 | ||||
| -rw-r--r-- | src/server/game/Server/WorldPacket.h | 2 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 8 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 102 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.h | 7 |
5 files changed, 78 insertions, 50 deletions
diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp index 3c93cc71768..40670836677 100644 --- a/src/server/game/Server/Protocol/PacketLog.cpp +++ b/src/server/game/Server/Protocol/PacketLog.cpp @@ -137,7 +137,16 @@ void PacketLog::LogPacket(WorldPacket const& packet, Direction direction, boost: fwrite(&header, sizeof(header), 1, _file); if (!packet.empty()) + { + uint8 const* data = packet.contents(); + std::size_t size = packet.size(); + if (direction == CLIENT_TO_SERVER) + { + data += 2; + size -= 2; + } fwrite(packet.contents(), 1, packet.size(), _file); + } fflush(_file); } diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h index e817b2dfa3f..e420a55ddb8 100644 --- a/src/server/game/Server/WorldPacket.h +++ b/src/server/game/Server/WorldPacket.h @@ -65,7 +65,7 @@ class WorldPacket : public ByteBuffer return *this; } - WorldPacket(uint32 opcode, MessageBuffer&& buffer, ConnectionType connection) : ByteBuffer(std::move(buffer)), m_opcode(opcode), _connection(connection) { } + WorldPacket(MessageBuffer&& buffer, ConnectionType connection) : ByteBuffer(std::move(buffer)), m_opcode(UNKNOWN_OPCODE), _connection(connection) { } void Initialize(uint32 opcode, size_t newres = 200, ConnectionType connection = CONNECTION_TYPE_DEFAULT) { diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 143c53f8a65..1f5f2a829c7 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -722,13 +722,13 @@ void WorldSession::SendConnectToInstance(WorldPackets::Auth::ConnectToSerial ser connectTo.Payload.Port = sWorld->getIntConfig(CONFIG_PORT_INSTANCE); if (instanceAddress.is_v4()) { - memcpy(connectTo.Payload.Where.data(), instanceAddress.to_v4().to_bytes().data(), 4); - connectTo.Payload.Type = WorldPackets::Auth::ConnectTo::IPv4; + memcpy(connectTo.Payload.Where.Address.V4.data(), instanceAddress.to_v4().to_bytes().data(), 4); + connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv4; } else { - memcpy(connectTo.Payload.Where.data(), instanceAddress.to_v6().to_bytes().data(), 16); - connectTo.Payload.Type = WorldPackets::Auth::ConnectTo::IPv6; + memcpy(connectTo.Payload.Where.Address.V6.data(), instanceAddress.to_v6().to_bytes().data(), 16); + connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv6; } connectTo.Con = CONNECTION_TYPE_INSTANCE; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 3fa7c3e2cf1..148e1fda0ca 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -60,18 +60,16 @@ private: using boost::asio::ip::tcp; -std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT"); -std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER"); +std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT - V2"); +std::string const WorldSocket::ClientConnectionInitialize("WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER - V2"); uint32 const WorldSocket::MinSizeForCompression = 0x400; -uint32 const SizeOfClientHeader = sizeof(uint32) + sizeof(uint16); -uint32 const SizeOfServerHeader = sizeof(uint32) + sizeof(uint16); - uint8 const WorldSocket::AuthCheckSeed[16] = { 0xC5, 0xC6, 0x98, 0x95, 0x76, 0x3F, 0x1D, 0xCD, 0xB6, 0xA1, 0x37, 0x28, 0xB3, 0x12, 0xFF, 0x8A }; uint8 const WorldSocket::SessionKeySeed[16] = { 0x58, 0xCB, 0xCF, 0x40, 0xFE, 0x2E, 0xCE, 0xA6, 0x5A, 0x90, 0xB8, 0x01, 0x68, 0x6C, 0x28, 0x0B }; uint8 const WorldSocket::ContinuedSessionSeed[16] = { 0x16, 0xAD, 0x0C, 0xD4, 0x46, 0xF9, 0x4F, 0xB2, 0xEF, 0x7D, 0xEA, 0x2A, 0x17, 0x66, 0x4D, 0x2F }; +uint8 const WorldSocket::EncryptionKeySeed[16] = { 0xE9, 0x75, 0x3C, 0x50, 0x90, 0x93, 0x61, 0xDA, 0x3B, 0x07, 0xEE, 0xFA, 0xFF, 0x9D, 0x41, 0xB8 }; -uint8 const ClientTypeSeed_Wn64[16] = { 0xBB, 0x6D, 0x98, 0x66, 0xFE, 0x4A, 0x19, 0xA5, 0x68, 0x01, 0x51, 0x98, 0x78, 0x30, 0x03, 0xFC }; +uint8 const ClientTypeSeed_Wn64[16] = { 0x2B, 0xAD, 0x61, 0x65, 0x5A, 0xBC, 0x2F, 0xC3, 0xD0, 0x48, 0x93, 0xB5, 0x36, 0x40, 0x3A, 0x91 }; uint8 const ClientTypeSeed_Mc64[16] = { 0x34, 0x1C, 0xFE, 0xFE, 0x3D, 0x72, 0xAC, 0xA9, 0xA4, 0x40, 0x7D, 0xC5, 0x35, 0xDE, 0xD6, 0x6A }; WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), @@ -79,7 +77,8 @@ WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), _worldSession(nullptr), _authed(false), _sendBufferSize(4096), _compressionStream(nullptr) { _serverChallenge.SetRand(8 * 16); - _headerBuffer.Resize(SizeOfClientHeader); + memset(_encryptKey, 0, sizeof(_encryptKey)); + _headerBuffer.Resize(sizeof(PacketHeader)); } WorldSocket::~WorldSocket() @@ -211,17 +210,17 @@ bool WorldSocket::Update() if (packetSize > MinSizeForCompression && queued->NeedsEncryption()) packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); - if (buffer.GetRemainingSpace() < packetSize + SizeOfServerHeader) + if (buffer.GetRemainingSpace() < packetSize + sizeof(PacketHeader)) { QueuePacket(std::move(buffer)); buffer.Resize(_sendBufferSize); } - if (buffer.GetRemainingSpace() >= packetSize + SizeOfServerHeader) + if (buffer.GetRemainingSpace() >= packetSize + sizeof(PacketHeader)) WritePacketToBuffer(*queued, buffer); else // single packet larger than 4096 bytes { - MessageBuffer packetBuffer(packetSize + SizeOfServerHeader); + MessageBuffer packetBuffer(packetSize + sizeof(PacketHeader)); WritePacketToBuffer(*queued, packetBuffer); QueuePacket(std::move(packetBuffer)); } @@ -242,13 +241,12 @@ bool WorldSocket::Update() void WorldSocket::HandleSendAuthSession() { - _encryptSeed.SetRand(16 * 8); - _decryptSeed.SetRand(16 * 8); + BigNumber dosChallenge; + dosChallenge.SetRand(32 * 8); WorldPackets::Auth::AuthChallenge challenge; memcpy(challenge.Challenge.data(), _serverChallenge.AsByteArray(16).get(), 16); - memcpy(&challenge.DosChallenge[0], _encryptSeed.AsByteArray(16).get(), 16); - memcpy(&challenge.DosChallenge[4], _decryptSeed.AsByteArray(16).get(), 16); + memcpy(challenge.DosChallenge.data(), dosChallenge.AsByteArray(32).get(), 32); challenge.DosZeroBits = 1; SendPacketAndLogOpcode(*challenge.Write()); @@ -332,17 +330,14 @@ void WorldSocket::SetWorldSession(WorldSession* session) bool WorldSocket::ReadHeaderHandler() { - ASSERT(_headerBuffer.GetActiveSize() == SizeOfClientHeader, "Header size " SZFMTD " different than expected %u", _headerBuffer.GetActiveSize(), SizeOfClientHeader); - - _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), 4); + ASSERT(_headerBuffer.GetActiveSize() == sizeof(PacketHeader), "Header size " SZFMTD " different than expected %u", _headerBuffer.GetActiveSize(), sizeof(PacketHeader)); PacketHeader* header = reinterpret_cast<PacketHeader*>(_headerBuffer.GetReadPointer()); - header->Size -= 2; - if (!header->IsValidSize() || !header->IsValidOpcode()) + if (!header->IsValidSize()) { - TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %u, cmd: %u)", - GetRemoteIpAddress().to_string().c_str(), header->Size, header->Command); + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %u)", + GetRemoteIpAddress().to_string().c_str(), header->Size); return false; } @@ -353,9 +348,24 @@ bool WorldSocket::ReadHeaderHandler() WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() { PacketHeader* header = reinterpret_cast<PacketHeader*>(_headerBuffer.GetReadPointer()); - OpcodeClient opcode = static_cast<OpcodeClient>(header->Command); - WorldPacket packet(opcode, std::move(_packetBuffer), GetConnectionType()); + if (!_authCrypt.DecryptRecv(_packetBuffer.GetReadPointer(), header->Size, header->Tag)) + { + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s failed to decrypt packet (size: %u)", + GetRemoteIpAddress().to_string().c_str(), header->Size); + return ReadDataHandlerResult::Error; + } + + WorldPacket packet(std::move(_packetBuffer), GetConnectionType()); + OpcodeClient opcode = packet.read<OpcodeClient>(); + if (opcode >= NUM_OPCODE_HANDLERS) + { + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent wrong opcode (opcode: %u)", + GetRemoteIpAddress().to_string().c_str(), uint32(opcode)); + return ReadDataHandlerResult::Error; + } + + packet.SetOpcode(opcode); if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort(), GetConnectionType()); @@ -510,12 +520,14 @@ void WorldSocket::SendPacket(WorldPacket const& packet) void WorldSocket::WritePacketToBuffer(EncryptablePacket const& packet, MessageBuffer& buffer) { - uint32 opcode = packet.GetOpcode(); + uint16 opcode = packet.GetOpcode(); uint32 packetSize = packet.size(); // Reserve space for buffer uint8* headerPos = buffer.GetWritePointer(); - buffer.WriteCompleted(SizeOfServerHeader); + buffer.WriteCompleted(sizeof(PacketHeader)); + uint8* dataPos = buffer.GetWritePointer(); + buffer.WriteCompleted(sizeof(opcode)); if (packetSize > MinSizeForCompression && packet.NeedsEncryption()) { @@ -540,14 +552,14 @@ void WorldSocket::WritePacketToBuffer(EncryptablePacket const& packet, MessageBu else if (!packet.empty()) buffer.Write(packet.contents(), packet.size()); + memcpy(dataPos, &opcode, sizeof(opcode)); packetSize += 2 /*opcode*/; PacketHeader header; header.Size = packetSize; - header.Command = opcode; - _authCrypt.EncryptSend((uint8*)&header, 4); + _authCrypt.EncryptSend(dataPos, header.Size, header.Tag); - memcpy(headerPos, &header, SizeOfServerHeader); + memcpy(headerPos, &header, sizeof(PacketHeader)); } uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet) @@ -703,6 +715,15 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: _sessionKey.SetBinary(sessionKey, 40); + HmacSha256 encryptKeyGen(40, sessionKey); + encryptKeyGen.UpdateData(authSession->LocalChallenge.data(), authSession->LocalChallenge.size()); + encryptKeyGen.UpdateData(_serverChallenge.AsByteArray(16).get(), 16); + encryptKeyGen.UpdateData(EncryptionKeySeed, 16); + encryptKeyGen.Finalize(); + + // only first 16 bytes of the hmac are used + memcpy(_encryptKey, encryptKeyGen.GetDigest(), 16); + // As we don't know if attempted login process by ip works, we update last_attempt_ip right away PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); stmt->setString(0, address); @@ -835,7 +856,7 @@ void WorldSocket::LoadSessionPermissionsCallback(PreparedQueryResult result) // RBAC must be loaded before adding session to check for skip queue permission _worldSession->GetRBACData()->LoadFromDBCallback(result); - SendPacketAndLogOpcode(*WorldPackets::Auth::EnableEncryption().Write()); + SendPacketAndLogOpcode(*WorldPackets::Auth::EnableEncryption(_encryptKey, true).Write()); } void WorldSocket::HandleAuthContinuedSession(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession) @@ -889,7 +910,16 @@ void WorldSocket::HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPacket return; } - SendPacketAndLogOpcode(*WorldPackets::Auth::EnableEncryption().Write()); + HmacSha256 encryptKeyGen(40, _sessionKey.AsByteArray(40).get()); + encryptKeyGen.UpdateData(authSession->LocalChallenge.data(), authSession->LocalChallenge.size()); + encryptKeyGen.UpdateData(_serverChallenge.AsByteArray(16).get(), 16); + encryptKeyGen.UpdateData(EncryptionKeySeed, 16); + encryptKeyGen.Finalize(); + + // only first 16 bytes of the hmac are used + memcpy(_encryptKey, encryptKeyGen.GetDigest(), 16); + + SendPacketAndLogOpcode(*WorldPackets::Auth::EnableEncryption(_encryptKey, true).Write()); AsyncRead(); } @@ -933,16 +963,11 @@ void WorldSocket::HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed& con void WorldSocket::HandleEnableEncryptionAck() { + _authCrypt.Init(_encryptKey); if (_type == CONNECTION_TYPE_REALM) - { - _authCrypt.Init(&_sessionKey); sWorld->AddSession(_worldSession); - } else - { - _authCrypt.Init(&_sessionKey, _encryptSeed.AsByteArray().get(), _decryptSeed.AsByteArray().get()); sWorld->AddInstanceSocket(shared_from_this(), _key); - } } void WorldSocket::SendAuthResponseError(uint32 code) @@ -1009,8 +1034,3 @@ bool WorldSocket::HandlePing(WorldPackets::Auth::Ping& ping) SendPacketAndLogOpcode(*WorldPackets::Auth::Pong(ping.Serial).Write()); return true; } - -bool PacketHeader::IsValidOpcode() -{ - return Command < NUM_OPCODE_HANDLERS; -} diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 95a18920f91..1dde8562521 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -55,10 +55,9 @@ namespace WorldPackets struct PacketHeader { uint32 Size; - uint16 Command; + uint8 Tag[12]; bool IsValidSize() { return Size < 0x10000; } - bool IsValidOpcode(); }; #pragma pack(pop) @@ -72,6 +71,7 @@ class TC_GAME_API WorldSocket : public Socket<WorldSocket> static uint8 const AuthCheckSeed[16]; static uint8 const SessionKeySeed[16]; static uint8 const ContinuedSessionSeed[16]; + static uint8 const EncryptionKeySeed[16]; typedef Socket<WorldSocket> BaseSocket; @@ -133,9 +133,8 @@ private: BigNumber _serverChallenge; WorldPacketCrypt _authCrypt; - BigNumber _encryptSeed; - BigNumber _decryptSeed; BigNumber _sessionKey; + uint8 _encryptKey[16]; std::chrono::steady_clock::time_point _LastPingTime; uint32 _OverSpeedPings; |
