aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-07-12 20:42:49 +0200
committerShauren <shauren.trinity@gmail.com>2019-07-14 19:20:45 +0200
commit74a801182a39358d62b596642c82c5f6c6e242e9 (patch)
tree1cbc1428e87cb63618fb1edd4d87d945797032af
parent0e4c5697704359f648be4eab52eeb739528eb9d2 (diff)
Core/PacketIO: Updated packet encryption to 8.2
-rw-r--r--src/common/Cryptography/AES.cpp55
-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.h43
-rw-r--r--src/common/Cryptography/Authentication/WorldPacketCrypt.cpp59
-rw-r--r--src/common/Cryptography/Authentication/WorldPacketCrypt.h22
-rw-r--r--src/common/Cryptography/RSA.cpp2
-rw-r--r--src/server/game/Server/Protocol/PacketLog.cpp9
-rw-r--r--src/server/game/Server/WorldPacket.h2
-rw-r--r--src/server/game/Server/WorldSession.cpp8
-rw-r--r--src/server/game/Server/WorldSocket.cpp102
-rw-r--r--src/server/game/Server/WorldSocket.h7
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;