1
0

Do protocol decryption in-place (with CryptoAPI on Windows) (#5145)

This commit is contained in:
Tiger Wang
2021-03-08 16:37:36 +00:00
committed by GitHub
parent 3daf253b7f
commit 01a4e696b3
10 changed files with 206 additions and 174 deletions

View File

@@ -173,31 +173,14 @@ cProtocol_1_8_0::cProtocol_1_8_0(cClientHandle * a_Client, const AString & a_Ser
void cProtocol_1_8_0::DataReceived(cByteBuffer & a_Buffer, const char * a_Data, size_t a_Size)
void cProtocol_1_8_0::DataReceived(cByteBuffer & a_Buffer, ContiguousByteBuffer && a_Data)
{
if (m_IsEncrypted)
{
// An artefact of the protocol recogniser, will be removed when decryption done in-place:
if (a_Size == 0)
{
AddReceivedData(a_Buffer, nullptr, 0);
return;
}
m_Decryptor.ProcessData(a_Data.data(), a_Data.size());
}
std::byte Decrypted[512];
while (a_Size > 0)
{
size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size;
m_Decryptor.ProcessData(Decrypted, reinterpret_cast<const Byte *>(a_Data), NumBytes);
AddReceivedData(a_Buffer, reinterpret_cast<const char *>(Decrypted), NumBytes);
a_Size -= NumBytes;
a_Data += NumBytes;
}
}
else
{
AddReceivedData(a_Buffer, a_Data, a_Size);
}
AddReceivedData(a_Buffer, a_Data);
}
@@ -2002,123 +1985,6 @@ UInt32 cProtocol_1_8_0::GetProtocolMobType(const eMonsterType a_MobType)
void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const char * a_Data, size_t a_Size)
{
// Write the incoming data into the comm log file:
if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
{
if (a_Buffer.GetReadableSpace() > 0)
{
ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
m_CommLogFile.Printf("Incoming data, %zu (0x%zx) unparsed bytes already present in buffer:\n%s\n",
AllData.size(), AllData.size(), Hex.c_str()
);
}
AString Hex;
CreateHexDump(Hex, a_Data, a_Size, 16);
m_CommLogFile.Printf("Incoming data: %u (0x%x) bytes: \n%s\n",
static_cast<unsigned>(a_Size), static_cast<unsigned>(a_Size), Hex.c_str()
);
m_CommLogFile.Flush();
}
if (!a_Buffer.Write(a_Data, a_Size))
{
// Too much data in the incoming queue, report to caller:
m_Client->PacketBufferFull();
return;
}
// Handle all complete packets:
for (;;)
{
UInt32 PacketLen;
if (!a_Buffer.ReadVarInt(PacketLen))
{
// Not enough data
a_Buffer.ResetRead();
break;
}
if (!a_Buffer.CanReadBytes(PacketLen))
{
// The full packet hasn't been received yet
a_Buffer.ResetRead();
break;
}
// Check packet for compression:
if (m_State == 3)
{
UInt32 NumBytesRead = static_cast<UInt32>(a_Buffer.GetReadableSpace());
UInt32 UncompressedSize;
if (!a_Buffer.ReadVarInt(UncompressedSize))
{
m_Client->Kick("Compression packet incomplete");
return;
}
NumBytesRead -= static_cast<UInt32>(a_Buffer.GetReadableSpace()); // How many bytes has the UncompressedSize taken up?
ASSERT(PacketLen > NumBytesRead);
PacketLen -= NumBytesRead;
if (UncompressedSize > 0)
{
// Decompress the data:
m_Extractor.ReadFrom(a_Buffer, PacketLen);
a_Buffer.CommitRead();
const auto UncompressedData = m_Extractor.Extract(UncompressedSize);
const auto Uncompressed = UncompressedData.GetView();
cByteBuffer bb(Uncompressed.size());
// Compression was used, move the uncompressed data:
VERIFY(bb.Write(Uncompressed.data(), Uncompressed.size()));
HandlePacket(bb);
continue;
}
}
// Move the packet payload to a separate cByteBuffer, bb:
cByteBuffer bb(PacketLen);
// No compression was used, move directly:
VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
a_Buffer.CommitRead();
HandlePacket(bb);
} // for (ever)
// Log any leftover bytes into the logfile:
if (g_ShouldLogCommIn && (a_Buffer.GetReadableSpace() > 0) && m_CommLogFile.IsOpen())
{
ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
m_CommLogFile.Printf("There are %zu (0x%zx) bytes of non-parse-able data left in the buffer:\n%s",
a_Buffer.GetReadableSpace(), a_Buffer.GetReadableSpace(), Hex.c_str()
);
m_CommLogFile.Flush();
}
}
UInt32 cProtocol_1_8_0::GetPacketID(ePacketType a_PacketType)
{
switch (a_PacketType)
@@ -3961,6 +3827,123 @@ void cProtocol_1_8_0::WriteEntityProperties(cPacketizer & a_Pkt, const cEntity &
void cProtocol_1_8_0::AddReceivedData(cByteBuffer & a_Buffer, const ContiguousByteBufferView a_Data)
{
// Write the incoming data into the comm log file:
if (g_ShouldLogCommIn && m_CommLogFile.IsOpen())
{
if (a_Buffer.GetReadableSpace() > 0)
{
ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
m_CommLogFile.Printf("Incoming data, %zu (0x%zx) unparsed bytes already present in buffer:\n%s\n",
AllData.size(), AllData.size(), Hex.c_str()
);
}
AString Hex;
CreateHexDump(Hex, a_Data.data(), a_Data.size(), 16);
m_CommLogFile.Printf("Incoming data: %zu (0x%zx) bytes: \n%s\n",
a_Data.size(), a_Data.size(), Hex.c_str()
);
m_CommLogFile.Flush();
}
if (!a_Buffer.Write(a_Data.data(), a_Data.size()))
{
// Too much data in the incoming queue, report to caller:
m_Client->PacketBufferFull();
return;
}
// Handle all complete packets:
for (;;)
{
UInt32 PacketLen;
if (!a_Buffer.ReadVarInt(PacketLen))
{
// Not enough data
a_Buffer.ResetRead();
break;
}
if (!a_Buffer.CanReadBytes(PacketLen))
{
// The full packet hasn't been received yet
a_Buffer.ResetRead();
break;
}
// Check packet for compression:
if (m_State == 3)
{
UInt32 NumBytesRead = static_cast<UInt32>(a_Buffer.GetReadableSpace());
UInt32 UncompressedSize;
if (!a_Buffer.ReadVarInt(UncompressedSize))
{
m_Client->Kick("Compression packet incomplete");
return;
}
NumBytesRead -= static_cast<UInt32>(a_Buffer.GetReadableSpace()); // How many bytes has the UncompressedSize taken up?
ASSERT(PacketLen > NumBytesRead);
PacketLen -= NumBytesRead;
if (UncompressedSize > 0)
{
// Decompress the data:
m_Extractor.ReadFrom(a_Buffer, PacketLen);
a_Buffer.CommitRead();
const auto UncompressedData = m_Extractor.Extract(UncompressedSize);
const auto Uncompressed = UncompressedData.GetView();
cByteBuffer bb(Uncompressed.size());
// Compression was used, move the uncompressed data:
VERIFY(bb.Write(Uncompressed.data(), Uncompressed.size()));
HandlePacket(bb);
continue;
}
}
// Move the packet payload to a separate cByteBuffer, bb:
cByteBuffer bb(PacketLen);
// No compression was used, move directly:
VERIFY(a_Buffer.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
a_Buffer.CommitRead();
HandlePacket(bb);
} // for (ever)
// Log any leftover bytes into the logfile:
if (g_ShouldLogCommIn && (a_Buffer.GetReadableSpace() > 0) && m_CommLogFile.IsOpen())
{
ContiguousByteBuffer AllData;
size_t OldReadableSpace = a_Buffer.GetReadableSpace();
a_Buffer.ReadAll(AllData);
a_Buffer.ResetRead();
a_Buffer.SkipRead(a_Buffer.GetReadableSpace() - OldReadableSpace);
ASSERT(a_Buffer.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
m_CommLogFile.Printf("There are %zu (0x%zx) bytes of non-parse-able data left in the buffer:\n%s",
a_Buffer.GetReadableSpace(), a_Buffer.GetReadableSpace(), Hex.c_str()
);
m_CommLogFile.Flush();
}
}
void cProtocol_1_8_0::HandlePacket(cByteBuffer & a_Buffer)
{
UInt32 PacketType;