diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Cryptography/AES.cpp | 55 | ||||
-rw-r--r-- | src/common/Cryptography/AES.h (renamed from src/common/Cryptography/Authentication/PacketCrypt.cpp) | 35 | ||||
-rw-r--r-- | src/common/Cryptography/Authentication/PacketCrypt.h | 43 | ||||
-rw-r--r-- | src/common/Cryptography/Authentication/WorldPacketCrypt.cpp | 59 | ||||
-rw-r--r-- | src/common/Cryptography/Authentication/WorldPacketCrypt.h | 22 | ||||
-rw-r--r-- | src/common/Cryptography/RSA.cpp | 2 | ||||
-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 |
11 files changed, 205 insertions, 139 deletions
diff --git a/src/common/Cryptography/AES.cpp b/src/common/Cryptography/AES.cpp new file mode 100644 index 00000000000..cd9ff29f79f --- /dev/null +++ b/src/common/Cryptography/AES.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "AES.h" + +Trinity::Crypto::AES::AES(bool encrypting) : _ctx(EVP_CIPHER_CTX_new()) +{ + EVP_CIPHER_CTX_init(_ctx); + EVP_CipherInit_ex(_ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr, encrypting ? 1 : 0); +} + +Trinity::Crypto::AES::~AES() +{ + EVP_CIPHER_CTX_free(_ctx); +} + +void Trinity::Crypto::AES::Init(uint8 const* key) +{ + EVP_CipherInit_ex(_ctx, nullptr, nullptr, key, nullptr, -1); +} + +bool Trinity::Crypto::AES::Process(uint8 const* iv, uint8* data, std::size_t length, uint8* tag) +{ + if (!EVP_CipherInit_ex(_ctx, nullptr, nullptr, nullptr, iv, -1)) + return false; + + int outLen; + if (!EVP_CipherUpdate(_ctx, data, &outLen, data, length)) + return false; + + if (!EVP_CIPHER_CTX_encrypting(_ctx) && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_SET_TAG, 12, tag)) + return false; + + if (!EVP_CipherFinal_ex(_ctx, data + outLen, &outLen)) + return false; + + if (EVP_CIPHER_CTX_encrypting(_ctx) && !EVP_CIPHER_CTX_ctrl(_ctx, EVP_CTRL_GCM_GET_TAG, 12, tag)) + return false; + + return true; +} diff --git a/src/common/Cryptography/Authentication/PacketCrypt.cpp b/src/common/Cryptography/AES.h index 3d5a565a9e7..edb096ae69e 100644 --- a/src/common/Cryptography/Authentication/PacketCrypt.cpp +++ b/src/common/Cryptography/AES.h @@ -15,25 +15,30 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "PacketCrypt.h" +#ifndef Trinity_AES_h__ +#define Trinity_AES_h__ -PacketCrypt::PacketCrypt(uint32 rc4InitSize) - : _clientDecrypt(rc4InitSize), _serverEncrypt(rc4InitSize), _initialized(false) -{ -} +#include "Define.h" +#include <openssl/evp.h> -void PacketCrypt::DecryptRecv(uint8* data, size_t len) +namespace Trinity +{ +namespace Crypto +{ +class TC_COMMON_API AES { - if (!_initialized) - return; +public: + AES(bool encrypting); + ~AES(); - _clientDecrypt.UpdateData(len, data); -} + void Init(uint8 const* key); -void PacketCrypt::EncryptSend(uint8* data, size_t len) -{ - if (!_initialized) - return; + bool Process(uint8 const* iv, uint8* data, std::size_t length, uint8* tag); - _serverEncrypt.UpdateData(len, data); +private: + EVP_CIPHER_CTX* _ctx; +}; } +} + +#endif // Trinity_AES_h__ diff --git a/src/common/Cryptography/Authentication/PacketCrypt.h b/src/common/Cryptography/Authentication/PacketCrypt.h deleted file mode 100644 index d1e891f5ce0..00000000000 --- a/src/common/Cryptography/Authentication/PacketCrypt.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _PACKETCRYPT_H -#define _PACKETCRYPT_H - -#include "Cryptography/ARC4.h" - -class BigNumber; - -class TC_COMMON_API PacketCrypt -{ - public: - PacketCrypt(uint32 rc4InitSize); - virtual ~PacketCrypt() { } - - virtual void Init(BigNumber* K) = 0; - void DecryptRecv(uint8* data, size_t length); - void EncryptSend(uint8* data, size_t length); - - bool IsInitialized() const { return _initialized; } - - protected: - ARC4 _clientDecrypt; - ARC4 _serverEncrypt; - bool _initialized; -}; - -#endif // _PACKETCRYPT_H diff --git a/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp index 04ee142cb40..af1ac4cfdc6 100644 --- a/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp +++ b/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -17,42 +17,53 @@ */ #include "WorldPacketCrypt.h" -#include "Cryptography/HmacHash.h" -#include "Cryptography/BigNumber.h" - +#include <array> #include <cstring> -WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) +WorldPacketCrypt::WorldPacketCrypt() : _clientDecrypt(false), _serverEncrypt(true), _clientCounter(0), _serverCounter(0), _initialized(false) { } -void WorldPacketCrypt::Init(BigNumber* K) +void WorldPacketCrypt::Init(uint8 const* key) { - uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x08, 0xF1, 0x95, 0x9F, 0x47, 0xE5, 0xD2, 0xDB, 0xA1, 0x3D, 0x77, 0x8F, 0x3F, 0x3E, 0xE7, 0x00 }; - uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0x40, 0xAA, 0xD3, 0x92, 0x26, 0x71, 0x43, 0x47, 0x3A, 0x31, 0x08, 0xA6, 0xE7, 0xDC, 0x98, 0x2A }; - Init(K, ServerEncryptionKey, ServerDecryptionKey); + _clientDecrypt.Init(key); + _serverEncrypt.Init(key); + _initialized = true; } -void WorldPacketCrypt::Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey) +struct WorldPacketCryptIV { - HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)serverKey); - uint8 *encryptHash = serverEncryptHmac.ComputeHash(k); - - HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)clientKey); - uint8 *decryptHash = clientDecryptHmac.ComputeHash(k); - - _clientDecrypt.Init(decryptHash); - _serverEncrypt.Init(encryptHash); + WorldPacketCryptIV(uint64 counter, uint32 magic) + { + memcpy(Value.data(), &counter, sizeof(uint64)); + memcpy(Value.data() + sizeof(uint64), &magic, sizeof(uint32)); + } - // Drop first 1024 bytes, as WoW uses ARC4-drop1024. - uint8 syncBuf[1024]; - memset(syncBuf, 0, 1024); + std::array<uint8, 12> Value; +}; - _serverEncrypt.UpdateData(1024, syncBuf); +bool WorldPacketCrypt::DecryptRecv(uint8* data, size_t len, uint8* tag) +{ + if (_initialized) + { + WorldPacketCryptIV iv{ _clientCounter, 0x544E4C43 }; + if (!_clientDecrypt.Process(iv.Value.data(), data, len, tag)) + return false; + } - memset(syncBuf, 0, 1024); + ++_clientCounter; + return true; +} - _clientDecrypt.UpdateData(1024, syncBuf); +bool WorldPacketCrypt::EncryptSend(uint8* data, size_t len, uint8* tag) +{ + if (_initialized) + { + WorldPacketCryptIV iv{ _serverCounter, 0x52565253 }; + if (!_serverEncrypt.Process(iv.Value.data(), data, len, tag)) + return false; + } - _initialized = true; + ++_serverCounter; + return true; } diff --git a/src/common/Cryptography/Authentication/WorldPacketCrypt.h b/src/common/Cryptography/Authentication/WorldPacketCrypt.h index acb403a026e..155d741fdea 100644 --- a/src/common/Cryptography/Authentication/WorldPacketCrypt.h +++ b/src/common/Cryptography/Authentication/WorldPacketCrypt.h @@ -19,17 +19,27 @@ #ifndef _WORLDPACKETCRYPT_H #define _WORLDPACKETCRYPT_H -#include "PacketCrypt.h" +#include "Cryptography/AES.h" class BigNumber; -class TC_COMMON_API WorldPacketCrypt : public PacketCrypt +class TC_COMMON_API WorldPacketCrypt { - public: - WorldPacketCrypt(); +public: + WorldPacketCrypt(); - void Init(BigNumber* K) override; - void Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey); + void Init(uint8 const* key); + bool DecryptRecv(uint8* data, size_t length, uint8* tag); + bool EncryptSend(uint8* data, size_t length, uint8* tag); + + bool IsInitialized() const { return _initialized; } + +protected: + Trinity::Crypto::AES _clientDecrypt; + Trinity::Crypto::AES _serverEncrypt; + uint64 _clientCounter; + uint64 _serverCounter; + bool _initialized; }; #endif // _WORLDPACKETCRYPT_H diff --git a/src/common/Cryptography/RSA.cpp b/src/common/Cryptography/RSA.cpp index 3885e17d71c..97a406f690c 100644 --- a/src/common/Cryptography/RSA.cpp +++ b/src/common/Cryptography/RSA.cpp @@ -117,7 +117,7 @@ bool Trinity::Crypto::RSA::Sign(int32 hashType, uint8 const* dataHash, std::size uint32 signatureLength = 0; int result = RSA_sign(hashType, dataHash, dataHashLength, output, &signatureLength, _rsa); std::reverse(output, output + GetOutputSize()); - return result != -1; + return result != 0; } namespace Trinity 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; |