From 4153da3c16d184a1e6ffa15d2c504c6e3f6b0e1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Sat, 19 Aug 2023 09:42:34 +0200 Subject: Network: move secure channel to protocol module --- include/erebos/network.h | 1 - src/CMakeLists.txt | 2 +- src/channel.cpp | 200 ----------------------------------------------- src/channel.h | 73 ----------------- src/network.cpp | 69 +++++++--------- src/network.h | 32 -------- src/network/channel.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++++ src/network/channel.h | 73 +++++++++++++++++ src/network/protocol.cpp | 7 ++ src/network/protocol.h | 35 +++++++++ 10 files changed, 344 insertions(+), 348 deletions(-) delete mode 100644 src/channel.cpp delete mode 100644 src/channel.h create mode 100644 src/network/channel.cpp create mode 100644 src/network/channel.h diff --git a/include/erebos/network.h b/include/erebos/network.h index 6a3112a..2761a40 100644 --- a/include/erebos/network.h +++ b/include/erebos/network.h @@ -99,7 +99,6 @@ public: string addressStr() const; uint16_t port() const; - bool hasChannel() const; bool send(UUID, const Ref &) const; bool send(UUID, const Object &) const; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 478fc50..fff6242 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,13 +4,13 @@ include_directories( add_library(erebos attach.cpp - channel.cpp contact.cpp frp.cpp identity.cpp merge.cpp message.cpp network.cpp + network/channel.cpp network/protocol.cpp pairing.cpp pubkey.cpp diff --git a/src/channel.cpp b/src/channel.cpp deleted file mode 100644 index b317f3d..0000000 --- a/src/channel.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "channel.h" - -#include -#include -#include - -#include - -using std::remove_const; -using std::runtime_error; - -using namespace erebos; - -Ref ChannelRequestData::store(const Storage & st) const -{ - vector items; - - for (const auto & p : peers) - items.emplace_back("peer", p); - items.emplace_back("enc", "aes-128-gcm"); - items.emplace_back("key", key); - - return st.storeObject(Record(std::move(items))); -} - -ChannelRequestData ChannelRequestData::load(const Ref & ref) -{ - if (auto rec = ref->asRecord()) { - if (rec->item("enc").asText() == "aes-128-gcm") - if (auto key = rec->item("key").as()) - return ChannelRequestData { - .peers = rec->items("peer").as>(), - .key = *key, - }; - } - - return ChannelRequestData { - .peers = {}, - .key = Stored::load(ref.storage().zref()), - }; -} - -Ref ChannelAcceptData::store(const Storage & st) const -{ - vector items; - - items.emplace_back("req", request); - items.emplace_back("enc", "aes-128-gcm"); - items.emplace_back("key", key); - - return st.storeObject(Record(std::move(items))); -} - -ChannelAcceptData ChannelAcceptData::load(const Ref & ref) -{ - if (auto rec = ref->asRecord()) - if (rec->item("enc").asText() == "aes-128-gcm") - return ChannelAcceptData { - .request = *rec->item("req").as(), - .key = *rec->item("key").as(), - }; - - return ChannelAcceptData { - .request = Stored::load(ref.storage().zref()), - .key = Stored::load(ref.storage().zref()), - }; -} - -unique_ptr ChannelAcceptData::channel() const -{ - if (auto secret = SecretKexKey::load(key)) - return make_unique( - request->data->peers, - secret->dh(*request->data->key), - false - ); - - if (auto secret = SecretKexKey::load(request->data->key)) - return make_unique( - request->data->peers, - secret->dh(*key), - true - ); - - throw runtime_error("failed to load secret DH key"); -} - - -Stored Channel::generateRequest(const Storage & st, - const Identity & self, const Identity & peer) -{ - auto signKey = SecretKey::load(self.keyMessage()); - if (!signKey) - throw runtime_error("failed to load own message key"); - - return signKey->sign(st.store(ChannelRequestData { - .peers = self.ref()->digest() < peer.ref()->digest() ? - vector>> { - Stored>::load(*self.ref()), - Stored>::load(*peer.ref()), - } : - vector>> { - Stored>::load(*peer.ref()), - Stored>::load(*self.ref()), - }, - .key = SecretKexKey::generate(st).pub(), - })); -} - -optional> Channel::acceptRequest(const Identity & self, - const Identity & peer, const Stored & request) -{ - if (!request->isSignedBy(peer.keyMessage())) - return nullopt; - - auto & peers = request->data->peers; - if (peers.size() != 2 || - std::none_of(peers.begin(), peers.end(), [&self](const auto & x) - { return x.ref().digest() == self.ref()->digest(); }) || - std::none_of(peers.begin(), peers.end(), [&peer](const auto & x) - { return x.ref().digest() == peer.ref()->digest(); })) - return nullopt; - - auto & st = request.ref().storage(); - - auto signKey = SecretKey::load(self.keyMessage()); - if (!signKey) - throw runtime_error("failed to load own message key"); - - return signKey->sign(st.store(ChannelAcceptData { - .request = request, - .key = SecretKexKey::generate(st).pub(), - })); -} - -vector Channel::encrypt(const vector & plain) -{ - vector res(plain.size() + 8 + 16 + 16); - array iv; - - uint64_t beCount = htobe64(nonceCounter++); - std::memcpy(res.data(), &beCount, 8); - std::copy_n(nonceFixedOur.begin(), 6, iv.begin()); - std::copy_n(res.begin() + 2, 6, iv.begin() + 6); - - const unique_ptr - ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), - nullptr, key.data(), iv.data()); - - int outl = 0; - uint8_t * cur = res.data() + 8; - - if (EVP_EncryptUpdate(ctx.get(), cur, &outl, plain.data(), plain.size()) != 1) - throw runtime_error("failed to encrypt data"); - cur += outl; - - if (EVP_EncryptFinal(ctx.get(), cur, &outl) != 1) - throw runtime_error("failed to encrypt data"); - cur += outl; - - EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, 16, cur); - cur += 16; - - res.resize(cur - res.data()); - return res; -} - -optional> Channel::decrypt(const vector & ctext) -{ - vector res(ctext.size()); - array iv; - - std::copy_n(nonceFixedPeer.begin(), 6, iv.begin()); - std::copy_n(ctext.begin() + 2, 6, iv.begin() + 6); - - const unique_ptr - ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); - EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), - nullptr, key.data(), iv.data()); - - int outl = 0; - uint8_t * cur = res.data(); - - if (EVP_DecryptUpdate(ctx.get(), cur, &outl, - ctext.data() + 8, ctext.size() - 8 - 16) != 1) - return nullopt; - cur += outl; - - if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, 16, - (void *) (ctext.data() + ctext.size() - 16))) - return nullopt; - - if (EVP_DecryptFinal_ex(ctx.get(), cur, &outl) != 1) - return nullopt; - cur += outl; - - res.resize(cur - res.data()); - return res; -} diff --git a/src/channel.h b/src/channel.h deleted file mode 100644 index 5f1786e..0000000 --- a/src/channel.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include - -#include "identity.h" - -#include -#include - -namespace erebos { - -using std::array; -using std::atomic; -using std::unique_ptr; - -struct ChannelRequestData -{ - Ref store(const Storage & st) const; - static ChannelRequestData load(const Ref &); - - const vector>> peers; - const Stored key; -}; - -typedef Signed ChannelRequest; - -struct ChannelAcceptData -{ - Ref store(const Storage & st) const; - static ChannelAcceptData load(const Ref &); - - unique_ptr channel() const; - - const Stored request; - const Stored key; -}; - -typedef Signed ChannelAccept; - -class Channel -{ -public: - Channel(const vector>> & peers, - vector && key, bool ourRequest): - peers(peers), - key(std::move(key)), - nonceFixedOur({ uint8_t(ourRequest ? 1 : 2), 0, 0, 0, 0, 0 }), - nonceFixedPeer({ uint8_t(ourRequest ? 2 : 1), 0, 0, 0, 0, 0 }) - {} - - Channel(const Channel &) = delete; - Channel(Channel &&) = delete; - Channel & operator=(const Channel &) = delete; - Channel & operator=(Channel &&) = delete; - - static Stored generateRequest(const Storage &, - const Identity & self, const Identity & peer); - static optional> acceptRequest(const Identity & self, - const Identity & peer, const Stored & request); - - vector encrypt(const vector &); - optional> decrypt(const vector &); - -private: - const vector>> peers; - const vector key; - - const array nonceFixedOur; - const array nonceFixedPeer; - atomic nonceCounter = 0; -}; - -} diff --git a/src/network.cpp b/src/network.cpp index 725ac50..455496c 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -207,13 +207,6 @@ void Peer::Priv::notifyWatchers() } } -bool Peer::hasChannel() const -{ - if (auto speer = p->speer.lock()) - return holds_alternative>(speer->channel); - return false; -} - bool Peer::send(UUID uuid, const Ref & ref) const { return send(uuid, ref, *ref); @@ -396,13 +389,13 @@ void Server::Priv::doListen() continue; current = &buf; - if (holds_alternative>(peer->channel)) { - if (auto dec = std::get>(peer->channel)->decrypt(buf)) { + if (holds_alternative>(peer->connection.channel())) { + if (auto dec = std::get>(peer->connection.channel())->decrypt(buf)) { decrypted = std::move(*dec); current = &decrypted; } - } else if (holds_alternative>(peer->channel)) { - if (auto dec = std::get>(peer->channel)-> + } else if (holds_alternative>(peer->connection.channel())) { + if (auto dec = std::get>(peer->connection.channel())-> data->channel()->decrypt(buf)) { decrypted = std::move(*dec); current = &decrypted; @@ -508,7 +501,6 @@ Server::Peer & Server::Priv::getPeer(const sockaddr_in6 & paddr) .connection = protocol.connect(paddr), .identity = monostate(), .identityUpdates = {}, - .channel = monostate(), .tempStorage = st, .partStorage = st.derivePartialStorage(), }); @@ -527,7 +519,6 @@ Server::Peer & Server::Priv::addPeer(NetworkProtocol::Connection conn) .connection = move(conn), .identity = monostate(), .identityUpdates = {}, - .channel = monostate(), .tempStorage = st, .partStorage = st.derivePartialStorage(), }); @@ -548,16 +539,16 @@ void Server::Priv::handlePacket(Server::Peer & peer, const NetworkProtocol::Head switch (item.type) { case NetworkProtocol::Header::Type::Acknowledged: { auto dgst = std::get(item.value); - if (holds_alternative>(peer.channel) && - std::get>(peer.channel).ref().digest() == dgst) + if (holds_alternative>(peer.connection.channel()) && + std::get>(peer.connection.channel()).ref().digest() == dgst) peer.finalizeChannel(reply, - std::get>(peer.channel)->data->channel()); + std::get>(peer.connection.channel())->data->channel()); break; } case NetworkProtocol::Header::Type::DataRequest: { auto dgst = std::get(item.value); - if (holds_alternative>(peer.channel) || + if (holds_alternative>(peer.connection.channel()) || plaintextRefs.find(dgst) != plaintextRefs.end()) { if (auto ref = peer.tempStorage.ref(dgst)) { reply.header({ NetworkProtocol::Header::Type::DataResponse, ref->digest() }); @@ -595,7 +586,6 @@ void Server::Priv::handlePacket(Server::Peer & peer, const NetworkProtocol::Head shared_ptr wref(new WaitingRef { .storage = peer.tempStorage, .ref = peer.partStorage.ref(dgst), - .peer = peer, .missing = {}, }); waiting.push_back(wref); @@ -613,7 +603,6 @@ void Server::Priv::handlePacket(Server::Peer & peer, const NetworkProtocol::Head shared_ptr wref(new WaitingRef { .storage = peer.tempStorage, .ref = peer.partStorage.ref(dgst), - .peer = peer, .missing = {}, }); waiting.push_back(wref); @@ -626,29 +615,28 @@ void Server::Priv::handlePacket(Server::Peer & peer, const NetworkProtocol::Head auto dgst = std::get(item.value); reply.header({ NetworkProtocol::Header::Type::Acknowledged, dgst }); - if (holds_alternative>(peer.channel) && - std::get>(peer.channel).ref().digest() < dgst) + if (holds_alternative>(peer.connection.channel()) && + std::get>(peer.connection.channel()).ref().digest() < dgst) break; - if (holds_alternative>(peer.channel)) + if (holds_alternative>(peer.connection.channel())) break; shared_ptr wref(new WaitingRef { .storage = peer.tempStorage, .ref = peer.partStorage.ref(dgst), - .peer = peer, .missing = {}, }); waiting.push_back(wref); - peer.channel = wref; + peer.connection.channel() = wref; wref->check(reply); break; } case NetworkProtocol::Header::Type::ChannelAccept: { auto dgst = std::get(item.value); - if (holds_alternative>(peer.channel) && - std::get>(peer.channel).ref().digest() < dgst) + if (holds_alternative>(peer.connection.channel()) && + std::get>(peer.connection.channel()).ref().digest() < dgst) break; auto cres = peer.tempStorage.copy(peer.partStorage.ref(dgst)); @@ -685,9 +673,8 @@ void Server::Priv::handlePacket(Server::Peer & peer, const NetworkProtocol::Head shared_ptr wref(new WaitingRef { .storage = peer.tempStorage, - .ref = pref, - .peer = peer, - .missing = {}, + .ref = pref, + .missing = {}, }); waiting.push_back(wref); peer.serviceQueue.emplace_back(*serviceType, wref); @@ -732,8 +719,8 @@ void Server::Peer::send(const NetworkProtocol::Header & header, const vector>(channel)) - out = std::get>(channel)->encrypt(data); + if (holds_alternative>(connection.channel())) + out = std::get>(connection.channel())->encrypt(data); else if (secure) secureOutQueue.emplace_back(move(data)); else @@ -784,10 +771,10 @@ void Server::Peer::updateChannel(ReplyBuilder & reply) if (!holds_alternative(identity)) return; - if (holds_alternative(channel)) { + if (holds_alternative(connection.channel())) { auto req = Channel::generateRequest(tempStorage, server.self, std::get(identity)); - channel.emplace>(req); + connection.channel().emplace>(req); reply.header({ NetworkProtocol::Header::Type::ChannelRequest, req.ref().digest() }); reply.body(req.ref()); reply.body(req->data.ref()); @@ -796,13 +783,13 @@ void Server::Peer::updateChannel(ReplyBuilder & reply) reply.body(sig.ref()); } - if (holds_alternative>(channel)) { - if (auto ref = std::get>(channel)->check(reply)) { + if (holds_alternative>(connection.channel())) { + if (auto ref = std::get>(connection.channel())->check(reply)) { auto req = Stored::load(*ref); if (holds_alternative(identity) && req->isSignedBy(std::get(identity).keyMessage())) { if (auto acc = Channel::acceptRequest(server.self, std::get(identity), req)) { - channel.emplace>(*acc); + connection.channel().emplace>(*acc); reply.header({ NetworkProtocol::Header::Type::ChannelAccept, acc->ref().digest() }); reply.body(acc->ref()); reply.body(acc.value()->data.ref()); @@ -810,10 +797,10 @@ void Server::Peer::updateChannel(ReplyBuilder & reply) for (const auto & sig : acc.value()->sigs) reply.body(sig.ref()); } else { - channel = monostate(); + connection.channel() = monostate(); } } else { - channel = monostate(); + connection.channel() = monostate(); } } } @@ -821,7 +808,7 @@ void Server::Peer::updateChannel(ReplyBuilder & reply) void Server::Peer::finalizeChannel(ReplyBuilder & reply, unique_ptr ch) { - channel.emplace>(move(ch)); + connection.channel().emplace>(move(ch)); vector hitems; for (const auto & r : server.self.refs()) @@ -871,11 +858,11 @@ void Server::Peer::trySendOutQueue() if (secureOutQueue.empty()) return; - if (!holds_alternative>(channel)) + if (!holds_alternative>(connection.channel())) return; for (const auto & data : secureOutQueue) { - auto out = std::get>(channel)->encrypt(data); + auto out = std::get>(connection.channel())->encrypt(data); connection.send(out); } diff --git a/src/network.h b/src/network.h index c3a2074..2959adc 100644 --- a/src/network.h +++ b/src/network.h @@ -2,7 +2,6 @@ #include -#include "channel.h" #include "network/protocol.h" #include @@ -51,12 +50,6 @@ struct Server::Peer Identity> identity; vector> identityUpdates; - variant, - shared_ptr, - Stored, - unique_ptr> channel; - Storage tempStorage; PartialStorage partStorage; @@ -91,31 +84,6 @@ struct PeerList::Priv : enable_shared_from_this void push(const shared_ptr &); }; -class ReplyBuilder -{ -public: - void header(NetworkProtocol::Header::Item &&); - void body(const Ref &); - - const vector & header() const { return mheader; } - vector body() const; - -private: - vector mheader; - vector mbody; -}; - -struct WaitingRef -{ - const Storage storage; - const PartialRef ref; - const Server::Peer & peer; - vector missing; - - optional check(); - optional check(ReplyBuilder &); -}; - struct Server::Priv { Priv(const Head & local, const Identity & self); diff --git a/src/network/channel.cpp b/src/network/channel.cpp new file mode 100644 index 0000000..b317f3d --- /dev/null +++ b/src/network/channel.cpp @@ -0,0 +1,200 @@ +#include "channel.h" + +#include +#include +#include + +#include + +using std::remove_const; +using std::runtime_error; + +using namespace erebos; + +Ref ChannelRequestData::store(const Storage & st) const +{ + vector items; + + for (const auto & p : peers) + items.emplace_back("peer", p); + items.emplace_back("enc", "aes-128-gcm"); + items.emplace_back("key", key); + + return st.storeObject(Record(std::move(items))); +} + +ChannelRequestData ChannelRequestData::load(const Ref & ref) +{ + if (auto rec = ref->asRecord()) { + if (rec->item("enc").asText() == "aes-128-gcm") + if (auto key = rec->item("key").as()) + return ChannelRequestData { + .peers = rec->items("peer").as>(), + .key = *key, + }; + } + + return ChannelRequestData { + .peers = {}, + .key = Stored::load(ref.storage().zref()), + }; +} + +Ref ChannelAcceptData::store(const Storage & st) const +{ + vector items; + + items.emplace_back("req", request); + items.emplace_back("enc", "aes-128-gcm"); + items.emplace_back("key", key); + + return st.storeObject(Record(std::move(items))); +} + +ChannelAcceptData ChannelAcceptData::load(const Ref & ref) +{ + if (auto rec = ref->asRecord()) + if (rec->item("enc").asText() == "aes-128-gcm") + return ChannelAcceptData { + .request = *rec->item("req").as(), + .key = *rec->item("key").as(), + }; + + return ChannelAcceptData { + .request = Stored::load(ref.storage().zref()), + .key = Stored::load(ref.storage().zref()), + }; +} + +unique_ptr ChannelAcceptData::channel() const +{ + if (auto secret = SecretKexKey::load(key)) + return make_unique( + request->data->peers, + secret->dh(*request->data->key), + false + ); + + if (auto secret = SecretKexKey::load(request->data->key)) + return make_unique( + request->data->peers, + secret->dh(*key), + true + ); + + throw runtime_error("failed to load secret DH key"); +} + + +Stored Channel::generateRequest(const Storage & st, + const Identity & self, const Identity & peer) +{ + auto signKey = SecretKey::load(self.keyMessage()); + if (!signKey) + throw runtime_error("failed to load own message key"); + + return signKey->sign(st.store(ChannelRequestData { + .peers = self.ref()->digest() < peer.ref()->digest() ? + vector>> { + Stored>::load(*self.ref()), + Stored>::load(*peer.ref()), + } : + vector>> { + Stored>::load(*peer.ref()), + Stored>::load(*self.ref()), + }, + .key = SecretKexKey::generate(st).pub(), + })); +} + +optional> Channel::acceptRequest(const Identity & self, + const Identity & peer, const Stored & request) +{ + if (!request->isSignedBy(peer.keyMessage())) + return nullopt; + + auto & peers = request->data->peers; + if (peers.size() != 2 || + std::none_of(peers.begin(), peers.end(), [&self](const auto & x) + { return x.ref().digest() == self.ref()->digest(); }) || + std::none_of(peers.begin(), peers.end(), [&peer](const auto & x) + { return x.ref().digest() == peer.ref()->digest(); })) + return nullopt; + + auto & st = request.ref().storage(); + + auto signKey = SecretKey::load(self.keyMessage()); + if (!signKey) + throw runtime_error("failed to load own message key"); + + return signKey->sign(st.store(ChannelAcceptData { + .request = request, + .key = SecretKexKey::generate(st).pub(), + })); +} + +vector Channel::encrypt(const vector & plain) +{ + vector res(plain.size() + 8 + 16 + 16); + array iv; + + uint64_t beCount = htobe64(nonceCounter++); + std::memcpy(res.data(), &beCount, 8); + std::copy_n(nonceFixedOur.begin(), 6, iv.begin()); + std::copy_n(res.begin() + 2, 6, iv.begin() + 6); + + const unique_ptr + ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), + nullptr, key.data(), iv.data()); + + int outl = 0; + uint8_t * cur = res.data() + 8; + + if (EVP_EncryptUpdate(ctx.get(), cur, &outl, plain.data(), plain.size()) != 1) + throw runtime_error("failed to encrypt data"); + cur += outl; + + if (EVP_EncryptFinal(ctx.get(), cur, &outl) != 1) + throw runtime_error("failed to encrypt data"); + cur += outl; + + EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, 16, cur); + cur += 16; + + res.resize(cur - res.data()); + return res; +} + +optional> Channel::decrypt(const vector & ctext) +{ + vector res(ctext.size()); + array iv; + + std::copy_n(nonceFixedPeer.begin(), 6, iv.begin()); + std::copy_n(ctext.begin() + 2, 6, iv.begin() + 6); + + const unique_ptr + ctx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free); + EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), + nullptr, key.data(), iv.data()); + + int outl = 0; + uint8_t * cur = res.data(); + + if (EVP_DecryptUpdate(ctx.get(), cur, &outl, + ctext.data() + 8, ctext.size() - 8 - 16) != 1) + return nullopt; + cur += outl; + + if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, 16, + (void *) (ctext.data() + ctext.size() - 16))) + return nullopt; + + if (EVP_DecryptFinal_ex(ctx.get(), cur, &outl) != 1) + return nullopt; + cur += outl; + + res.resize(cur - res.data()); + return res; +} diff --git a/src/network/channel.h b/src/network/channel.h new file mode 100644 index 0000000..f932c84 --- /dev/null +++ b/src/network/channel.h @@ -0,0 +1,73 @@ +#pragma once + +#include + +#include "../identity.h" + +#include +#include + +namespace erebos { + +using std::array; +using std::atomic; +using std::unique_ptr; + +struct ChannelRequestData +{ + Ref store(const Storage & st) const; + static ChannelRequestData load(const Ref &); + + const vector>> peers; + const Stored key; +}; + +typedef Signed ChannelRequest; + +struct ChannelAcceptData +{ + Ref store(const Storage & st) const; + static ChannelAcceptData load(const Ref &); + + unique_ptr channel() const; + + const Stored request; + const Stored key; +}; + +typedef Signed ChannelAccept; + +class Channel +{ +public: + Channel(const vector>> & peers, + vector && key, bool ourRequest): + peers(peers), + key(std::move(key)), + nonceFixedOur({ uint8_t(ourRequest ? 1 : 2), 0, 0, 0, 0, 0 }), + nonceFixedPeer({ uint8_t(ourRequest ? 2 : 1), 0, 0, 0, 0, 0 }) + {} + + Channel(const Channel &) = delete; + Channel(Channel &&) = delete; + Channel & operator=(const Channel &) = delete; + Channel & operator=(Channel &&) = delete; + + static Stored generateRequest(const Storage &, + const Identity & self, const Identity & peer); + static optional> acceptRequest(const Identity & self, + const Identity & peer, const Stored & request); + + vector encrypt(const vector &); + optional> decrypt(const vector &); + +private: + const vector>> peers; + const vector key; + + const array nonceFixedOur; + const array nonceFixedPeer; + atomic nonceCounter = 0; +}; + +} diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index fb3a5ea..4151bf2 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -24,6 +24,8 @@ struct NetworkProtocol::ConnectionPriv mutex cmutex {}; vector buffer {}; + + ChannelState channel = monostate(); }; @@ -202,6 +204,11 @@ void NetworkProtocol::Connection::close() p = nullptr; } +NetworkProtocol::ChannelState & NetworkProtocol::Connection::channel() +{ + return p->channel; +} + /******************************************************************************/ /* Header */ diff --git a/src/network/protocol.h b/src/network/protocol.h index 4794ba6..88abf67 100644 --- a/src/network/protocol.h +++ b/src/network/protocol.h @@ -1,5 +1,7 @@ #pragma once +#include "channel.h" + #include #include @@ -45,6 +47,12 @@ public: PollResult poll(); + using ChannelState = variant, + shared_ptr, + Stored, + unique_ptr>; + Connection connect(sockaddr_in6 addr); bool recvfrom(vector & buffer, sockaddr_in6 & addr); @@ -84,6 +92,9 @@ public: void close(); + // temporary: + ChannelState & channel(); + private: unique_ptr p; }; @@ -121,4 +132,28 @@ struct NetworkProtocol::Header const vector items; }; +class ReplyBuilder +{ +public: + void header(NetworkProtocol::Header::Item &&); + void body(const Ref &); + + const vector & header() const { return mheader; } + vector body() const; + +private: + vector mheader; + vector mbody; +}; + +struct WaitingRef +{ + const Storage storage; + const PartialRef ref; + vector missing; + + optional check(); + optional check(ReplyBuilder &); +}; + } -- cgit v1.2.3