diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index ac28a63073c..5cf1905c2e8 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -469,14 +469,13 @@ void ConditionAttributes::addCondition(std::shared_ptr creature, const endCondition(creature); // Apply the new one - memcpy(skills, conditionAttrs->skills, sizeof(skills)); - memcpy(skillsPercent, conditionAttrs->skillsPercent, sizeof(skillsPercent)); - memcpy(stats, conditionAttrs->stats, sizeof(stats)); - memcpy(statsPercent, conditionAttrs->statsPercent, sizeof(statsPercent)); - memcpy(buffs, conditionAttrs->buffs, sizeof(buffs)); - memcpy(buffsPercent, conditionAttrs->buffsPercent, sizeof(buffsPercent)); - - // Using std::array can only increment to the new instead of use memcpy + std::ranges::copy(std::span(conditionAttrs->skills), skills); + std::ranges::copy(std::span(conditionAttrs->skillsPercent), skillsPercent); + std::ranges::copy(std::span(conditionAttrs->stats), stats); + std::ranges::copy(std::span(conditionAttrs->statsPercent), statsPercent); + std::ranges::copy(std::span(conditionAttrs->buffs), buffs); + std::ranges::copy(std::span(conditionAttrs->buffsPercent), buffsPercent); + absorbs = conditionAttrs->absorbs; absorbsPercent = conditionAttrs->absorbsPercent; increases = conditionAttrs->increases; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index c03f00a868a..f007e82499b 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -514,7 +514,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s if (oldPos.y > newPos.y) { // north // shift y south for (int32_t y = mapWalkHeight - 1; --y >= 0;) { - memcpy(localMapCache[y + 1], localMapCache[y], sizeof(localMapCache[y])); + std::ranges::copy(std::span(localMapCache[y]), localMapCache[y + 1]); } // update 0 @@ -525,7 +525,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s } else if (oldPos.y < newPos.y) { // south // shift y north for (int32_t y = 0; y <= mapWalkHeight - 2; ++y) { - memcpy(localMapCache[y], localMapCache[y + 1], sizeof(localMapCache[y])); + std::ranges::copy(std::span(localMapCache[y + 1]), localMapCache[y]); } // update mapWalkHeight - 1 diff --git a/src/security/rsa.cpp b/src/security/rsa.cpp index 220ba94a43d..536ebdc02d3 100644 --- a/src/security/rsa.cpp +++ b/src/security/rsa.cpp @@ -95,8 +95,9 @@ void RSA::decrypt(char* msg) const { // m = c^d mod n mpz_powm(m, c, d, n); - size_t count = (mpz_sizeinbase(m, 2) + 7) / 8; - memset(msg, 0, 128 - count); + const size_t count = (mpz_sizeinbase(m, 2) + 7) / 8; + std::fill(msg, msg + (128 - count), 0); + mpz_export(msg + (128 - count), nullptr, 1, 1, 0, 0, m); mpz_clear(c); @@ -159,27 +160,27 @@ enum { }; uint16_t RSA::decodeLength(char*&pos) const { - uint8_t buffer[4] = { 0 }; - auto length = static_cast(static_cast(*pos++)); + std::array buffer = { 0 }; + uint16_t length = static_cast(*pos++); if (length & 0x80) { - length &= 0x7F; - if (length > 4) { + uint8_t numLengthBytes = length & 0x7F; + if (numLengthBytes > 4) { g_logger().error("[RSA::loadPEM] - Invalid 'length'"); return 0; } - switch (length) { - case 4: - buffer[3] = static_cast(*pos++); - case 3: - buffer[2] = static_cast(*pos++); - case 2: - buffer[1] = static_cast(*pos++); - case 1: - buffer[0] = static_cast(*pos++); - default: - break; + // Copy 'numLengthBytes' bytes from 'pos' into 'buffer', starting at the correct position + std::ranges::copy_n(pos, numLengthBytes, buffer.begin() + (4 - numLengthBytes)); + pos += numLengthBytes; + // Reconstruct 'length' from 'buffer' (big-endian) + uint32_t tempLength = 0; + for (size_t i = 0; i < numLengthBytes; ++i) { + tempLength = (tempLength << 8) | buffer[4 - numLengthBytes + i]; + } + if (tempLength > UINT16_MAX) { + g_logger().error("[RSA::loadPEM] - Length too large"); + return 0; } - std::memcpy(&length, buffer, sizeof(length)); + length = static_cast(tempLength); } return length; } diff --git a/src/server/network/protocol/protocol.cpp b/src/server/network/protocol/protocol.cpp index ca39107fe55..72d6e8f3195 100644 --- a/src/server/network/protocol/protocol.cpp +++ b/src/server/network/protocol/protocol.cpp @@ -125,69 +125,89 @@ void Protocol::disconnect() const { } } -void Protocol::XTEA_encrypt(OutputMessage &outputMessage) const { - const uint32_t delta = 0x61C88647; - - // The message must be a multiple of 8 - size_t paddingBytes = outputMessage.getLength() & 7; - if (paddingBytes != 0) { - outputMessage.addPaddingBytes(8 - paddingBytes); +void Protocol::XTEA_transform(uint8_t* buffer, size_t messageLength, bool encrypt) const { + constexpr uint32_t delta = 0x61C88647; + size_t readPos = 0; + const std::array newKey = key; + + std::array, 32> precachedControlSum; + uint32_t sum = encrypt ? 0 : 0xC6EF3720; + + // Precompute control sums + if (encrypt) { + for (size_t i = 0; i < 32; ++i) { + precachedControlSum[i][0] = sum + newKey[sum & 3]; + sum -= delta; + precachedControlSum[i][1] = sum + newKey[(sum >> 11) & 3]; + } + } else { + for (size_t i = 0; i < 32; ++i) { + precachedControlSum[i][0] = sum + newKey[(sum >> 11) & 3]; + sum += delta; + precachedControlSum[i][1] = sum + newKey[sum & 3]; + } } - uint8_t* buffer = outputMessage.getOutputBuffer(); - auto messageLength = static_cast(outputMessage.getLength()); - int32_t readPos = 0; - const std::array newKey = { key[0], key[1], key[2], key[3] }; - // TODO: refactor this for not use c-style - uint32_t precachedControlSum[32][2]; - uint32_t sum = 0; - for (int32_t i = 0; i < 32; ++i) { - precachedControlSum[i][0] = (sum + newKey[sum & 3]); - sum -= delta; - precachedControlSum[i][1] = (sum + newKey[(sum >> 11) & 3]); - } while (readPos < messageLength) { - std::array vData = {}; - memcpy(vData.data(), buffer + readPos, 8); - for (int32_t i = 0; i < 32; ++i) { - vData[0] += ((vData[1] << 4 ^ vData[1] >> 5) + vData[1]) ^ precachedControlSum[i][0]; - vData[1] += ((vData[0] << 4 ^ vData[0] >> 5) + vData[0]) ^ precachedControlSum[i][1]; + std::array tempBuffer; + std::ranges::copy_n(buffer + readPos, 8, tempBuffer.begin()); + + // Convert bytes to uint32_t considering little-endian order + std::array bytes0; + std::array bytes1; + std::copy_n(tempBuffer.begin(), 4, bytes0.begin()); + std::copy_n(tempBuffer.begin() + 4, 4, bytes1.begin()); + + uint32_t vData0 = std::bit_cast(bytes0); + uint32_t vData1 = std::bit_cast(bytes1); + + if (encrypt) { + for (size_t i = 0; i < 32; ++i) { + vData0 += ((vData1 << 4 ^ vData1 >> 5) + vData1) ^ precachedControlSum[i][0]; + vData1 += ((vData0 << 4 ^ vData0 >> 5) + vData0) ^ precachedControlSum[i][1]; + } + } else { + for (size_t i = 0; i < 32; ++i) { + vData1 -= ((vData0 << 4 ^ vData0 >> 5) + vData0) ^ precachedControlSum[i][0]; + vData0 -= ((vData1 << 4 ^ vData1 >> 5) + vData1) ^ precachedControlSum[i][1]; + } } - memcpy(buffer + readPos, vData.data(), 8); + + // Convert vData back to bytes + bytes0 = std::bit_cast>(vData0); + bytes1 = std::bit_cast>(vData1); + + // Copy transformed bytes back to buffer + std::copy_n(bytes0.begin(), 4, buffer + readPos); + std::copy_n(bytes1.begin(), 4, buffer + readPos + 4); + readPos += 8; } } +void Protocol::XTEA_encrypt(OutputMessage &outputMessage) const { + // Ensure the message length is a multiple of 8 + size_t paddingBytes = outputMessage.getLength() % 8; + if (paddingBytes != 0) { + outputMessage.addPaddingBytes(8 - paddingBytes); + } + + uint8_t* buffer = outputMessage.getOutputBuffer(); + size_t messageLength = outputMessage.getLength(); + + XTEA_transform(buffer, messageLength, true); +} + bool Protocol::XTEA_decrypt(NetworkMessage &msg) const { uint16_t msgLength = msg.getLength() - (checksumMethod == CHECKSUM_METHOD_NONE ? 2 : 6); - if ((msgLength & 7) != 0) { + if ((msgLength % 8) != 0) { return false; } - const uint32_t delta = 0x61C88647; - uint8_t* buffer = msg.getBuffer() + msg.getBufferPosition(); - auto messageLength = static_cast(msgLength); - int32_t readPos = 0; - const std::array newKey = { key[0], key[1], key[2], key[3] }; - // TODO: refactor this for not use c-style - uint32_t precachedControlSum[32][2]; - uint32_t sum = 0xC6EF3720; - for (int32_t i = 0; i < 32; ++i) { - precachedControlSum[i][0] = (sum + newKey[(sum >> 11) & 3]); - sum += delta; - precachedControlSum[i][1] = (sum + newKey[sum & 3]); - } - while (readPos < messageLength) { - std::array vData = {}; - memcpy(vData.data(), buffer + readPos, 8); - for (int32_t i = 0; i < 32; ++i) { - vData[1] -= ((vData[0] << 4 ^ vData[0] >> 5) + vData[0]) ^ precachedControlSum[i][0]; - vData[0] -= ((vData[1] << 4 ^ vData[1] >> 5) + vData[1]) ^ precachedControlSum[i][1]; - } - memcpy(buffer + readPos, vData.data(), 8); - readPos += 8; - } + size_t messageLength = msgLength; + + XTEA_transform(buffer, messageLength, false); uint16_t innerLength = msg.get(); if (std::cmp_greater(innerLength, msgLength - 2)) { diff --git a/src/server/network/protocol/protocol.hpp b/src/server/network/protocol/protocol.hpp index 033e2069ff5..86dc533ea35 100644 --- a/src/server/network/protocol/protocol.hpp +++ b/src/server/network/protocol/protocol.hpp @@ -59,7 +59,7 @@ class Protocol : public std::enable_shared_from_this { encryptionEnabled = true; } void setXTEAKey(const uint32_t* newKey) { - memcpy(this->key.data(), newKey, sizeof(*newKey) * 4); + std::ranges::copy(newKey, newKey + 4, this->key.begin()); } void setChecksumMethod(ChecksumMethods_t method) { checksumMethod = method; @@ -85,6 +85,7 @@ class Protocol : public std::enable_shared_from_this { std::array buffer {}; }; + void XTEA_transform(uint8_t* buffer, size_t messageLength, bool encrypt) const; void XTEA_encrypt(OutputMessage &msg) const; bool XTEA_decrypt(NetworkMessage &msg) const; bool compression(OutputMessage &msg) const;