aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Cryptography/AES.cpp22
-rw-r--r--src/common/Cryptography/AES.h1
-rw-r--r--src/common/Cryptography/Authentication/WorldPacketCrypt.cpp12
-rw-r--r--src/common/Cryptography/Authentication/WorldPacketCrypt.h1
-rw-r--r--src/server/game/Server/WorldSocket.cpp25
-rw-r--r--src/server/game/Server/WorldSocket.h8
6 files changed, 61 insertions, 8 deletions
diff --git a/src/common/Cryptography/AES.cpp b/src/common/Cryptography/AES.cpp
index 7d4ccc7c46f..1b011da7c9b 100644
--- a/src/common/Cryptography/AES.cpp
+++ b/src/common/Cryptography/AES.cpp
@@ -63,3 +63,25 @@ bool Trinity::Crypto::AES::Process(IV const& iv, uint8* data, size_t length, Tag
return true;
}
+
+bool Trinity::Crypto::AES::ProcessNoIntegrityCheck(IV const& iv, uint8* data, size_t partialLength)
+{
+ ASSERT(!_encrypting, "Partial encryption is not allowed");
+ ASSERT(partialLength <= std::numeric_limits<int>::max());
+ int len = static_cast<int>(partialLength);
+ if (!EVP_CipherInit_ex(_ctx, nullptr, nullptr, nullptr, iv.data(), -1))
+ return false;
+
+ int outLen;
+ if (!EVP_CipherUpdate(_ctx, data, &outLen, data, len))
+ return false;
+
+ len -= outLen;
+
+ if (!EVP_CipherFinal_ex(_ctx, data + outLen, &outLen))
+ return false;
+
+ ASSERT(len == outLen);
+
+ return true;
+}
diff --git a/src/common/Cryptography/AES.h b/src/common/Cryptography/AES.h
index d3b9f48c552..e559be75a16 100644
--- a/src/common/Cryptography/AES.h
+++ b/src/common/Cryptography/AES.h
@@ -43,6 +43,7 @@ namespace Crypto
void Init(Key const& key);
bool Process(IV const& iv, uint8* data, size_t length, Tag& tag);
+ bool ProcessNoIntegrityCheck(IV const& iv, uint8* data, size_t partialLength);
private:
EVP_CIPHER_CTX* _ctx;
diff --git a/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp
index 723657048d5..926f77d757d 100644
--- a/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp
+++ b/src/common/Cryptography/Authentication/WorldPacketCrypt.cpp
@@ -41,6 +41,18 @@ struct WorldPacketCryptIV
std::array<uint8, 12> Value;
};
+bool WorldPacketCrypt::PeekDecryptRecv(uint8* data, size_t length)
+{
+ if (_initialized)
+ {
+ WorldPacketCryptIV iv{ _clientCounter, 0x544E4C43 };
+ if (!_clientDecrypt.ProcessNoIntegrityCheck(iv.Value, data, length))
+ return false;
+ }
+
+ return true;
+}
+
bool WorldPacketCrypt::DecryptRecv(uint8* data, size_t length, Trinity::Crypto::AES::Tag& tag)
{
if (_initialized)
diff --git a/src/common/Cryptography/Authentication/WorldPacketCrypt.h b/src/common/Cryptography/Authentication/WorldPacketCrypt.h
index 5cd6e1282b8..600d0d1715e 100644
--- a/src/common/Cryptography/Authentication/WorldPacketCrypt.h
+++ b/src/common/Cryptography/Authentication/WorldPacketCrypt.h
@@ -27,6 +27,7 @@ public:
WorldPacketCrypt();
void Init(Trinity::Crypto::AES::Key const& key);
+ bool PeekDecryptRecv(uint8* data, size_t length);
bool DecryptRecv(uint8* data, size_t length, Trinity::Crypto::AES::Tag& tag);
bool EncryptSend(uint8* data, size_t length, Trinity::Crypto::AES::Tag& tag);
diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp
index 0b0eeda6b86..3e22c91e2a1 100644
--- a/src/server/game/Server/WorldSocket.cpp
+++ b/src/server/game/Server/WorldSocket.cpp
@@ -71,11 +71,11 @@ uint8 const WorldSocket::EncryptionKeySeed[16] = { 0xE9, 0x75, 0x3C, 0x50, 0x90,
WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)),
_type(CONNECTION_TYPE_REALM), _key(0), _OverSpeedPings(0),
- _worldSession(nullptr), _authed(false), _sendBufferSize(4096), _compressionStream(nullptr)
+ _worldSession(nullptr), _authed(false), _canRequestHotfixes(true), _sendBufferSize(4096), _compressionStream(nullptr)
{
Trinity::Crypto::GetRandomBytes(_serverChallenge);
_encryptKey.fill(0);
- _headerBuffer.Resize(sizeof(PacketHeader));
+ _headerBuffer.Resize(sizeof(IncomingPacketHeader));
}
WorldSocket::~WorldSocket()
@@ -324,18 +324,26 @@ void WorldSocket::SetWorldSession(WorldSession* session)
bool WorldSocket::ReadHeaderHandler()
{
- ASSERT(_headerBuffer.GetActiveSize() == sizeof(PacketHeader), "Header size " SZFMTD " different than expected " SZFMTD, _headerBuffer.GetActiveSize(), sizeof(PacketHeader));
+ ASSERT(_headerBuffer.GetActiveSize() == sizeof(IncomingPacketHeader), "Header size " SZFMTD " different than expected " SZFMTD, _headerBuffer.GetActiveSize(), sizeof(IncomingPacketHeader));
- PacketHeader* header = reinterpret_cast<PacketHeader*>(_headerBuffer.GetReadPointer());
+ IncomingPacketHeader* header = reinterpret_cast<IncomingPacketHeader*>(_headerBuffer.GetReadPointer());
+ uint16 encryptedOpcode = header->EncryptedOpcode;
if (!header->IsValidSize())
{
- TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %u)",
- GetRemoteIpAddress().to_string().c_str(), header->Size);
- return false;
+ _authCrypt.PeekDecryptRecv(reinterpret_cast<uint8*>(&header->EncryptedOpcode), sizeof(encryptedOpcode));
+
+ // CMSG_HOTFIX_REQUEST can be much larger than normal packets, allow receiving it once per session
+ if (header->EncryptedOpcode != CMSG_HOTFIX_REQUEST || header->Size > 0x100000 || !_canRequestHotfixes)
+ {
+ TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %u, opcode %u)",
+ GetRemoteIpAddress().to_string().c_str(), header->Size, uint32(header->EncryptedOpcode));
+ return false;
+ }
}
_packetBuffer.Resize(header->Size);
+ _packetBuffer.Write(&encryptedOpcode, sizeof(encryptedOpcode));
return true;
}
@@ -453,6 +461,9 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
LogOpcodeText(opcode, sessionGuard);
HandleEnterEncryptedModeAck();
break;
+ case CMSG_HOTFIX_REQUEST:
+ _canRequestHotfixes = false;
+ /* fallthrough */
default:
{
sessionGuard.lock();
diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h
index da7890d4b07..5327db10ed6 100644
--- a/src/server/game/Server/WorldSocket.h
+++ b/src/server/game/Server/WorldSocket.h
@@ -57,7 +57,12 @@ struct PacketHeader
uint32 Size;
uint8 Tag[12];
- bool IsValidSize() { return Size < 0x40000; }
+ bool IsValidSize() { return Size < 0x10000; }
+};
+
+struct IncomingPacketHeader : PacketHeader
+{
+ uint16 EncryptedOpcode;
};
#pragma pack(pop)
@@ -142,6 +147,7 @@ private:
std::mutex _worldSessionLock;
WorldSession* _worldSession;
bool _authed;
+ bool _canRequestHotfixes;
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;