TESTING: protocol version 2
This commit is contained in:
@@ -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 <aesKey Encrypted with Server Public 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 <Assigned SessionID>
|
||||
```
|
||||
@@ -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.
|
||||
|
||||
@@ -17,7 +17,10 @@ namespace ColumnLynx {
|
||||
bool insecureMode;
|
||||
std::string configPath;
|
||||
std::shared_ptr<Net::VirtualInterface> 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<Utils::LibSodiumWrapper> sodium, SymmetricKey& k, bool insecure,
|
||||
std::string& config, std::shared_ptr<Net::VirtualInterface> tun, uint64_t session)
|
||||
: sodiumWrapper(sodium), aesKey(k), insecureMode(insecure), configPath(config), virtualInterface(tun), sessionID(session) {}
|
||||
std::string& config, std::shared_ptr<Net::VirtualInterface> 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<Net::VirtualInterface>& 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<Utils::LibSodiumWrapper> sodiumWrapper);
|
||||
@@ -62,7 +79,21 @@ namespace ColumnLynx {
|
||||
void setInsecureMode(bool insecureMode);
|
||||
void setConfigPath(const std::string& configPath);
|
||||
void setVirtualInterface(std::shared_ptr<Net::VirtualInterface> 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;
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace ColumnLynx::Net::TCP {
|
||||
std::string mHost, mPort;
|
||||
uint8_t mServerPublicKey[32]; // Assuming 256-bit public key
|
||||
std::array<uint8_t, 32> mSubmittedChallenge{};
|
||||
uint64_t mConnectionSessionID;
|
||||
uint32_t mConnectionSessionID;
|
||||
SymmetricKey mConnectionAESKey;
|
||||
asio::steady_timer mHeartbeatTimer;
|
||||
std::chrono::steady_clock::time_point mLastHeartbeatReceived;
|
||||
|
||||
@@ -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<SessionState> state);
|
||||
void put(uint32_t sessionID, std::shared_ptr<SessionState> state);
|
||||
|
||||
// Lookup a session entry by session ID
|
||||
std::shared_ptr<const SessionState> get(uint64_t sessionID) const;
|
||||
std::shared_ptr<const SessionState> get(uint32_t sessionID) const;
|
||||
|
||||
// Lookup a session entry by IPv4
|
||||
std::shared_ptr<const SessionState> getByIP(uint32_t ip) const;
|
||||
|
||||
// Get a snapshot of the Session Registry
|
||||
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snapshot() const;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> 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<uint64_t, std::shared_ptr<SessionState>> mSessions;
|
||||
std::unordered_map<uint64_t, uint32_t> mSessionIPs;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> mSessions;
|
||||
std::unordered_map<uint32_t, uint32_t> mSessionIPs;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> mIPSessions;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -65,27 +65,6 @@ namespace ColumnLynx::Utils {
|
||||
return std::string(reinterpret_cast<const char*>(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 <typename T>
|
||||
T cbswap128(const T& x) {
|
||||
static_assert(sizeof(T) == 16, "cbswap128 requires a 128-bit type");
|
||||
|
||||
@@ -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<uint8_t, 32> getAESKey() const;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace ColumnLynx::Net::TCP {
|
||||
std::shared_ptr<MessageHandler> mHandler;
|
||||
std::function<void(std::shared_ptr<TCPConnection>)> mOnDisconnect;
|
||||
std::array<uint8_t, 32> mConnectionAESKey;
|
||||
uint64_t mConnectionSessionID;
|
||||
uint32_t mConnectionSessionID;
|
||||
AsymPublicKey mConnectionPublicKey;
|
||||
asio::steady_timer mHeartbeatTimer;
|
||||
std::chrono::steady_clock::time_point mLastHeartbeatReceived;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<VirtualInterface> tun = std::make_shared<VirtualInterface>(optionsObj["interface"].as<std::string>());
|
||||
log("Using virtual interface: " + tun->getName());
|
||||
@@ -116,7 +119,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
std::array<uint8_t, 32> aesKey = std::array<uint8_t, 32>();
|
||||
aesKey.fill(0); // Defualt zeroed state until modified by handshake
|
||||
uint64_t sessionID = 0;
|
||||
uint32_t sessionID = 0;
|
||||
initialState.aesKey = aesKey;
|
||||
initialState.sessionID = sessionID;
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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<uint8_t> packet;
|
||||
packet.reserve(sizeof(UDPPacketHeader) + sizeof(uint64_t) + encryptedPayload.size());
|
||||
packet.reserve(sizeof(UDPPacketHeader) + encryptedPayload.size());
|
||||
packet.insert(packet.end(),
|
||||
reinterpret_cast<uint8_t*>(&hdr),
|
||||
reinterpret_cast<uint8_t*>(&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() {
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include <columnlynx/common/net/session_registry.hpp>
|
||||
|
||||
namespace ColumnLynx::Net {
|
||||
void SessionRegistry::put(uint64_t sessionID, std::shared_ptr<SessionState> state) {
|
||||
void SessionRegistry::put(uint32_t sessionID, std::shared_ptr<SessionState> state) {
|
||||
std::unique_lock lock(mMutex);
|
||||
mSessions[sessionID] = std::move(state);
|
||||
mIPSessions[mSessions[sessionID]->clientTunIP] = mSessions[sessionID];
|
||||
}
|
||||
|
||||
std::shared_ptr<const SessionState> SessionRegistry::get(uint64_t sessionID) const {
|
||||
std::shared_ptr<const SessionState> 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<uint64_t, std::shared_ptr<SessionState>> SessionRegistry::snapshot() const {
|
||||
std::unordered_map<uint64_t, std::shared_ptr<SessionState>> snap;
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> SessionRegistry::snapshot() const {
|
||||
std::unordered_map<uint32_t, std::shared_ptr<SessionState>> 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);
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace ColumnLynx::Utils {
|
||||
}
|
||||
|
||||
unsigned char protocolVersion() {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::string bytesToHexString(const uint8_t* bytes, size_t length) {
|
||||
|
||||
@@ -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<uint8_t> 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<uint8_t> 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<uint8_t> 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<SessionState>(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);
|
||||
|
||||
|
||||
@@ -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<UDPPacketHeader*>(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<uint8_t> 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<const char*>(&sessionID), sizeof(uint64_t))
|
||||
//std::string(reinterpret_cast<const char*>(&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<const SessionState> 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<SessionState*>(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<const uint8_t*>(data.data()), data.size(),
|
||||
session->aesKey, hdr.nonce, "udp-data"
|
||||
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint64_t))
|
||||
//std::string(reinterpret_cast<const char*>(&sessionID), sizeof(uint32_t))
|
||||
);
|
||||
|
||||
std::vector<uint8_t> 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<uint8_t*>(&hdr),
|
||||
reinterpret_cast<uint8_t*>(&hdr) + sizeof(UDPPacketHeader)
|
||||
);
|
||||
uint32_t sessionIDNet = htonl(sessionID);
|
||||
packet.insert(packet.end(),
|
||||
reinterpret_cast<const uint8_t*>(&sessionID),
|
||||
reinterpret_cast<const uint8_t*>(&sessionID) + sizeof(sessionID)
|
||||
reinterpret_cast<const uint8_t*>(&sessionIDNet),
|
||||
reinterpret_cast<const uint8_t*>(&sessionIDNet) + sizeof(sessionIDNet)
|
||||
);
|
||||
packet.insert(packet.end(), encryptedPayload.begin(), encryptedPayload.end());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user