From 21e1b04474ee5e8bc7acdd53772331f850234811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Sat, 8 Jan 2022 18:28:32 +0100 Subject: Channel: use counter to generate nonce --- src/channel.cpp | 73 ++++++++++++++++++++------------------------------------- src/channel.h | 29 +++++++++++++++++------ src/network.cpp | 20 ++++++++-------- src/network.h | 2 +- 4 files changed, 58 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/channel.cpp b/src/channel.cpp index 787fb08..f5cfb9c 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -3,8 +3,6 @@ #include #include -#include - using std::remove_const; using std::runtime_error; @@ -70,54 +68,26 @@ ChannelAcceptData ChannelAcceptData::load(const Ref & ref) }; } -Stored ChannelAcceptData::channel() const +unique_ptr ChannelAcceptData::channel() const { - const auto & st = request.ref().storage(); - if (auto secret = SecretKexKey::load(key)) - return st.store(Channel( + return make_unique( request->data->peers, - secret->dh(*request->data->key) - )); + secret->dh(*request->data->key), + false + ); if (auto secret = SecretKexKey::load(request->data->key)) - return st.store(Channel( + return make_unique( request->data->peers, - secret->dh(*key) - )); + secret->dh(*key), + true + ); throw runtime_error("failed to load secret DH key"); } -Ref Channel::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))); -} - -Channel Channel::load(const Ref & ref) -{ - if (auto rec = ref->asRecord()) { - remove_const::type peers; - for (const auto & i : rec->items("peer")) - if (auto p = i.as>()) - peers.push_back(*p); - - if (rec->item("enc").asText() == "aes-128-gcm") - if (auto key = rec->item("key").asBinary()) - return Channel(peers, std::move(*key)); - } - - return Channel({}, {}); -} - Stored Channel::generateRequest(const Storage & st, const Identity & self, const Identity & peer) { @@ -165,20 +135,23 @@ optional> Channel::acceptRequest(const Identity & self, })); } -vector Channel::encrypt(const vector & plain) const +vector Channel::encrypt(const vector & plain) { - vector res(plain.size() + 12 + 16 + 16); + vector res(plain.size() + 8 + 16 + 16); + array iv; - if (RAND_bytes(res.data(), 12) != 1) - throw runtime_error("failed to generate random IV"); + uint64_t beCount = htobe64(nonceCounter++); + std::copy_n(&beCount, 6, res.begin()); + 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(), res.data()); + nullptr, key.data(), iv.data()); int outl = 0; - uint8_t * cur = res.data() + 12; + 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"); @@ -195,20 +168,24 @@ vector Channel::encrypt(const vector & plain) const return res; } -optional> Channel::decrypt(const vector & ctext) const +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(), ctext.data()); + nullptr, key.data(), iv.data()); int outl = 0; uint8_t * cur = res.data(); if (EVP_DecryptUpdate(ctx.get(), cur, &outl, - ctext.data() + 12, ctext.size() - 12 - 16) != 1) + ctext.data() + 8, ctext.size() - 8 - 16) != 1) return nullopt; cur += outl; diff --git a/src/channel.h b/src/channel.h index 1c7df30..5f1786e 100644 --- a/src/channel.h +++ b/src/channel.h @@ -4,8 +4,15 @@ #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; @@ -22,7 +29,7 @@ struct ChannelAcceptData Ref store(const Storage & st) const; static ChannelAcceptData load(const Ref &); - Stored channel() const; + unique_ptr channel() const; const Stored request; const Stored key; @@ -34,25 +41,33 @@ class Channel { public: Channel(const vector>> & peers, - vector && key): + vector && key, bool ourRequest): peers(peers), - key(std::move(key)) + 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 }) {} - Ref store(const Storage & st) const; - static Channel load(const Ref &); + 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 &) const; - optional> decrypt(const vector &) const; + 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 b735262..84c3083 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -135,7 +135,7 @@ void Peer::Priv::notifyWatchers() bool Peer::hasChannel() const { if (auto speer = p->speer.lock()) - return holds_alternative>(speer->channel); + return holds_alternative>(speer->channel); return false; } @@ -306,8 +306,8 @@ void Server::Priv::doListen() auto & peer = getPeer(paddr); current = &buf; - if (holds_alternative>(peer.channel)) { - if (auto dec = std::get>(peer.channel)->decrypt(buf)) { + if (holds_alternative>(peer.channel)) { + if (auto dec = std::get>(peer.channel)->decrypt(buf)) { decrypted = std::move(*dec); current = &decrypted; } @@ -421,14 +421,14 @@ void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & hea if (auto pref = std::get(item.value)) { if (holds_alternative>(peer.channel) && std::get>(peer.channel).ref().digest() == pref.digest()) - peer.channel.emplace> + peer.channel.emplace> (std::get>(peer.channel)->data->channel()); } break; case TransportHeader::Type::DataRequest: { auto pref = std::get(item.value); - if (holds_alternative>(peer.channel) || + if (holds_alternative>(peer.channel) || plaintextRefs.find(pref.digest()) != plaintextRefs.end()) { if (auto ref = peer.tempStorage.ref(pref.digest())) { TransportHeader::Item hitem { TransportHeader::Type::DataResponse, *ref }; @@ -514,7 +514,7 @@ void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & hea if (holds_alternative(peer.identity) && acc.isSignedBy(std::get(peer.identity).keyMessage())) { reply.header({ TransportHeader::Type::Acknowledged, pref }); - peer.channel.emplace>(acc.data->channel()); + peer.channel.emplace>(acc.data->channel()); } } } @@ -578,8 +578,8 @@ void Server::Peer::send(const TransportHeader & header, const vector & o data.insert(data.end(), part.begin(), part.end()); } - if (holds_alternative>(channel)) - out = std::get>(channel)->encrypt(data); + if (holds_alternative>(channel)) + out = std::get>(channel)->encrypt(data); else if (secure) secureOutQueue.emplace_back(move(data)); else @@ -676,11 +676,11 @@ void Server::Peer::trySendOutQueue() if (secureOutQueue.empty()) return; - if (!holds_alternative>(channel)) + if (!holds_alternative>(channel)) return; for (const auto & data : secureOutQueue) { - auto out = std::get>(channel)->encrypt(data); + auto out = std::get>(channel)->encrypt(data); sendto(server.sock, out.data(), out.size(), 0, (sockaddr *) &addr, sizeof(addr)); diff --git a/src/network.h b/src/network.h index a59a1bc..40c06bf 100644 --- a/src/network.h +++ b/src/network.h @@ -50,7 +50,7 @@ struct Server::Peer Stored, shared_ptr, Stored, - Stored> channel; + unique_ptr> channel; Storage tempStorage; PartialStorage partStorage; -- cgit v1.2.3