From 14298453b3ba0e5e5e354d648984a90c9c824dbc Mon Sep 17 00:00:00 2001 From: DcruBro Date: Tue, 10 Feb 2026 13:27:15 +0100 Subject: [PATCH] TESTING: protocol version 2 --- README.md | 8 ++-- include/columnlynx/client/client_session.hpp | 41 ++++++++++++++++--- .../columnlynx/client/net/tcp/tcp_client.hpp | 2 +- .../common/net/session_registry.hpp | 26 +++++++----- include/columnlynx/common/utils.hpp | 21 ---------- .../server/net/tcp/tcp_connection.hpp | 4 +- .../columnlynx/server/net/udp/udp_server.hpp | 2 +- src/client/client_session.cpp | 4 +- src/client/main.cpp | 5 ++- src/client/net/tcp/tcp_client.cpp | 2 +- src/client/net/udp/udp_client.cpp | 11 ++++- src/common/session_registry.cpp | 14 +++---- src/common/utils.cpp | 2 +- src/server/net/tcp/tcp_connection.cpp | 11 ++--- src/server/net/udp/udp_server.cpp | 31 ++++++++------ 15 files changed, 110 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 834d5ab..d3ad9d7 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,8 @@ ColumnLynx makes use of both **TCP** and **UDP**. **TCP** is used for the initia It operates on port **48042** for both TCP and UDP. +Current protocol version is **2**. + Generally, all transmission is done in **little-endian byte order**, since pretty much every single modern architecture uses it by default. The only exemption to this is the **transmission of IP addresses** (for the **Virtual Interface**), which is **big-endian**. ### Handshake Procedure @@ -231,7 +233,7 @@ The Client now generates a random aesKey (32 bytes long) C: HANDSHAKE_EXCHANGE_KEY -The Server now assigns a local 8 byte session ID in the Session Registry. +The Server now assigns a local 4 byte session ID in the Session Registry. S: HANDSHAKE_EXCHANGE_KEY_CONFIRM ``` @@ -242,7 +244,7 @@ The **Client** and **Server** have now securely exchanged a symmetric **AES Key* Packet exchange and the general data tunneling is done via **Standard UDP** (*see the **UDP Packet** in **Data***). -The **header** of the sent packet always includes a **random 12 byte nonce** used to obscure the **encrypted payload / data** and the **Session ID** assigned by the server to the client (8 bytes). This makes the header **20 bytes long**. +The **header** of the sent packet always includes a **12 byte nonce** derived from a random **4 byte base nonce** and the **send count** to ensure a unique nonce, used to obscure the **encrypted payload / data** and the **Session ID** assigned by the server to the client (4 bytes). This makes the header **16 bytes long**. The **payload / data** of the sent packet is **always encrypted** using the exchanged **AES Key** and obscured using the **random nonce**. @@ -298,7 +300,7 @@ The **Data** is generally just the **raw underlying packet** forwarded to the se | Type | Length | Name | Description | |:-----|:-------|:-----|:------------| | uint8_t | 12 bytes | **Header** - Nonce | Random nonce to obfuscate encrypted contents | -| uint64_t | 8 bytes | **Header** - Session ID | The unique and random session identifier for the client | +| uint32_t | 4 bytes | **Header** - Session ID | The unique and random session identifier for the client | | uint8_t | variable | Data | General data / payload | ## Misc. diff --git a/include/columnlynx/client/client_session.hpp b/include/columnlynx/client/client_session.hpp index a456ed1..1cb3188 100644 --- a/include/columnlynx/client/client_session.hpp +++ b/include/columnlynx/client/client_session.hpp @@ -17,7 +17,10 @@ namespace ColumnLynx { bool insecureMode; std::string configPath; std::shared_ptr virtualInterface; - uint64_t sessionID; + uint32_t sessionID; + uint64_t recv_cnt; + uint64_t send_cnt; + uint32_t noncePrefix; ~ClientState() { sodium_memzero(aesKey.data(), aesKey.size()); } ClientState(const ClientState&) = delete; @@ -28,8 +31,8 @@ namespace ColumnLynx { explicit ClientState() = default; explicit ClientState(std::shared_ptr sodium, SymmetricKey& k, bool insecure, - std::string& config, std::shared_ptr tun, uint64_t session) - : sodiumWrapper(sodium), aesKey(k), insecureMode(insecure), configPath(config), virtualInterface(tun), sessionID(session) {} + std::string& config, std::shared_ptr tun, uint32_t session, uint64_t recv, uint64_t send) + : sodiumWrapper(sodium), aesKey(k), insecureMode(insecure), configPath(config), virtualInterface(tun), sessionID(session), recv_cnt(recv), send_cnt(send) {} }; class ClientSession { @@ -54,7 +57,21 @@ namespace ColumnLynx { // Get the virtual interface const std::shared_ptr& getVirtualInterface() const; // Get the session ID - uint64_t getSessionID() const; + uint32_t getSessionID() const; + uint64_t getRecvCount() const { + std::shared_lock lock(mMutex); + return mClientState->recv_cnt; + } + + uint64_t getSendCount() const { + std::shared_lock lock(mMutex); + return mClientState->send_cnt; + } + + uint32_t getNoncePrefix() const { + std::shared_lock lock(mMutex); + return mClientState->noncePrefix; + } // Setters void setSodiumWrapper(std::shared_ptr sodiumWrapper); @@ -62,7 +79,21 @@ namespace ColumnLynx { void setInsecureMode(bool insecureMode); void setConfigPath(const std::string& configPath); void setVirtualInterface(std::shared_ptr virtualInterface); - void setSessionID(uint64_t sessionID); + void setSessionID(uint32_t sessionID); + void incrementRecvCount() { + std::unique_lock lock(mMutex); + mClientState->recv_cnt++; + } + + void incrementSendCount() { + std::unique_lock lock(mMutex); + mClientState->send_cnt++; + } + + void setNoncePrefix(uint32_t prefix) { + std::unique_lock lock(mMutex); + mClientState->noncePrefix = prefix; + } private: mutable std::shared_mutex mMutex; diff --git a/include/columnlynx/client/net/tcp/tcp_client.hpp b/include/columnlynx/client/net/tcp/tcp_client.hpp index b9f011d..2faf3db 100644 --- a/include/columnlynx/client/net/tcp/tcp_client.hpp +++ b/include/columnlynx/client/net/tcp/tcp_client.hpp @@ -97,7 +97,7 @@ namespace ColumnLynx::Net::TCP { std::string mHost, mPort; uint8_t mServerPublicKey[32]; // Assuming 256-bit public key std::array mSubmittedChallenge{}; - uint64_t mConnectionSessionID; + uint32_t mConnectionSessionID; SymmetricKey mConnectionAESKey; asio::steady_timer mHeartbeatTimer; std::chrono::steady_clock::time_point mLastHeartbeatReceived; diff --git a/include/columnlynx/common/net/session_registry.hpp b/include/columnlynx/common/net/session_registry.hpp index d686aae..cc764cc 100644 --- a/include/columnlynx/common/net/session_registry.hpp +++ b/include/columnlynx/common/net/session_registry.hpp @@ -27,8 +27,9 @@ namespace ColumnLynx::Net { std::chrono::steady_clock::time_point expires{}; // Time of expiry uint32_t clientTunIP; // Assigned IP uint32_t serverTunIP; // Server IP - uint64_t sessionID; // Session ID + uint32_t sessionID; // Session ID Nonce base_nonce{}; + uint32_t noncePrefix; ~SessionState() { sodium_memzero(aesKey.data(), aesKey.size()); } SessionState(const SessionState&) = delete; @@ -36,7 +37,7 @@ namespace ColumnLynx::Net { SessionState(SessionState&&) = default; SessionState& operator=(SessionState&&) = default; - explicit SessionState(const SymmetricKey& k, std::chrono::seconds ttl = std::chrono::hours(24), uint32_t clientIP = 0, uint32_t serverIP = 0, uint64_t id = 0) : aesKey(k), clientTunIP(clientIP), serverTunIP(serverIP), sessionID(id) { + explicit SessionState(const SymmetricKey& k, std::chrono::seconds ttl = std::chrono::hours(24), uint32_t clientIP = 0, uint32_t serverIP = 0, uint32_t id = 0) : aesKey(k), clientTunIP(clientIP), serverTunIP(serverIP), sessionID(id) { expires = created + ttl; } @@ -44,6 +45,11 @@ namespace ColumnLynx::Net { void setUDPEndpoint(const asio::ip::udp::endpoint& ep) { udpEndpoint = ep; } + + void setBaseNonce() { + Utils::debug("Generating random base nonce for session " + std::to_string(sessionID)); + randombytes_buf(base_nonce.data(), base_nonce.size()); + } }; class SessionRegistry { @@ -52,19 +58,19 @@ namespace ColumnLynx::Net { static SessionRegistry& getInstance() { static SessionRegistry instance; return instance; } // Insert or replace a session entry - void put(uint64_t sessionID, std::shared_ptr state); + void put(uint32_t sessionID, std::shared_ptr state); // Lookup a session entry by session ID - std::shared_ptr get(uint64_t sessionID) const; + std::shared_ptr get(uint32_t sessionID) const; // Lookup a session entry by IPv4 std::shared_ptr getByIP(uint32_t ip) const; // Get a snapshot of the Session Registry - std::unordered_map> snapshot() const; + std::unordered_map> snapshot() const; // Remove a session by ID - void erase(uint64_t sessionID); + void erase(uint32_t sessionID); // Cleanup expired sessions void cleanupExpired(); @@ -78,15 +84,15 @@ namespace ColumnLynx::Net { uint32_t getFirstAvailableIP(uint32_t baseIP, uint8_t mask) const; // Lock IP to session ID; Do NOT call before put() - You will segfault! - void lockIP(uint64_t sessionID, uint32_t ip); + void lockIP(uint32_t sessionID, uint32_t ip); // Unlock IP from session ID - void deallocIP(uint64_t sessionID); + void deallocIP(uint32_t sessionID); private: mutable std::shared_mutex mMutex; - std::unordered_map> mSessions; - std::unordered_map mSessionIPs; + std::unordered_map> mSessions; + std::unordered_map mSessionIPs; std::unordered_map> mIPSessions; }; } diff --git a/include/columnlynx/common/utils.hpp b/include/columnlynx/common/utils.hpp index 9702f09..51d6f69 100644 --- a/include/columnlynx/common/utils.hpp +++ b/include/columnlynx/common/utils.hpp @@ -65,27 +65,6 @@ namespace ColumnLynx::Utils { return std::string(reinterpret_cast(data), length); } - inline constexpr uint64_t cbswap64(uint64_t x) { - return ((x & 0x00000000000000FFULL) << 56) | - ((x & 0x000000000000FF00ULL) << 40) | - ((x & 0x0000000000FF0000ULL) << 24) | - ((x & 0x00000000FF000000ULL) << 8) | - ((x & 0x000000FF00000000ULL) >> 8) | - ((x & 0x0000FF0000000000ULL) >> 24) | - ((x & 0x00FF000000000000ULL) >> 40) | - ((x & 0xFF00000000000000ULL) >> 56); - } - - // host -> big-endian (for little-endian hosts) - 64 bit - inline constexpr uint64_t chtobe64(uint64_t x) { - return cbswap64(x); - } - - // big-endian -> host (for little-endian hosts) - 64 bit - inline constexpr uint64_t cbe64toh(uint64_t x) { - return cbswap64(x); - } - template T cbswap128(const T& x) { static_assert(sizeof(T) == 16, "cbswap128 requires a 128-bit type"); diff --git a/include/columnlynx/server/net/tcp/tcp_connection.hpp b/include/columnlynx/server/net/tcp/tcp_connection.hpp index 040a2a2..0afdcdf 100644 --- a/include/columnlynx/server/net/tcp/tcp_connection.hpp +++ b/include/columnlynx/server/net/tcp/tcp_connection.hpp @@ -44,7 +44,7 @@ namespace ColumnLynx::Net::TCP { void disconnect(bool echo = true); // Get the assigned session ID - uint64_t getSessionID() const; + uint32_t getSessionID() const; // Get the assigned AES key; You should probably access this via the Session Registry instead std::array getAESKey() const; @@ -65,7 +65,7 @@ namespace ColumnLynx::Net::TCP { std::shared_ptr mHandler; std::function)> mOnDisconnect; std::array mConnectionAESKey; - uint64_t mConnectionSessionID; + uint32_t mConnectionSessionID; AsymPublicKey mConnectionPublicKey; asio::steady_timer mHeartbeatTimer; std::chrono::steady_clock::time_point mLastHeartbeatReceived; diff --git a/include/columnlynx/server/net/udp/udp_server.hpp b/include/columnlynx/server/net/udp/udp_server.hpp index a46b628..73866f5 100644 --- a/include/columnlynx/server/net/udp/udp_server.hpp +++ b/include/columnlynx/server/net/udp/udp_server.hpp @@ -61,7 +61,7 @@ namespace ColumnLynx::Net::UDP { void stop(); // Send UDP data to an endpoint; Fetched via the Session Registry - void sendData(const uint64_t sessionID, const std::string& data); + void sendData(uint32_t sessionID, const std::string& data); private: // Start receiving UDP data diff --git a/src/client/client_session.cpp b/src/client/client_session.cpp index ce193bd..86f174d 100644 --- a/src/client/client_session.cpp +++ b/src/client/client_session.cpp @@ -35,7 +35,7 @@ namespace ColumnLynx { return getClientState()->virtualInterface; } - uint64_t ClientSession::getSessionID() const { + uint32_t ClientSession::getSessionID() const { return getClientState()->sessionID; } @@ -64,7 +64,7 @@ namespace ColumnLynx { mClientState->virtualInterface = virtualInterface; } - void ClientSession::setSessionID(uint64_t sessionID) { + void ClientSession::setSessionID(uint32_t sessionID) { std::unique_lock lock(mMutex); mClientState->sessionID = sessionID; } diff --git a/src/client/main.cpp b/src/client/main.cpp index 7419b35..f29724d 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -104,6 +104,9 @@ int main(int argc, char** argv) { struct ClientState initialState{}; initialState.configPath = configPath; initialState.insecureMode = insecureMode; + initialState.send_cnt = 0; + initialState.recv_cnt = 0; + randombytes_buf(&initialState.noncePrefix, sizeof(uint32_t)); // Randomize nonce prefix std::shared_ptr tun = std::make_shared(optionsObj["interface"].as()); log("Using virtual interface: " + tun->getName()); @@ -116,7 +119,7 @@ int main(int argc, char** argv) { std::array aesKey = std::array(); aesKey.fill(0); // Defualt zeroed state until modified by handshake - uint64_t sessionID = 0; + uint32_t sessionID = 0; initialState.aesKey = aesKey; initialState.sessionID = sessionID; diff --git a/src/client/net/tcp/tcp_client.cpp b/src/client/net/tcp/tcp_client.cpp index 7e04960..c5ed047 100644 --- a/src/client/net/tcp/tcp_client.cpp +++ b/src/client/net/tcp/tcp_client.cpp @@ -244,7 +244,7 @@ namespace ColumnLynx::Net::TCP { std::memcpy(&mConnectionSessionID, decrypted.data(), sizeof(mConnectionSessionID)); std::memcpy(&mTunConfig, decrypted.data() + sizeof(mConnectionSessionID), sizeof(Protocol::TunConfig)); - mConnectionSessionID = Utils::cbe64toh(mConnectionSessionID); + mConnectionSessionID = ntohl(mConnectionSessionID); Utils::log("Connection established with Session ID: " + std::to_string(mConnectionSessionID)); diff --git a/src/client/net/udp/udp_client.cpp b/src/client/net/udp/udp_client.cpp index e5e6702..b284a23 100644 --- a/src/client/net/udp/udp_client.cpp +++ b/src/client/net/udp/udp_client.cpp @@ -46,7 +46,12 @@ namespace ColumnLynx::Net::UDP { void UDPClient::sendMessage(const std::string& data) { UDPPacketHeader hdr{}; - randombytes_buf(hdr.nonce.data(), hdr.nonce.size()); + uint8_t nonce[12]; + uint32_t prefix = ClientSession::getInstance().getNoncePrefix(); + uint64_t sendCount = ClientSession::getInstance().getSendCount(); + memcpy(nonce, &prefix, sizeof(uint32_t)); // Prefix nonce with client-specific random value + memcpy(nonce + sizeof(uint32_t), &sendCount, sizeof(uint64_t)); // Use send count as nonce suffix to ensure uniqueness + std::copy_n(nonce, 12, hdr.nonce.data()); if (ClientSession::getInstance().getAESKey().empty() || ClientSession::getInstance().getSessionID() == 0) { Utils::error("UDP Client AES key or Session ID reference is null!"); @@ -62,7 +67,7 @@ namespace ColumnLynx::Net::UDP { ); std::vector packet; - packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint64_t) + encryptedPayload.size()); + packet.reserve(sizeof(UDPPacketHeader) + encryptedPayload.size()); packet.insert(packet.end(), reinterpret_cast(&hdr), reinterpret_cast(&hdr) + sizeof(UDPPacketHeader) @@ -76,6 +81,8 @@ namespace ColumnLynx::Net::UDP { mSocket.send_to(asio::buffer(packet), mRemoteEndpoint); Utils::debug("Sent UDP packet of size " + std::to_string(packet.size())); + + ClientSession::getInstance().incrementSendCount(); } void UDPClient::stop() { diff --git a/src/common/session_registry.cpp b/src/common/session_registry.cpp index 1a4bf12..491264d 100644 --- a/src/common/session_registry.cpp +++ b/src/common/session_registry.cpp @@ -5,13 +5,13 @@ #include namespace ColumnLynx::Net { - void SessionRegistry::put(uint64_t sessionID, std::shared_ptr state) { + void SessionRegistry::put(uint32_t sessionID, std::shared_ptr state) { std::unique_lock lock(mMutex); mSessions[sessionID] = std::move(state); mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID]; } - std::shared_ptr SessionRegistry::get(uint64_t sessionID) const { + std::shared_ptr SessionRegistry::get(uint32_t sessionID) const { std::shared_lock lock(mMutex); auto it = mSessions.find(sessionID); return (it == mSessions.end()) ? nullptr : it->second; @@ -23,14 +23,14 @@ namespace ColumnLynx::Net { return (it == mIPSessions.end()) ? nullptr : it->second; } - std::unordered_map> SessionRegistry::snapshot() const { - std::unordered_map> snap; + std::unordered_map> SessionRegistry::snapshot() const { + std::unordered_map> snap; std::shared_lock lock(mMutex); snap = mSessions; return snap; } - void SessionRegistry::erase(uint64_t sessionID) { + void SessionRegistry::erase(uint32_t sessionID) { std::unique_lock lock(mMutex); mSessions.erase(sessionID); } @@ -77,7 +77,7 @@ namespace ColumnLynx::Net { return 0; } - void SessionRegistry::lockIP(uint64_t sessionID, uint32_t ip) { + void SessionRegistry::lockIP(uint32_t sessionID, uint32_t ip) { std::unique_lock lock(mMutex); mSessionIPs[sessionID] = ip; @@ -87,7 +87,7 @@ namespace ColumnLynx::Net { mIPSessions[ip] = mSessions.find(sessionID)->second; } - void SessionRegistry::deallocIP(uint64_t sessionID) { + void SessionRegistry::deallocIP(uint32_t sessionID) { std::unique_lock lock(mMutex); auto it = mSessionIPs.find(sessionID); diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 4cdbc97..a2429fd 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -93,7 +93,7 @@ namespace ColumnLynx::Utils { } unsigned char protocolVersion() { - return 1; + return 2; } std::string bytesToHexString(const uint8_t* bytes, size_t length) { diff --git a/src/server/net/tcp/tcp_connection.cpp b/src/server/net/tcp/tcp_connection.cpp index 4226e04..334e056 100644 --- a/src/server/net/tcp/tcp_connection.cpp +++ b/src/server/net/tcp/tcp_connection.cpp @@ -66,7 +66,7 @@ namespace ColumnLynx::Net::TCP { Utils::log("Initiated graceful disconnect (half-close) to " + mRemoteIP); } - uint64_t TCPConnection::getSessionID() const { + uint32_t TCPConnection::getSessionID() const { return mConnectionSessionID; } @@ -247,11 +247,11 @@ namespace ColumnLynx::Net::TCP { tunConfig.dns1 = htonl(0x08080808); // 8.8.8.8 tunConfig.dns2 = 0; - uint64_t sessionIDNet = Utils::chtobe64(mConnectionSessionID); + uint32_t sessionIDNet = htonl(mConnectionSessionID); - std::vector payload(sizeof(uint64_t) + sizeof(tunConfig)); - std::memcpy(payload.data(), &sessionIDNet, sizeof(uint64_t)); - std::memcpy(payload.data() + sizeof(uint64_t), &tunConfig, sizeof(tunConfig)); + std::vector payload(sizeof(uint32_t) + sizeof(tunConfig)); + std::memcpy(payload.data(), &sessionIDNet, sizeof(uint32_t)); + std::memcpy(payload.data() + sizeof(uint32_t), &tunConfig, sizeof(tunConfig)); std::vector encryptedPayload = Utils::LibSodiumWrapper::encryptMessage( payload.data(), payload.size(), @@ -263,6 +263,7 @@ namespace ColumnLynx::Net::TCP { // Add to session registry Utils::log("Handshake with " + reqAddr + " completed successfully. Session ID assigned (" + std::to_string(mConnectionSessionID) + ")."); auto session = std::make_shared(mConnectionAESKey, std::chrono::hours(12), clientIP, htonl(0x0A0A0001), mConnectionSessionID); + session->setBaseNonce(); // Set it SessionRegistry::getInstance().put(mConnectionSessionID, std::move(session)); SessionRegistry::getInstance().lockIP(mConnectionSessionID, clientIP); diff --git a/src/server/net/udp/udp_server.cpp b/src/server/net/udp/udp_server.cpp index b1b3284..85015a3 100644 --- a/src/server/net/udp/udp_server.cpp +++ b/src/server/net/udp/udp_server.cpp @@ -26,16 +26,17 @@ namespace ColumnLynx::Net::UDP { } void UDPServer::mHandlePacket(std::size_t bytes) { - if (bytes < sizeof(UDPPacketHeader)) + if (bytes < sizeof(UDPPacketHeader) + sizeof(uint32_t)) return; const auto* hdr = reinterpret_cast(mRecvBuffer.data()); - // Get plaintext session ID (assuming first 8 bytes after nonce (header)) - uint64_t sessionID = 0; - std::memcpy(&sessionID, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint64_t)); + // Get plaintext session ID (assuming first 4 bytes after nonce (header)) + uint32_t sessionIDNet = 0; + std::memcpy(&sessionIDNet, mRecvBuffer.data() + sizeof(UDPPacketHeader), sizeof(uint32_t)); + uint32_t sessionID = ntohl(sessionIDNet); - auto it = mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint64_t); + auto it = mRecvBuffer.begin() + sizeof(UDPPacketHeader) + sizeof(uint32_t); std::vector encryptedPayload(it, mRecvBuffer.begin() + bytes); // Get associated session state @@ -54,7 +55,7 @@ namespace ColumnLynx::Net::UDP { encryptedPayload.data(), encryptedPayload.size(), session->aesKey, hdr->nonce, "udp-data" - //std::string(reinterpret_cast(&sessionID), sizeof(uint64_t)) + //std::string(reinterpret_cast(&sessionID), sizeof(uint32_t)) ); Utils::debug("Passed decryption"); @@ -76,7 +77,7 @@ namespace ColumnLynx::Net::UDP { } } - void UDPServer::sendData(const uint64_t sessionID, const std::string& data) { + void UDPServer::sendData(uint32_t sessionID, const std::string& data) { // Find the IPv4/IPv6 endpoint for the session std::shared_ptr session = SessionRegistry::getInstance().get(sessionID); if (!session) { @@ -92,23 +93,29 @@ namespace ColumnLynx::Net::UDP { // Prepare packet UDPPacketHeader hdr{}; - randombytes_buf(hdr.nonce.data(), hdr.nonce.size()); + uint8_t nonce[12]; + uint32_t prefix = session->noncePrefix; + uint64_t sendCount = const_cast(session.get())->send_ctr.fetch_add(1, std::memory_order_relaxed); + memcpy(nonce, &prefix, sizeof(uint32_t)); // Prefix nonce + memcpy(nonce + sizeof(uint32_t), &sendCount, sizeof(uint64_t)); // Use send count as nonce suffix to ensure uniqueness + std::copy_n(nonce, 12, hdr.nonce.data()); auto encryptedPayload = Utils::LibSodiumWrapper::encryptMessage( reinterpret_cast(data.data()), data.size(), session->aesKey, hdr.nonce, "udp-data" - //std::string(reinterpret_cast(&sessionID), sizeof(uint64_t)) + //std::string(reinterpret_cast(&sessionID), sizeof(uint32_t)) ); std::vector packet; - packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint64_t) + encryptedPayload.size()); + packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint32_t) + encryptedPayload.size()); packet.insert(packet.end(), reinterpret_cast(&hdr), reinterpret_cast(&hdr) + sizeof(UDPPacketHeader) ); + uint32_t sessionIDNet = htonl(sessionID); packet.insert(packet.end(), - reinterpret_cast(&sessionID), - reinterpret_cast(&sessionID) + sizeof(sessionID) + reinterpret_cast(&sessionIDNet), + reinterpret_cast(&sessionIDNet) + sizeof(sessionIDNet) ); packet.insert(packet.end(), encryptedPayload.begin(), encryptedPayload.end());