summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2022-01-08 18:28:32 +0100
committerRoman Smrž <roman.smrz@seznam.cz>2022-01-08 18:53:04 +0100
commit21e1b04474ee5e8bc7acdd53772331f850234811 (patch)
tree05151b9305c327d3991ecec5614c8ee7a5915a4a
parent76319277261ac2d894921eeedf3a359d8353344e (diff)
Channel: use counter to generate nonce
-rw-r--r--src/channel.cpp73
-rw-r--r--src/channel.h29
-rw-r--r--src/network.cpp20
-rw-r--r--src/network.h2
4 files changed, 58 insertions, 66 deletions
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 <algorithm>
#include <stdexcept>
-#include <openssl/rand.h>
-
using std::remove_const;
using std::runtime_error;
@@ -70,54 +68,26 @@ ChannelAcceptData ChannelAcceptData::load(const Ref & ref)
};
}
-Stored<Channel> ChannelAcceptData::channel() const
+unique_ptr<Channel> ChannelAcceptData::channel() const
{
- const auto & st = request.ref().storage();
-
if (auto secret = SecretKexKey::load(key))
- return st.store(Channel(
+ return make_unique<Channel>(
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<Channel>(
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<Record::Item> 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<decltype(peers)>::type peers;
- for (const auto & i : rec->items("peer"))
- if (auto p = i.as<Signed<IdentityData>>())
- 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<ChannelRequest> Channel::generateRequest(const Storage & st,
const Identity & self, const Identity & peer)
{
@@ -165,20 +135,23 @@ optional<Stored<ChannelAccept>> Channel::acceptRequest(const Identity & self,
}));
}
-vector<uint8_t> Channel::encrypt(const vector<uint8_t> & plain) const
+vector<uint8_t> Channel::encrypt(const vector<uint8_t> & plain)
{
- vector<uint8_t> res(plain.size() + 12 + 16 + 16);
+ vector<uint8_t> res(plain.size() + 8 + 16 + 16);
+ array<uint8_t, 12> 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<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX*)>
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<uint8_t> Channel::encrypt(const vector<uint8_t> & plain) const
return res;
}
-optional<vector<uint8_t>> Channel::decrypt(const vector<uint8_t> & ctext) const
+optional<vector<uint8_t>> Channel::decrypt(const vector<uint8_t> & ctext)
{
vector<uint8_t> res(ctext.size());
+ array<uint8_t, 12> iv;
+
+ std::copy_n(nonceFixedPeer.begin(), 6, iv.begin());
+ std::copy_n(ctext.begin() + 2, 6, iv.begin() + 6);
const unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX*)>
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 <atomic>
+#include <memory>
+
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<class Channel> channel() const;
+ unique_ptr<class Channel> channel() const;
const Stored<ChannelRequest> request;
const Stored<PublicKexKey> key;
@@ -34,25 +41,33 @@ class Channel
{
public:
Channel(const vector<Stored<Signed<IdentityData>>> & peers,
- vector<uint8_t> && key):
+ vector<uint8_t> && 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<ChannelRequest> generateRequest(const Storage &,
const Identity & self, const Identity & peer);
static optional<Stored<ChannelAccept>> acceptRequest(const Identity & self,
const Identity & peer, const Stored<ChannelRequest> & request);
- vector<uint8_t> encrypt(const vector<uint8_t> &) const;
- optional<vector<uint8_t>> decrypt(const vector<uint8_t> &) const;
+ vector<uint8_t> encrypt(const vector<uint8_t> &);
+ optional<vector<uint8_t>> decrypt(const vector<uint8_t> &);
private:
const vector<Stored<Signed<IdentityData>>> peers;
const vector<uint8_t> key;
+
+ const array<uint8_t, 6> nonceFixedOur;
+ const array<uint8_t, 6> nonceFixedPeer;
+ atomic<uint64_t> 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<Stored<Channel>>(speer->channel);
+ return holds_alternative<unique_ptr<Channel>>(speer->channel);
return false;
}
@@ -306,8 +306,8 @@ void Server::Priv::doListen()
auto & peer = getPeer(paddr);
current = &buf;
- if (holds_alternative<Stored<Channel>>(peer.channel)) {
- if (auto dec = std::get<Stored<Channel>>(peer.channel)->decrypt(buf)) {
+ if (holds_alternative<unique_ptr<Channel>>(peer.channel)) {
+ if (auto dec = std::get<unique_ptr<Channel>>(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<PartialRef>(item.value)) {
if (holds_alternative<Stored<ChannelAccept>>(peer.channel) &&
std::get<Stored<ChannelAccept>>(peer.channel).ref().digest() == pref.digest())
- peer.channel.emplace<Stored<Channel>>
+ peer.channel.emplace<unique_ptr<Channel>>
(std::get<Stored<ChannelAccept>>(peer.channel)->data->channel());
}
break;
case TransportHeader::Type::DataRequest: {
auto pref = std::get<PartialRef>(item.value);
- if (holds_alternative<Stored<Channel>>(peer.channel) ||
+ if (holds_alternative<unique_ptr<Channel>>(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<Identity>(peer.identity) &&
acc.isSignedBy(std::get<Identity>(peer.identity).keyMessage())) {
reply.header({ TransportHeader::Type::Acknowledged, pref });
- peer.channel.emplace<Stored<Channel>>(acc.data->channel());
+ peer.channel.emplace<unique_ptr<Channel>>(acc.data->channel());
}
}
}
@@ -578,8 +578,8 @@ void Server::Peer::send(const TransportHeader & header, const vector<Object> & o
data.insert(data.end(), part.begin(), part.end());
}
- if (holds_alternative<Stored<Channel>>(channel))
- out = std::get<Stored<Channel>>(channel)->encrypt(data);
+ if (holds_alternative<unique_ptr<Channel>>(channel))
+ out = std::get<unique_ptr<Channel>>(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<Stored<Channel>>(channel))
+ if (!holds_alternative<unique_ptr<Channel>>(channel))
return;
for (const auto & data : secureOutQueue) {
- auto out = std::get<Stored<Channel>>(channel)->encrypt(data);
+ auto out = std::get<unique_ptr<Channel>>(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<ChannelRequest>,
shared_ptr<struct WaitingRef>,
Stored<ChannelAccept>,
- Stored<Channel>> channel;
+ unique_ptr<Channel>> channel;
Storage tempStorage;
PartialStorage partStorage;