From d7d964bf57fe1cc42b142c53cd6b3593178a734d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 14:31:01 -0500 Subject: [PATCH 01/58] GarlicRoutingSession/ElGamalAESSession split --- libi2pd/Garlic.cpp | 242 +++++++++++++++++++++++---------------------- libi2pd/Garlic.h | 115 +++++++++++++-------- libi2pd/NetDb.cpp | 2 +- 3 files changed, 201 insertions(+), 158 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index aa715e0c..aac4c06c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -19,23 +19,16 @@ namespace i2p namespace garlic { GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, - std::shared_ptr destination, int numTags, bool attachLeaseSet): - m_Owner (owner), m_Destination (destination), m_NumTags (numTags), + std::shared_ptr destination, bool attachLeaseSet): + m_Owner (owner), m_Destination (destination), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) { - // create new session tags and session key - RAND_bytes (m_SessionKey, 32); - m_Encryption.SetKey (m_SessionKey); } - GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): - m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) + GarlicRoutingSession::GarlicRoutingSession (): + m_Owner (nullptr), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) { - memcpy (m_SessionKey, sessionKey, 32); - m_Encryption.SetKey (m_SessionKey); - m_SessionTags.push_back (sessionTag); - m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); } GarlicRoutingSession::~GarlicRoutingSession () @@ -67,88 +60,24 @@ namespace garlic m_SharedRoutingPath = path; } - GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags () + ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner, + std::shared_ptr destination, int numTags, bool attachLeaseSet): + GarlicRoutingSession (owner, destination, attachLeaseSet), m_NumTags (numTags) { - auto tags = new UnconfirmedTags (m_NumTags); - tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); - for (int i = 0; i < m_NumTags; i++) - { - RAND_bytes (tags->sessionTags[i], 32); - tags->sessionTags[i].creationTime = tags->tagsCreationTime; - } - return tags; + // create new session tags and session key + RAND_bytes (m_SessionKey, 32); + m_Encryption.SetKey (m_SessionKey); } - void GarlicRoutingSession::MessageConfirmed (uint32_t msgID) + ElGamalAESSession::ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag) { - TagsConfirmed (msgID); - if (msgID == m_LeaseSetUpdateMsgID) - { - m_LeaseSetUpdateStatus = eLeaseSetUpToDate; - m_LeaseSetUpdateMsgID = 0; - LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); - } - else - CleanupExpiredTags (); + memcpy (m_SessionKey, sessionKey, 32); + m_Encryption.SetKey (m_SessionKey); + m_SessionTags.push_back (sessionTag); + m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); } - void GarlicRoutingSession::TagsConfirmed (uint32_t msgID) - { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - auto it = m_UnconfirmedTagsMsgs.find (msgID); - if (it != m_UnconfirmedTagsMsgs.end ()) - { - auto& tags = it->second; - if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) - { - for (int i = 0; i < tags->numTags; i++) - m_SessionTags.push_back (tags->sessionTags[i]); - } - m_UnconfirmedTagsMsgs.erase (it); - } - } - - bool GarlicRoutingSession::CleanupExpiredTags () - { - auto ts = i2p::util::GetSecondsSinceEpoch (); - for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();) - { - if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) - it = m_SessionTags.erase (it); - else - ++it; - } - CleanupUnconfirmedTags (); - if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) - { - if (m_Owner) - m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); - m_LeaseSetUpdateMsgID = 0; - } - return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); - } - - bool GarlicRoutingSession::CleanupUnconfirmedTags () - { - bool ret = false; - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - // delete expired unconfirmed tags - for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) - { - if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) - { - if (m_Owner) - m_Owner->RemoveDeliveryStatusSession (it->first); - it = m_UnconfirmedTagsMsgs.erase (it); - ret = true; - } - else - ++it; - } - return ret; - } - - std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) + std::shared_ptr ElGamalAESSession::WrapSingleMessage (std::shared_ptr msg) { auto m = NewI2NPMessage (); m->Align (12); // in order to get buf aligned to 16 (12 + 4) @@ -178,7 +107,7 @@ namespace garlic if (!tagFound) // new session { LogPrint (eLogInfo, "Garlic: No tags available, will use ElGamal"); - if (!m_Destination) + if (!GetDestination ()) { LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination"); return nullptr; @@ -190,7 +119,7 @@ namespace garlic uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); BN_CTX * ctx = BN_CTX_new (); - m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx); + GetDestination ()->Encrypt ((uint8_t *)&elGamal, buf, ctx); BN_CTX_free (ctx); m_Encryption.SetIV (iv); buf += 514; @@ -214,10 +143,10 @@ namespace garlic return m; } - size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr msg) + size_t ElGamalAESSession::CreateAESBlock (uint8_t * buf, std::shared_ptr msg) { size_t blockSize = 0; - bool createNewTags = m_Owner && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3); + bool createNewTags = GetOwner () && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3); UnconfirmedTags * newTags = createNewTags ? GenerateSessionTags () : nullptr; htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count blockSize += 2; @@ -246,7 +175,7 @@ namespace garlic return blockSize; } - size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags) + size_t ElGamalAESSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint32_t msgID; @@ -256,17 +185,17 @@ namespace garlic *numCloves = 0; size++; - if (m_Owner) + if (GetOwner ()) { // resubmit non-confirmed LeaseSet - if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) + if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) { - m_LeaseSetUpdateStatus = eLeaseSetUpdated; + SetLeaseSetUpdateStatus (eLeaseSetUpdated); SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed } // attach DeviveryStatus if necessary - if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated + if (newTags || GetLeaseSetUpdateStatus () == eLeaseSetUpdated) // new tags created or leaseset updated { // clove is DeliveryStatus auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID); @@ -280,27 +209,27 @@ namespace garlic m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr(newTags))); newTags = nullptr; // got acquired } - m_Owner->DeliveryStatusSent (shared_from_this (), msgID); + GetOwner ()->DeliveryStatusSent (shared_from_this (), msgID); } else LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created"); } // attach LeaseSet - if (m_LeaseSetUpdateStatus == eLeaseSetUpdated) + if (GetLeaseSetUpdateStatus () == eLeaseSetUpdated) { - if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous - m_LeaseSetUpdateStatus = eLeaseSetSubmitted; - m_LeaseSetUpdateMsgID = msgID; - m_LeaseSetSubmissionTime = ts; + if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous + SetLeaseSetUpdateStatus (eLeaseSetSubmitted); + SetLeaseSetUpdateMsgID (msgID); + SetLeaseSetSubmissionTime (ts); // clove if our leaseSet must be attached - auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ()); + auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); size += CreateGarlicClove (payload + size, leaseSet, false); (*numCloves)++; } } if (msg) // clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); + size += CreateGarlicClove (payload + size, msg, IsDestination ()); (*numCloves)++; } memset (payload + size, 0, 3); // certificate of message @@ -314,7 +243,7 @@ namespace garlic return size; } - size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination) + size_t ElGamalAESSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec size_t size = 0; @@ -322,7 +251,7 @@ namespace garlic { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (buf + size, m_Destination->GetIdentHash (), 32); + memcpy (buf + size, GetDestination ()->GetIdentHash (), 32); size += 32; } else @@ -344,12 +273,12 @@ namespace garlic return size; } - size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID) + size_t ElGamalAESSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID) { size_t size = 0; - if (m_Owner) + if (GetOwner ()) { - auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel (); + auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel (); if (inboundTunnel) { buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel @@ -361,14 +290,14 @@ namespace garlic size += 4; // create msg auto msg = CreateDeliveryStatusMsg (msgID); - if (m_Owner) + if (GetOwner ()) { //encrypt uint8_t key[32], tag[32]; RAND_bytes (key, 32); // random session key RAND_bytes (tag, 32); // random session tag - m_Owner->SubmitSessionKey (key, tag); - GarlicRoutingSession garlic (key, tag); + GetOwner ()->SubmitSessionKey (key, tag); + ElGamalAESSession garlic (key, tag); msg = garlic.WrapSingleMessage (msg); } memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); @@ -393,6 +322,87 @@ namespace garlic return size; } + ElGamalAESSession::UnconfirmedTags * ElGamalAESSession::GenerateSessionTags () + { + auto tags = new UnconfirmedTags (m_NumTags); + tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); + for (int i = 0; i < m_NumTags; i++) + { + RAND_bytes (tags->sessionTags[i], 32); + tags->sessionTags[i].creationTime = tags->tagsCreationTime; + } + return tags; + } + + void ElGamalAESSession::MessageConfirmed (uint32_t msgID) + { + TagsConfirmed (msgID); + if (msgID == GetLeaseSetUpdateMsgID ()) + { + SetLeaseSetUpdateStatus (eLeaseSetUpToDate); + SetLeaseSetUpdateMsgID (0); + LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); + } + else + CleanupExpiredTags (); + } + + void ElGamalAESSession::TagsConfirmed (uint32_t msgID) + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + auto it = m_UnconfirmedTagsMsgs.find (msgID); + if (it != m_UnconfirmedTagsMsgs.end ()) + { + auto& tags = it->second; + if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) + { + for (int i = 0; i < tags->numTags; i++) + m_SessionTags.push_back (tags->sessionTags[i]); + } + m_UnconfirmedTagsMsgs.erase (it); + } + } + + bool ElGamalAESSession::CleanupExpiredTags () + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();) + { + if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) + it = m_SessionTags.erase (it); + else + ++it; + } + CleanupUnconfirmedTags (); + if (GetLeaseSetUpdateMsgID () && ts*1000LL > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) + { + if (GetOwner ()) + GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); + SetLeaseSetUpdateMsgID (0); + } + return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); + } + + bool ElGamalAESSession::CleanupUnconfirmedTags () + { + bool ret = false; + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + // delete expired unconfirmed tags + for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) + { + if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) + { + if (GetOwner ()) + GetOwner ()->RemoveDeliveryStatusSession (it->first); + it = m_UnconfirmedTagsMsgs.erase (it); + ret = true; + } + else + ++it; + } + return ret; + } + GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default { m_Ctx = BN_CTX_new (); @@ -646,7 +656,7 @@ namespace garlic std::shared_ptr GarlicDestination::GetRoutingSession ( std::shared_ptr destination, bool attachLeaseSet) { - GarlicRoutingSessionPtr session; + ElGamalAESSessionPtr session; { std::unique_lock l(m_SessionsMutex); auto it = m_Sessions.find (destination->GetIdentHash ()); @@ -655,7 +665,7 @@ namespace garlic } if (!session) { - session = std::make_shared (this, destination, + session = std::make_shared (this, destination, attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests std::unique_lock l(m_SessionsMutex); m_Sessions[destination->GetIdentHash ()] = session; @@ -716,7 +726,7 @@ namespace garlic m_DeliveryStatusSessions.erase (msgID); } - void GarlicDestination::DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID) + void GarlicDestination::DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID) { std::unique_lock l(m_DeliveryStatusSessionsMutex); m_DeliveryStatusSessions[msgID] = session; @@ -724,7 +734,7 @@ namespace garlic void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID) { - GarlicRoutingSessionPtr session; + ElGamalAESSessionPtr session; { std::unique_lock l(m_DeliveryStatusSessionsMutex); auto it = m_DeliveryStatusSessions.find (msgID); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 30e6ff4b..296ef9a3 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -85,8 +85,10 @@ namespace garlic }; class GarlicDestination; - class GarlicRoutingSession: public std::enable_shared_from_this + class GarlicRoutingSession { + protected: + enum LeaseSetUpdateStatus { eLeaseSetUpToDate = 0, @@ -95,26 +97,13 @@ namespace garlic eLeaseSetDoNotSend }; - struct UnconfirmedTags - { - UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; }; - ~UnconfirmedTags () { delete[] sessionTags; }; - uint32_t msgID; - int numTags; - SessionTag * sessionTags; - uint32_t tagsCreationTime; - }; - public: - GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, - int numTags, bool attachLeaseSet); - GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption - ~GarlicRoutingSession (); - std::shared_ptr WrapSingleMessage (std::shared_ptr msg); - void MessageConfirmed (uint32_t msgID); - bool CleanupExpiredTags (); // returns true if something left - bool CleanupUnconfirmedTags (); // returns true if something has been deleted + GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, bool attachLeaseSet); + GarlicRoutingSession (); + virtual ~GarlicRoutingSession (); + virtual std::shared_ptr WrapSingleMessage (std::shared_ptr msg) = 0; + virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession void SetLeaseSetUpdated () { @@ -127,11 +116,65 @@ namespace garlic std::shared_ptr GetSharedRoutingPath (); void SetSharedRoutingPath (std::shared_ptr path); - const GarlicDestination * GetOwner () const { return m_Owner; } + GarlicDestination * GetOwner () const { return m_Owner; } void SetOwner (GarlicDestination * owner) { m_Owner = owner; } + protected: + + LeaseSetUpdateStatus GetLeaseSetUpdateStatus () const { return m_LeaseSetUpdateStatus; } + void SetLeaseSetUpdateStatus (LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; } + uint32_t GetLeaseSetUpdateMsgID () const { return m_LeaseSetUpdateMsgID; } + void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; } + + void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; } + bool IsDestination () const { return m_Destination ? m_Destination->IsDestination () : false; } + const std::shared_ptr& GetDestination () const { return m_Destination; } + private: + GarlicDestination * m_Owner; + std::shared_ptr m_Destination; + + LeaseSetUpdateStatus m_LeaseSetUpdateStatus; + uint32_t m_LeaseSetUpdateMsgID; + uint64_t m_LeaseSetSubmissionTime; // in milliseconds + + std::shared_ptr m_SharedRoutingPath; + + public: + // for HTTP only + virtual size_t GetNumOutgoingTags () const { return 0; }; + }; + //using GarlicRoutingSessionPtr = std::shared_ptr; + typedef std::shared_ptr GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8 + + class ElGamalAESSession: public GarlicRoutingSession, public std::enable_shared_from_this + { + struct UnconfirmedTags + { + UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; }; + ~UnconfirmedTags () { delete[] sessionTags; }; + uint32_t msgID; + int numTags; + SessionTag * sessionTags; + uint32_t tagsCreationTime; + }; + + public: + + ElGamalAESSession (GarlicDestination * owner, std::shared_ptr destination, + int numTags, bool attachLeaseSet); + ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption + ~ElGamalAESSession () {}; + + std::shared_ptr WrapSingleMessage (std::shared_ptr msg); + + void MessageConfirmed (uint32_t msgID); + bool CleanupExpiredTags (); // returns true if something left + bool CleanupUnconfirmedTags (); // returns true if something has been deleted + + private: + size_t CreateAESBlock (uint8_t * buf, std::shared_ptr msg); size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags); size_t CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination); @@ -139,31 +182,21 @@ namespace garlic void TagsConfirmed (uint32_t msgID); UnconfirmedTags * GenerateSessionTags (); + + private: - private: - - GarlicDestination * m_Owner; - std::shared_ptr m_Destination; - - i2p::crypto::AESKey m_SessionKey; + i2p::crypto::AESKey m_SessionKey; std::list m_SessionTags; int m_NumTags; std::map > m_UnconfirmedTagsMsgs; // msgID->tags - LeaseSetUpdateStatus m_LeaseSetUpdateStatus; - uint32_t m_LeaseSetUpdateMsgID; - uint64_t m_LeaseSetSubmissionTime; // in milliseconds + i2p::crypto::CBCEncryption m_Encryption; - i2p::crypto::CBCEncryption m_Encryption; - - std::shared_ptr m_SharedRoutingPath; - - public: + public: // for HTTP only - size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; - }; - //using GarlicRoutingSessionPtr = std::shared_ptr; - typedef std::shared_ptr GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8 + size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; + }; + typedef std::shared_ptr ElGamalAESSessionPtr; class GarlicDestination: public i2p::data::LocalDestination { @@ -182,7 +215,7 @@ namespace garlic void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread - void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); + void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID); virtual void ProcessGarlicMessage (std::shared_ptr msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); @@ -217,12 +250,12 @@ namespace garlic // outgoing sessions int m_NumTags; std::mutex m_SessionsMutex; - std::map m_Sessions; + std::map m_Sessions; // incoming std::map > m_Tags; // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; - std::map m_DeliveryStatusSessions; // msgID -> session + std::map m_DeliveryStatusSessions; // msgID -> session public: diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 4461c094..6d69f131 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -950,7 +950,7 @@ namespace data if (numTags) { const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag - i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag); + i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag); replyMsg = garlic.WrapSingleMessage (replyMsg); if(replyMsg == nullptr) LogPrint(eLogError, "NetDb: failed to wrap message"); } From dc9da6950953b6491385257de29dc5061545bbb4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 14:59:19 -0500 Subject: [PATCH 02/58] derive ECIESX25519AEADRatchetSession from GarlicRoutingSession --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 19 +++++++++++++------ libi2pd/ECIESX25519AEADRatchetSession.h | 10 ++++++---- libi2pd/Garlic.cpp | 21 ++++++++++----------- libi2pd/Garlic.h | 10 ++++------ 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 96efe5e6..56b97635 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -12,7 +12,8 @@ namespace i2p namespace garlic { - ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession () + ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): + GarlicRoutingSession (owner, true) { // TODO : use precalculated hashes static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes @@ -34,12 +35,12 @@ namespace garlic SHA256_Final (m_H, &ctx); } - bool ECIESX25519AEADRatchetSession::NewIncomingSession (const i2p::data::LocalDestination& dest, - const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { + if (!GetOwner ()) return false; // we are Bob // KDF1 - MixHash (dest.GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk) + MixHash (GetOwner ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk) uint8_t aepk[32]; // Alice's ephemeral key if (!i2p::crypto::GetElligator ()->Decode (buf, aepk)) @@ -51,7 +52,7 @@ namespace garlic MixHash (aepk, 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32], keyData[64]; - dest.Decrypt (aepk, sharedSecret, nullptr); // x25519(bsk, aepk) + GetOwner ()->Decrypt (aepk, sharedSecret, nullptr); // x25519(bsk, aepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] @@ -73,7 +74,7 @@ namespace garlic if (isStatic) { // static key, fs is apk - dest.Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk) + GetOwner ()->Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] } @@ -126,6 +127,12 @@ namespace garlic offset += size; } } + + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) + { + // TODO: + return nullptr; + } } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index aa482d54..fa9a960e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -4,6 +4,7 @@ #include #include #include "Identity.h" +#include "Garlic.h" namespace i2p { @@ -20,17 +21,18 @@ namespace garlic eECIESx25519BlkPadding = 254 }; - class ECIESX25519AEADRatchetSession + class ECIESX25519AEADRatchetSession: public GarlicRoutingSession { public: typedef std::function CloveHandler; - ECIESX25519AEADRatchetSession (); + ECIESX25519AEADRatchetSession (GarlicDestination * owner); ~ECIESX25519AEADRatchetSession (); - bool NewIncomingSession (const i2p::data::LocalDestination& dest, const uint8_t * buf, size_t len, - CloveHandler handleClove); + std::shared_ptr WrapSingleMessage (std::shared_ptr msg); + + bool NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); private: diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index aac4c06c..965ccdb4 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -18,10 +18,8 @@ namespace i2p { namespace garlic { - GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, - std::shared_ptr destination, bool attachLeaseSet): - m_Owner (owner), m_Destination (destination), - m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), + GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, bool attachLeaseSet): + m_Owner (owner), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) { } @@ -62,7 +60,8 @@ namespace garlic ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner, std::shared_ptr destination, int numTags, bool attachLeaseSet): - GarlicRoutingSession (owner, destination, attachLeaseSet), m_NumTags (numTags) + GarlicRoutingSession (owner, attachLeaseSet), + m_Destination (destination), m_NumTags (numTags) { // create new session tags and session key RAND_bytes (m_SessionKey, 32); @@ -107,7 +106,7 @@ namespace garlic if (!tagFound) // new session { LogPrint (eLogInfo, "Garlic: No tags available, will use ElGamal"); - if (!GetDestination ()) + if (!m_Destination) { LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination"); return nullptr; @@ -119,7 +118,7 @@ namespace garlic uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); BN_CTX * ctx = BN_CTX_new (); - GetDestination ()->Encrypt ((uint8_t *)&elGamal, buf, ctx); + m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx); BN_CTX_free (ctx); m_Encryption.SetIV (iv); buf += 514; @@ -229,7 +228,7 @@ namespace garlic } if (msg) // clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, IsDestination ()); + size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); (*numCloves)++; } memset (payload + size, 0, 3); // certificate of message @@ -251,7 +250,7 @@ namespace garlic { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (buf + size, GetDestination ()->GetIdentHash (), 32); + memcpy (buf + size, m_Destination->GetIdentHash (), 32); size += 32; } else @@ -842,8 +841,8 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { - ECIESX25519AEADRatchetSession session; - session.NewIncomingSession (*this, buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, + ECIESX25519AEADRatchetSession session (this); + session.NewIncomingSession (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, this, std::placeholders::_1, std::placeholders::_2)); } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 296ef9a3..cd8c48ed 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -99,7 +99,7 @@ namespace garlic public: - GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, bool attachLeaseSet); + GarlicRoutingSession (GarlicDestination * owner, bool attachLeaseSet); GarlicRoutingSession (); virtual ~GarlicRoutingSession (); virtual std::shared_ptr WrapSingleMessage (std::shared_ptr msg) = 0; @@ -125,15 +125,11 @@ namespace garlic void SetLeaseSetUpdateStatus (LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; } uint32_t GetLeaseSetUpdateMsgID () const { return m_LeaseSetUpdateMsgID; } void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; } - - void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; } - bool IsDestination () const { return m_Destination ? m_Destination->IsDestination () : false; } - const std::shared_ptr& GetDestination () const { return m_Destination; } + void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; } private: GarlicDestination * m_Owner; - std::shared_ptr m_Destination; LeaseSetUpdateStatus m_LeaseSetUpdateStatus; uint32_t m_LeaseSetUpdateMsgID; @@ -184,6 +180,8 @@ namespace garlic UnconfirmedTags * GenerateSessionTags (); private: + + std::shared_ptr m_Destination; i2p::crypto::AESKey m_SessionKey; std::list m_SessionTags; From b6800dd125544d9823f75b488949366789d6df33 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 15:45:22 -0500 Subject: [PATCH 03/58] lookup ECIESX25519AEADRatchet session by static key --- libi2pd/CryptoKey.cpp | 6 +-- libi2pd/CryptoKey.h | 4 +- libi2pd/ECIESX25519AEADRatchetSession.cpp | 1 + libi2pd/ECIESX25519AEADRatchetSession.h | 3 +- libi2pd/Garlic.cpp | 55 +++++++++++++++-------- libi2pd/Garlic.h | 4 ++ 6 files changed, 48 insertions(+), 25 deletions(-) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index df5dd38f..9881ebef 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -151,11 +151,9 @@ namespace crypto memcpy (m_PublicKey, pub, 32); } - void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t * epriv, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding) + void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool) { - X25519Keys ep; - ep.SetPrivateKey (epriv); - ep.Agree (m_PublicKey, sharedSecret); + memcpy (pub, m_PublicKey, 32); } ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv) diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h index 6412f4d3..701e9482 100644 --- a/libi2pd/CryptoKey.h +++ b/libi2pd/CryptoKey.h @@ -125,8 +125,8 @@ namespace crypto ECIESX25519AEADRatchetEncryptor (const uint8_t * pub); ~ECIESX25519AEADRatchetEncryptor () {}; - void Encrypt (const uint8_t * epriv, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding); - // agree with ephemeral priv and return in sharedSecret (32 bytes) + void Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool); + // copies m_PublicKey to pub private: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 56b97635..2f18ada2 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -74,6 +74,7 @@ namespace garlic if (isStatic) { // static key, fs is apk + memcpy (m_StaticKey, fs, 32); GetOwner ()->Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index fa9a960e..b273f2fd 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -33,6 +33,7 @@ namespace garlic std::shared_ptr WrapSingleMessage (std::shared_ptr msg); bool NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); + const uint8_t * GetStaticKey () const { return m_StaticKey; }; private: @@ -42,7 +43,7 @@ namespace garlic private: - uint8_t m_H[32], m_CK[32]; + uint8_t m_H[32], m_CK[32], m_StaticKey[32]; }; } } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 965ccdb4..f865d8f9 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -655,21 +655,35 @@ namespace garlic std::shared_ptr GarlicDestination::GetRoutingSession ( std::shared_ptr destination, bool attachLeaseSet) { - ElGamalAESSessionPtr session; - { - std::unique_lock l(m_SessionsMutex); - auto it = m_Sessions.find (destination->GetIdentHash ()); - if (it != m_Sessions.end ()) - session = it->second; - } - if (!session) - { - session = std::make_shared (this, destination, - attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests - std::unique_lock l(m_SessionsMutex); - m_Sessions[destination->GetIdentHash ()] = session; - } - return session; + if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET) + { + ECIESX25519AEADRatchetSessionPtr session; + uint8_t staticKey[32]; + destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key + auto it = m_ECIESx25519Sessions.find (staticKey); + if (it != m_ECIESx25519Sessions.end ()) + session = it->second; + // TODO: Alice + return session; + } + else + { + ElGamalAESSessionPtr session; + { + std::unique_lock l(m_SessionsMutex); + auto it = m_Sessions.find (destination->GetIdentHash ()); + if (it != m_Sessions.end ()) + session = it->second; + } + if (!session) + { + session = std::make_shared (this, destination, + attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests + std::unique_lock l(m_SessionsMutex); + m_Sessions[destination->GetIdentHash ()] = session; + } + return session; + } } void GarlicDestination::CleanupExpiredTags () @@ -841,9 +855,14 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { - ECIESX25519AEADRatchetSession session (this); - session.NewIncomingSession (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, - this, std::placeholders::_1, std::placeholders::_2)); + auto session = std::make_shared (this); + if (session->NewIncomingSession (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, + this, std::placeholders::_1, std::placeholders::_2))) + { + m_ECIESx25519Sessions.emplace (session->GetStaticKey (), session); + } + else + LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); } void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index cd8c48ed..727b4a8d 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -196,6 +196,9 @@ namespace garlic }; typedef std::shared_ptr ElGamalAESSessionPtr; + class ECIESX25519AEADRatchetSession; + typedef std::shared_ptr ECIESX25519AEADRatchetSessionPtr; + class GarlicDestination: public i2p::data::LocalDestination { public: @@ -249,6 +252,7 @@ namespace garlic int m_NumTags; std::mutex m_SessionsMutex; std::map m_Sessions; + std::map, ECIESX25519AEADRatchetSessionPtr > m_ECIESx25519Sessions; // static key -> session // incoming std::map > m_Tags; // DeliveryStatus From 67dd59125ed6f9c065cb43b98b459fc08543c4cb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 16:34:13 -0500 Subject: [PATCH 04/58] new outgoing ECIESX25519AEADRatchet session --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 36 +++++++++++++++++++++++ libi2pd/ECIESX25519AEADRatchetSession.h | 4 +++ 2 files changed, 40 insertions(+) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 2f18ada2..22458a5e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -15,6 +15,7 @@ namespace garlic ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): GarlicRoutingSession (owner, true) { + m_EphemeralKeys.GenerateKeys (); // TODO : use precalculated hashes static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes SHA256 ((const uint8_t *)protocolName, 40, m_H); @@ -129,6 +130,41 @@ namespace garlic } } + bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) + { + // we are Alice, bpk is m_StaticKey + size_t offset = 0; + if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) + { + LogPrint (eLogError, "Garlic: Can't encode elligator"); + return false; + } + offset += 32; + + // KDF1 + MixHash (m_StaticKey, 32); // h = SHA256(h || bpk) + MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk) + uint8_t sharedSecret[32], keyData[64]; + m_EphemeralKeys.Agree (m_StaticKey, nullptr); // x25519(aesk, bpk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) + memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] + // encrypt static key section + uint8_t nonce[12]; + memset (nonce, 0, 12); // n = 0 + if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (), 32, m_H, 32, keyData + 32, nonce, out + offset, 48, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed "); + return false; + } + MixHash (out + offset, 48); // h = SHA256(h || ciphertext) + offset += 48; + + // KDF2 + // TODO: // x25519 (ask, bpk) + + return true; + } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { // TODO: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b273f2fd..8cfd18b9 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -4,6 +4,7 @@ #include #include #include "Identity.h" +#include "Crypto.h" #include "Garlic.h" namespace i2p @@ -41,9 +42,12 @@ namespace garlic void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); + bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + private: uint8_t m_H[32], m_CK[32], m_StaticKey[32]; + i2p::crypto::X25519Keys m_EphemeralKeys; }; } } From 00cb15d9b4e8bddd5e99c0563b4662a0f2450385 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 18:03:51 -0500 Subject: [PATCH 05/58] fixed tyypo --- libi2pd/Garlic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index f865d8f9..a4cbeb01 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -68,7 +68,8 @@ namespace garlic m_Encryption.SetKey (m_SessionKey); } - ElGamalAESSession::ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag) + ElGamalAESSession::ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag): + m_NumTags(1) { memcpy (m_SessionKey, sessionKey, 32); m_Encryption.SetKey (m_SessionKey); From 451c3945f051a843c56a326891c053f826a30d53 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 19:33:00 -0500 Subject: [PATCH 06/58] create new ECIESX25519AEADRatchet session if not found --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 44 ++++++++++++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 6 ++-- libi2pd/Garlic.cpp | 9 +++-- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 22458a5e..ff40bef1 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -35,7 +35,7 @@ namespace garlic SHA256_Update (&ctx, buf, len); SHA256_Final (m_H, &ctx); } - + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; @@ -52,15 +52,14 @@ namespace garlic buf += 32; len -= 32; MixHash (aepk, 32); // h = SHA256(h || aepk) - uint8_t sharedSecret[32], keyData[64]; + uint8_t sharedSecret[32]; GetOwner ()->Decrypt (aepk, sharedSecret, nullptr); // x25519(bsk, aepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) - memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] - + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + // decrypt flags/static uint8_t nonce[12], fs[32]; memset (nonce, 0, 12); // n = 0 - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, keyData + 32, nonce, fs, 32, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, m_CK + 32, nonce, fs, 32, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); return false; @@ -75,14 +74,13 @@ namespace garlic if (isStatic) { // static key, fs is apk - memcpy (m_StaticKey, fs, 32); + memcpy (m_RemoteStaticKey, fs, 32); GetOwner ()->Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) - memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) } else // all zeros flags htole64buf (nonce + 4, 1); // n = 1 - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keyData + 32, nonce, payload.data (), len - 16, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); return false; @@ -132,7 +130,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { - // we are Alice, bpk is m_StaticKey + // we are Alice, bpk is m_RemoteStaticKey size_t offset = 0; if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) { @@ -142,26 +140,32 @@ namespace garlic offset += 32; // KDF1 - MixHash (m_StaticKey, 32); // h = SHA256(h || bpk) + MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk) MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk) - uint8_t sharedSecret[32], keyData[64]; - m_EphemeralKeys.Agree (m_StaticKey, nullptr); // x25519(aesk, bpk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) - memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31] + uint8_t sharedSecret[32]; + m_EphemeralKeys.Agree (m_RemoteStaticKey, nullptr); // x25519(aesk, bpk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) // encrypt static key section uint8_t nonce[12]; memset (nonce, 0, 12); // n = 0 - if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (), 32, m_H, 32, keyData + 32, nonce, out + offset, 48, true)) // encrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed "); return false; } MixHash (out + offset, 48); // h = SHA256(h || ciphertext) offset += 48; - // KDF2 - // TODO: // x25519 (ask, bpk) - + GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr); // x25519 (ask, bpk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + // encrypt payload + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); + return false; + } + MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) + return true; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 8cfd18b9..fd0658a5 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -1,6 +1,7 @@ #ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__ #define ECIES_X25519_AEAD_RATCHET_SESSION_H__ +#include #include #include #include "Identity.h" @@ -34,7 +35,8 @@ namespace garlic std::shared_ptr WrapSingleMessage (std::shared_ptr msg); bool NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); - const uint8_t * GetStaticKey () const { return m_StaticKey; }; + const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } + void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } private: @@ -46,7 +48,7 @@ namespace garlic private: - uint8_t m_H[32], m_CK[32], m_StaticKey[32]; + uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; i2p::crypto::X25519Keys m_EphemeralKeys; }; } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index a4cbeb01..fc8a4f01 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -664,7 +664,12 @@ namespace garlic auto it = m_ECIESx25519Sessions.find (staticKey); if (it != m_ECIESx25519Sessions.end ()) session = it->second; - // TODO: Alice + if (!session) + { + session = std::make_shared (this); + session->SetRemoteStaticKey (staticKey); + m_ECIESx25519Sessions.emplace (staticKey, session); + } return session; } else @@ -860,7 +865,7 @@ namespace garlic if (session->NewIncomingSession (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, this, std::placeholders::_1, std::placeholders::_2))) { - m_ECIESx25519Sessions.emplace (session->GetStaticKey (), session); + m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); } else LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); From 80373623cdd325a52c79b1528a2375752cbf25e0 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 17 Jan 2020 11:21:41 -0500 Subject: [PATCH 07/58] create payload --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 45 ++++++++++++++++++++--- libi2pd/ECIESX25519AEADRatchetSession.h | 9 +++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index ff40bef1..49077ef7 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -15,7 +15,6 @@ namespace garlic ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): GarlicRoutingSession (owner, true) { - m_EphemeralKeys.GenerateKeys (); // TODO : use precalculated hashes static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes SHA256 ((const uint8_t *)protocolName, 40, m_H); @@ -86,7 +85,8 @@ namespace garlic return false; } if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext) - + m_State = eSessionStateNewSessionReceived; + HandlePayload (payload.data (), len - 16, handleClove); return true; @@ -130,6 +130,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { + m_EphemeralKeys.GenerateKeys (); // we are Alice, bpk is m_RemoteStaticKey size_t offset = 0; if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) @@ -170,10 +171,44 @@ namespace garlic } std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) - { - // TODO: - return nullptr; + { + auto m = NewI2NPMessage (); + m->Align (12); // in order to get buf aligned to 16 (12 + 4) + uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length + auto payload = CreatePayload (msg); + size_t len = payload.size (); + + switch (m_State) + { + case eSessionStateNew: + if (!NewOutgoingSessionMessage (payload.data (), payload.size (), buf, m->maxLen)) + return nullptr; + len += 96; + break; + default: + return nullptr; + } + + htobe32buf (m->GetPayload (), len); + m->len += len + 4; + m->FillI2NPMessageHeader (eI2NPGarlic); + return m; } + + std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) + { + uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1; + std::vector v(cloveSize + 3); + uint8_t * payload = v.data (); + payload[0] = eECIESx25519BlkGalicClove; // clove type + htobe16buf (payload + 1, cloveSize); // size + payload[3] = 0; // flag and delivery instructions + payload[4] = msg->GetTypeID (); // I2NP msg type + htobe32buf (payload + 5, msg->GetMsgID ()); // msgID + htobe32buf (payload + 9, msg->GetExpiration ()/1000); // expiration in seconds + memcpy (payload + 13, msg->GetPayload (), msg->GetPayloadLength ()); + return v; + } } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index fd0658a5..0689ed5b 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "Identity.h" #include "Crypto.h" #include "Garlic.h" @@ -25,6 +26,12 @@ namespace garlic class ECIESX25519AEADRatchetSession: public GarlicRoutingSession { + enum SessionState + { + eSessionStateNew =0, + eSessionStateNewSessionReceived + }; + public: typedef std::function CloveHandler; @@ -45,11 +52,13 @@ namespace garlic void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + std::vector CreatePayload (std::shared_ptr msg); private: uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; i2p::crypto::X25519Keys m_EphemeralKeys; + SessionState m_State = eSessionStateNew; }; } } From 62e39ddfbdbcb8c1f3d1cabbf416f0e0e978ac57 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 17 Jan 2020 14:11:15 -0500 Subject: [PATCH 08/58] new session reply --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 73 ++++++++++++++++++++++- libi2pd/ECIESX25519AEADRatchetSession.h | 2 + 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 49077ef7..36d8af43 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -34,7 +34,16 @@ namespace garlic SHA256_Update (&ctx, buf, len); SHA256_Final (m_H, &ctx); } - + + void ECIESX25519AEADRatchetSession::DHInitialize (const uint8_t * rootKey, const uint8_t * k, uint8_t * nextRootKey, uint8_t * ck) + { + uint8_t keydata[64]; + i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64) + memcpy (nextRootKey, keydata, 32); // nextRootKey = keydata[0:31] + i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", ck); + // ck = [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) + } + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; @@ -165,11 +174,66 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; } - MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) + MixHash (out + offset, 16); // h = SHA256(h || ciphertext) return true; } + bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) + { + m_EphemeralKeys.GenerateKeys (); + // we are Bob + uint8_t tagsetKey[32], ck[64]; + i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) + DHInitialize (m_CK, tagsetKey, tagsetKey, ck); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey), nextRootKey? + // Session Tag Ratchet + uint8_t keydata[64]; + i2p::crypto::HKDF (ck, nullptr, 0, "STInitialization", keydata); // keydata = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) + // sessTag_chainKey = keydata[0:31], SESSTAG_CONSTANT = keydata[32:63] + i2p::crypto::HKDF (keydata, keydata + 32, 32, "SessionTagKeyGen", keydata); // keydata_0 = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) + // tag_0 = keydata_0[32:39] + uint8_t * tag = keydata + 32; + + size_t offset = 0; + memcpy (out + offset, tag, 8); + offset += 8; + if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) // bepk + { + LogPrint (eLogError, "Garlic: Can't encode elligator"); + return false; + } + offset += 32; + // KDF for Reply Key Section + MixHash (tag, 8); // h = SHA256(h || tag) + MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) + uint8_t sharedSecret[32]; + m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, aepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + uint8_t nonce[12]; + memset (nonce, 0, 12); // n = 0 + // calulate hash for zero length + if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) + { + LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); + return false; + } + MixHash (out + offset, 16); // h = SHA256(h || ciphertext) + out += 16; + // KDF for payload + i2p::crypto::HKDF (m_CK, nullptr, 0, "STInitialization", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) + // k_ab = keydata[0:31], k_ba = keydata[32:63] + // tagset_ab = DH_INITIALIZE(chainKey, k_ab), tagset_ba = DH_INITIALIZE(chainKey, k_ba) + i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) + // encrypt payload + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); + return false; + } + + return true; + } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { auto m = NewI2NPMessage (); @@ -185,6 +249,11 @@ namespace garlic return nullptr; len += 96; break; + case eSessionStateNewSessionReceived: + if (!NewSessionReplyMessage (payload.data (), payload.size (), buf, m->maxLen)) + return nullptr; + len += 72; + break; default: return nullptr; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 0689ed5b..4ff6623f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -48,10 +48,12 @@ namespace garlic private: void MixHash (const uint8_t * buf, size_t len); + void DHInitialize (const uint8_t * rootKey, const uint8_t * k, uint8_t * nextRootKey, uint8_t * ck); // ck is 64 buytes void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); std::vector CreatePayload (std::shared_ptr msg); private: From 6cc388c1bc5f2fdb0c5880b72b616a0206eec98c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 18 Jan 2020 14:43:36 -0500 Subject: [PATCH 09/58] use HKDF for MixKey --- libi2pd/NTCP2.cpp | 27 ++++++++++----------------- libi2pd/NTCP2.h | 4 ++-- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e2c4ae43..664b917b 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -41,15 +41,8 @@ namespace transport void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial) { - // temp_key = HMAC-SHA256(ck, input_key_material) - uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) - static uint8_t one[1] = { 1 }; - HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, m_K, &len); + i2p::crypto::HKDF (m_CK, inputKeyMaterial, 32, "", m_CK); + // ck is m_CK[0:31], k is m_CK[32:63] } void NTCP2Establisher::MixHash (const uint8_t * buf, size_t len) @@ -181,7 +174,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt } void NTCP2Establisher::CreateSessionCreatedMessage () @@ -204,7 +197,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt } @@ -217,7 +210,7 @@ namespace transport MixHash (m_SessionCreatedBuffer + 64, paddingLength); // part1 48 bytes - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt } void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) @@ -228,7 +221,7 @@ namespace transport // encrypt m3p2, it must be filled in SessionRequest KDF3Alice (); uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; - i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2, m3p2Len, true); // encrypt // update h again MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext) } @@ -246,7 +239,7 @@ namespace transport // verify MAC and decrypt options block (32 bytes), use m_H as AD uint8_t nonce[12], options[16]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, GetH (), 32, GetK (), nonce, options, 16, false)) // decrypt { // options if (options[0] && options[0] != i2p::context.GetNetID ()) @@ -301,7 +294,7 @@ namespace transport uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, GetH (), 32, GetK (), nonce, payload, 16, false)) // decrypt { // options paddingLen = bufbe16toh(payload + 2); @@ -330,7 +323,7 @@ namespace transport if (paddingLength > 0) MixHash (m_SessionCreatedBuffer + 64, paddingLength); - if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S + if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, GetH (), 32, GetK (), nonce, m_RemoteStaticKey, 32, false)) // decrypt S { LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); return false; @@ -344,7 +337,7 @@ namespace transport MixHash (m_SessionConfirmedBuffer, 48); KDF3Bob (); - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt { // caclulate new h again for KDF data memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c66ff697..93f6a1cc 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -85,7 +85,7 @@ namespace transport const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set - const uint8_t * GetK () const { return m_K; }; + const uint8_t * GetK () const { return m_CK + 32; }; const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetH () const { return m_H; }; @@ -114,7 +114,7 @@ namespace transport i2p::crypto::X25519Keys m_EphemeralKeys; uint8_t m_RemoteEphemeralPublicKey[32]; // x25519 - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[64] /* [ck, k]*/; i2p::data::IdentHash m_RemoteIdentHash; uint16_t m3p2Len; From eabcafa516a6e03d7480f2b4ff7e8870a4372818 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Thu, 16 Jan 2020 22:10:15 -0800 Subject: [PATCH 10/58] replace random_shuffle with shuffle random_shuffle is gone with C++17. Found and fixed with clang-tidy. --- libi2pd/Tunnel.cpp | 3 ++- libi2pd/TunnelPool.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index 66620717..00b0a12c 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -1,5 +1,6 @@ #include #include "I2PEndian.h" +#include #include #include #include @@ -45,7 +46,7 @@ namespace tunnel // shuffle records std::vector recordIndicies; for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i); - std::random_shuffle (recordIndicies.begin(), recordIndicies.end()); + std::shuffle (recordIndicies.begin(), recordIndicies.end(), std::mt19937(std::random_device()())); // create real records uint8_t * records = msg->GetPayload () + 1; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 4f740a09..7a1325fe 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -1,4 +1,5 @@ #include +#include #include "I2PEndian.h" #include "Crypto.h" #include "Tunnel.h" @@ -441,7 +442,7 @@ namespace tunnel int size = m_ExplicitPeers->size (); std::vector peerIndicies; for (int i = 0; i < size; i++) peerIndicies.push_back(i); - std::random_shuffle (peerIndicies.begin(), peerIndicies.end()); + std::shuffle (peerIndicies.begin(), peerIndicies.end(), std::mt19937(std::random_device()())); int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; for (int i = 0; i < numHops; i++) From 8b49a5544284562a2a1082ae332ecb58578182c3 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 20 Jan 2020 15:17:38 -0500 Subject: [PATCH 11/58] ratchet tagsets --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 52 ++++++++++++++--------- libi2pd/ECIESX25519AEADRatchetSession.h | 15 ++++++- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 36d8af43..7548603c 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -12,6 +12,29 @@ namespace i2p namespace garlic { + void RatchetTagSet::DHInitialize (const uint8_t * rootKey, const uint8_t * k) + { + // DH_INITIALIZE(rootKey, k) + uint8_t keydata[64]; + i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64) + // nextRootKey = keydata[0:31] + i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_CK); + // ck = [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) + } + + void RatchetTagSet::NextSessionTagRatchet () + { + i2p::crypto::HKDF (m_CK, nullptr, 0, "STInitialization", m_CK); // [ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) + memcpy (m_SessTagConstant, m_CK + 32, 32); + } + + const uint8_t * RatchetTagSet::GetNextSessionTag () + { + i2p::crypto::HKDF (m_CK, m_SessTagConstant, 32, "SessionTagKeyGen", m_CK); // [ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) + return m_CK + 32; + } + + ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): GarlicRoutingSession (owner, true) { @@ -35,15 +58,6 @@ namespace garlic SHA256_Final (m_H, &ctx); } - void ECIESX25519AEADRatchetSession::DHInitialize (const uint8_t * rootKey, const uint8_t * k, uint8_t * nextRootKey, uint8_t * ck) - { - uint8_t keydata[64]; - i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64) - memcpy (nextRootKey, keydata, 32); // nextRootKey = keydata[0:31] - i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", ck); - // ck = [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) - } - bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; @@ -183,16 +197,14 @@ namespace garlic { m_EphemeralKeys.GenerateKeys (); // we are Bob - uint8_t tagsetKey[32], ck[64]; + uint8_t tagsetKey[32]; i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) - DHInitialize (m_CK, tagsetKey, tagsetKey, ck); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey), nextRootKey? + // Session Tag Ratchet - uint8_t keydata[64]; - i2p::crypto::HKDF (ck, nullptr, 0, "STInitialization", keydata); // keydata = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) - // sessTag_chainKey = keydata[0:31], SESSTAG_CONSTANT = keydata[32:63] - i2p::crypto::HKDF (keydata, keydata + 32, 32, "SessionTagKeyGen", keydata); // keydata_0 = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) - // tag_0 = keydata_0[32:39] - uint8_t * tag = keydata + 32; + RatchetTagSet tagsetNsr; + tagsetNsr.DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey) + tagsetNsr.NextSessionTagRatchet (); + auto tag = tagsetNsr.GetNextSessionTag (); size_t offset = 0; memcpy (out + offset, tag, 8); @@ -220,9 +232,11 @@ namespace garlic MixHash (out + offset, 16); // h = SHA256(h || ciphertext) out += 16; // KDF for payload - i2p::crypto::HKDF (m_CK, nullptr, 0, "STInitialization", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) + uint8_t keydata[64]; + i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) // k_ab = keydata[0:31], k_ba = keydata[32:63] - // tagset_ab = DH_INITIALIZE(chainKey, k_ab), tagset_ba = DH_INITIALIZE(chainKey, k_ba) + m_TagsetAB.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) + m_TagsetBA.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 4ff6623f..b449c0e5 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -13,6 +13,19 @@ namespace i2p { namespace garlic { + class RatchetTagSet + { + public: + + void DHInitialize (const uint8_t * rootKey, const uint8_t * k); + void NextSessionTagRatchet (); + const uint8_t * GetNextSessionTag (); + + private: + + uint8_t m_CK[64], m_SessTagConstant[32]; + }; + enum ECIESx25519BlockType { eECIESx25519BlkDateTime = 0, @@ -48,7 +61,6 @@ namespace garlic private: void MixHash (const uint8_t * buf, size_t len); - void DHInitialize (const uint8_t * rootKey, const uint8_t * k, uint8_t * nextRootKey, uint8_t * ck); // ck is 64 buytes void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); @@ -61,6 +73,7 @@ namespace garlic uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; + RatchetTagSet m_TagsetAB, m_TagsetBA; }; } } From f498fabd27dd805d1d52640d472e5cdb05406043 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 10:52:51 -0500 Subject: [PATCH 12/58] fix for openssl 1.1 --- tests/test-x25519.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test-x25519.cpp b/tests/test-x25519.cpp index 9f249dbd..2ab8ad6a 100644 --- a/tests/test-x25519.cpp +++ b/tests/test-x25519.cpp @@ -27,10 +27,13 @@ uint8_t p[32] = int main () { +#if !OPENSSL_X25519 +// we test it for openssl < 1.1.0 uint8_t buf[32]; BN_CTX * ctx = BN_CTX_new (); i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx); BN_CTX_free (ctx); assert(memcmp (buf, p, 32) == 0); +#endif } From 0e666e7d6a65d4b51bf64876e38dc02d2b36b4cc Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 10:53:11 -0500 Subject: [PATCH 13/58] encoding fail test --- tests/test-elligator.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test-elligator.cpp b/tests/test-elligator.cpp index 94798e80..e73eb8ab 100644 --- a/tests/test-elligator.cpp +++ b/tests/test-elligator.cpp @@ -58,6 +58,12 @@ const uint8_t key3[32] = 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; +const uint8_t failed_key[32] = +{ + 0xe6, 0xf6, 0x6f, 0xdf, 0x6e, 0x23, 0x0c, 0x60, 0x3c, 0x5e, 0x6e, 0x59, 0xa2, 0x54, 0xea, 0x14, + 0x76, 0xa1, 0x3e, 0xb9, 0x51, 0x1b, 0x95, 0x49, 0x84, 0x67, 0x81, 0xe1, 0x2e, 0x52, 0x23, 0x0a +}; + int main () { uint8_t buf[32]; @@ -74,4 +80,6 @@ int main () assert(memcmp (buf, key2, 32) == 0); el.Decode (encoded3, buf); assert(memcmp (buf, key3, 32) == 0); + // encoding fails + assert (!el.Encode (failed_key, buf)); } From f497a74ec4a0321d5b4e51b87d808923174f67b1 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 12:18:31 -0500 Subject: [PATCH 14/58] set random two highest bits --- libi2pd/Elligator.cpp | 13 ++++++++++--- libi2pd/Elligator.h | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libi2pd/Elligator.cpp b/libi2pd/Elligator.cpp index b9471512..bd9c382f 100644 --- a/libi2pd/Elligator.cpp +++ b/libi2pd/Elligator.cpp @@ -1,3 +1,4 @@ +#include #include "Crypto.h" #include "Elligator.h" @@ -39,8 +40,8 @@ namespace crypto BN_free (u); BN_free (iu); } - bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY) const - { + bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded) const + { bool ret = true; BN_CTX * ctx = BN_CTX_new (); BN_CTX_start (ctx); @@ -61,7 +62,11 @@ namespace crypto BN_mod_mul (uxxA, uxxA, xA, p, ctx); if (Legendre (uxxA, ctx) != -1) - { + { + uint8_t randByte; // random highest bits and high y + RAND_bytes (&randByte, 1); + bool highY = randByte & 0x01; + BIGNUM * r = BN_CTX_get (ctx); if (highY) { @@ -78,6 +83,7 @@ namespace crypto SquareRoot (r, r, ctx); bn2buf (r, encoded, 32); + encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte for (size_t i = 0; i < 16; i++) // To Little Endian { uint8_t tmp = encoded[i]; @@ -105,6 +111,7 @@ namespace crypto encoded1[i] = encoded[31 - i]; encoded1[31 - i] = encoded[i]; } + encoded1[0] &= 0x3F; // drop two highest bits BIGNUM * r = BN_CTX_get (ctx); BN_bin2bn (encoded1, 32, r); diff --git a/libi2pd/Elligator.h b/libi2pd/Elligator.h index ca463568..6f9eaf2a 100644 --- a/libi2pd/Elligator.h +++ b/libi2pd/Elligator.h @@ -17,7 +17,7 @@ namespace crypto Elligator2 (); ~Elligator2 (); - bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false) const; + bool Encode (const uint8_t * key, uint8_t * encoded) const; bool Decode (const uint8_t * encoded, uint8_t * key) const; private: From ccec3376ba0be9621306593c90986a546d14104e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 12:19:20 -0500 Subject: [PATCH 15/58] try another ephemeral keys if elligator encoding failes --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 19 ++++++++++++++----- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 7548603c..1dacdfcc 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -58,6 +58,17 @@ namespace garlic SHA256_Final (m_H, &ctx); } + bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf) + { + for (int i = 0; i < 5; i++) + { + m_EphemeralKeys.GenerateKeys (); + if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), buf)) + return true; // success + } + return false; + } + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; @@ -152,11 +163,10 @@ namespace garlic } bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) - { - m_EphemeralKeys.GenerateKeys (); + { // we are Alice, bpk is m_RemoteStaticKey size_t offset = 0; - if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) + if (!GenerateEphemeralKeysAndEncode (out + offset)) { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; @@ -195,7 +205,6 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { - m_EphemeralKeys.GenerateKeys (); // we are Bob uint8_t tagsetKey[32]; i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) @@ -209,7 +218,7 @@ namespace garlic size_t offset = 0; memcpy (out + offset, tag, 8); offset += 8; - if (!i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), out + offset)) // bepk + if (!GenerateEphemeralKeysAndEncode (out + offset)) // bepk { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b449c0e5..32a9a89f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -61,6 +61,7 @@ namespace garlic private: void MixHash (const uint8_t * buf, size_t len); + bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); From 6142e9325293f60614511d6886c65f8ebc13a805 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 14:40:23 -0500 Subject: [PATCH 16/58] session tag for ECIESx25519 sessions --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 51 ++++++++++++++--------- libi2pd/ECIESX25519AEADRatchetSession.h | 19 +++++++-- libi2pd/Garlic.cpp | 33 ++++++++++++--- libi2pd/Garlic.h | 4 +- 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 1dacdfcc..e3f3d974 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -18,20 +18,20 @@ namespace garlic uint8_t keydata[64]; i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64) // nextRootKey = keydata[0:31] - i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_CK); - // ck = [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) + i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf); + // [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) } void RatchetTagSet::NextSessionTagRatchet () { - i2p::crypto::HKDF (m_CK, nullptr, 0, "STInitialization", m_CK); // [ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) - memcpy (m_SessTagConstant, m_CK + 32, 32); + i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), nullptr, 0, "STInitialization", m_KeyData.buf); // [sessTag_ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) + memcpy (m_SessTagConstant, m_KeyData.GetSessTagConstant (), 32); } - const uint8_t * RatchetTagSet::GetNextSessionTag () + uint64_t RatchetTagSet::GetNextSessionTag () { - i2p::crypto::HKDF (m_CK, m_SessTagConstant, 32, "SessionTagKeyGen", m_CK); // [ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) - return m_CK + 32; + i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) + return m_KeyData.GetTag (); } @@ -60,7 +60,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf) { - for (int i = 0; i < 5; i++) + for (int i = 0; i < 10; i++) { m_EphemeralKeys.GenerateKeys (); if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), buf)) @@ -69,6 +69,17 @@ namespace garlic return false; } + uint64_t ECIESX25519AEADRatchetSession::CreateNewSessionTag () const + { + uint8_t tagsetKey[32]; + i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) + // Session Tag Ratchet + RatchetTagSet tagsetNsr; + tagsetNsr.DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey) + tagsetNsr.NextSessionTagRatchet (); + return tagsetNsr.GetNextSessionTag (); + } + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; @@ -199,24 +210,20 @@ namespace garlic return false; } MixHash (out + offset, 16); // h = SHA256(h || ciphertext) - + + if (GetOwner ()) + GetOwner ()->AddECIESx25519SessionTag (CreateNewSessionTag (), shared_from_this ()); + return true; } bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { // we are Bob - uint8_t tagsetKey[32]; - i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) - - // Session Tag Ratchet - RatchetTagSet tagsetNsr; - tagsetNsr.DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey) - tagsetNsr.NextSessionTagRatchet (); - auto tag = tagsetNsr.GetNextSessionTag (); + uint64_t tag = CreateNewSessionTag (); size_t offset = 0; - memcpy (out + offset, tag, 8); + memcpy (out + offset, &tag, 8); offset += 8; if (!GenerateEphemeralKeysAndEncode (out + offset)) // bepk { @@ -225,7 +232,7 @@ namespace garlic } offset += 32; // KDF for Reply Key Section - MixHash (tag, 8); // h = SHA256(h || tag) + MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, aepk) @@ -257,6 +264,12 @@ namespace garlic return true; } + bool ECIESX25519AEADRatchetSession::NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) + { + // TODO + return true; + } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { auto m = NewI2NPMessage (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 32a9a89f..829f0517 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "Identity.h" #include "Crypto.h" @@ -19,11 +20,21 @@ namespace garlic void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void NextSessionTagRatchet (); - const uint8_t * GetNextSessionTag (); + uint64_t GetNextSessionTag (); private: + + union + { + uint64_t ll[8]; + uint8_t buf[64]; - uint8_t m_CK[64], m_SessTagConstant[32]; + const uint8_t * GetSessTagCK () const { return buf; }; // sessTag_chainKey = keydata[0:31] + const uint8_t * GetSessTagConstant () const { return buf + 32; }; // SESSTAG_CONSTANT = keydata[32:63] + uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39] + + } m_KeyData; + uint8_t m_SessTagConstant[32]; }; enum ECIESx25519BlockType @@ -37,7 +48,7 @@ namespace garlic eECIESx25519BlkPadding = 254 }; - class ECIESX25519AEADRatchetSession: public GarlicRoutingSession + class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this { enum SessionState { @@ -55,6 +66,7 @@ namespace garlic std::shared_ptr WrapSingleMessage (std::shared_ptr msg); bool NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); + bool NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } @@ -62,6 +74,7 @@ namespace garlic void MixHash (const uint8_t * buf, size_t len); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes + uint64_t CreateNewSessionTag () const; void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index fc8a4f01..4e9f3d2c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -861,14 +861,32 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { - auto session = std::make_shared (this); - if (session->NewIncomingSession (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, - this, std::placeholders::_1, std::placeholders::_2))) + auto handleClove = std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, + this, std::placeholders::_1, std::placeholders::_2); + uint64_t tag; + memcpy (&tag, buf, 8); + auto it = m_ECIESx25519Tags.find (tag); + if (it != m_ECIESx25519Tags.end ()) { - m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); + // TODO + auto session = it->second; + if (!session->NewOutgoingSessionReply (buf, len, handleClove)) + { + LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session reply"); + m_ECIESx25519Tags.erase (tag); + m_ECIESx25519Sessions.erase (session->GetRemoteStaticKey ()); + } } else - LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); + { + auto session = std::make_shared (this); + if (session->NewIncomingSession (buf, len, handleClove)) + { + m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); + } + else + LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); + } } void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) @@ -926,5 +944,10 @@ namespace garlic LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); } } + + void GarlicDestination::AddECIESx25519SessionTag (uint64_t tag, ECIESX25519AEADRatchetSessionPtr session) + { + m_ECIESx25519Tags.emplace (tag, session); + } } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 727b4a8d..fa37bf66 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -217,6 +217,7 @@ namespace garlic void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID); + void AddECIESx25519SessionTag (uint64_t tag, ECIESX25519AEADRatchetSessionPtr session); virtual void ProcessGarlicMessage (std::shared_ptr msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); @@ -252,9 +253,10 @@ namespace garlic int m_NumTags; std::mutex m_SessionsMutex; std::map m_Sessions; - std::map, ECIESX25519AEADRatchetSessionPtr > m_ECIESx25519Sessions; // static key -> session + std::map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session // incoming std::map > m_Tags; + std::map m_ECIESx25519Tags; // session tag -> session // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::map m_DeliveryStatusSessions; // msgID -> session From 0d2d7e5e716ab0a1a9da1b1595890a43444b561b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 17:53:48 -0500 Subject: [PATCH 17/58] fixed Elligator tests --- libi2pd/Elligator.cpp | 18 +++++++++++------- libi2pd/Elligator.h | 2 +- tests/test-elligator.cpp | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libi2pd/Elligator.cpp b/libi2pd/Elligator.cpp index bd9c382f..48a5a7ac 100644 --- a/libi2pd/Elligator.cpp +++ b/libi2pd/Elligator.cpp @@ -40,7 +40,7 @@ namespace crypto BN_free (u); BN_free (iu); } - bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded) const + bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, bool random) const { bool ret = true; BN_CTX * ctx = BN_CTX_new (); @@ -63,10 +63,13 @@ namespace crypto if (Legendre (uxxA, ctx) != -1) { - uint8_t randByte; // random highest bits and high y - RAND_bytes (&randByte, 1); - bool highY = randByte & 0x01; - + uint8_t randByte = 0; // random highest bits and high y + if (random) + { + RAND_bytes (&randByte, 1); + highY = randByte & 0x01; + } + BIGNUM * r = BN_CTX_get (ctx); if (highY) { @@ -82,8 +85,9 @@ namespace crypto SquareRoot (r, r, ctx); bn2buf (r, encoded, 32); - - encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte + + if (random) + encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte for (size_t i = 0; i < 16; i++) // To Little Endian { uint8_t tmp = encoded[i]; diff --git a/libi2pd/Elligator.h b/libi2pd/Elligator.h index 6f9eaf2a..7cdcbbfe 100644 --- a/libi2pd/Elligator.h +++ b/libi2pd/Elligator.h @@ -17,7 +17,7 @@ namespace crypto Elligator2 (); ~Elligator2 (); - bool Encode (const uint8_t * key, uint8_t * encoded) const; + bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false, bool random = true) const; bool Decode (const uint8_t * encoded, uint8_t * key) const; private: diff --git a/tests/test-elligator.cpp b/tests/test-elligator.cpp index e73eb8ab..48c9e31a 100644 --- a/tests/test-elligator.cpp +++ b/tests/test-elligator.cpp @@ -69,9 +69,9 @@ int main () uint8_t buf[32]; i2p::crypto::Elligator2 el; // encoding tests - el.Encode (key, buf); + el.Encode (key, buf, false, false); assert(memcmp (buf, encoded_key, 32) == 0); - el.Encode (key, buf, true); // with highY + el.Encode (key, buf, true, false); // with highY assert(memcmp (buf, encoded_key_high_y, 32) == 0); // decoding tests el.Decode (encoded1, buf); From 2b2bd733e9c9e63cd649324b358ca88c93ebad5e Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 19:13:23 -0500 Subject: [PATCH 18/58] correct sharedkey for new outgoing session --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index e3f3d974..ece3ec1e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -188,7 +188,7 @@ namespace garlic MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk) MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; - m_EphemeralKeys.Agree (m_RemoteStaticKey, nullptr); // x25519(aesk, bpk) + m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) // encrypt static key section uint8_t nonce[12]; From 09c6c2a4f36dbdbc2b77400b404819780587091f Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 21 Jan 2020 21:09:19 -0500 Subject: [PATCH 19/58] decode aepk and bepk back --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index ece3ec1e..624a2f7f 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -181,12 +181,14 @@ namespace garlic { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; - } + } + uint8_t aepk[32]; + i2p::crypto::GetElligator ()->Decode (out + offset, aepk); // decode back for h offset += 32; // KDF1 MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk) - MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk) + MixHash (aepk, 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) @@ -229,11 +231,13 @@ namespace garlic { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; - } + } + uint8_t bepk[32]; + i2p::crypto::GetElligator ()->Decode (out + offset, bepk); // decode back for h offset += 32; // KDF for Reply Key Section MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) - MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) + MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, aepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) From 928b90d5bc104ae56136962f7f2dbbd99c202385 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2020 09:50:50 -0500 Subject: [PATCH 20/58] fixed #1461. Use openssl's HKDF for 1.1.1 anf higher --- libi2pd/Crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 33490c8a..2a0a8427 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -27,8 +27,8 @@ # define X509_getm_notAfter X509_get_notAfter #else # define LEGACY_OPENSSL 0 -# define OPENSSL_HKDF 1 # if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 +# define OPENSSL_HKDF 1 # define OPENSSL_EDDSA 1 # define OPENSSL_X25519 1 # define OPENSSL_SIPHASH 1 From 76f95644b7985c11f713cb48482aee32008887de Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2020 09:59:08 -0500 Subject: [PATCH 21/58] fixed #1461. Use openssl's HKDF for 1.1.1 anf higher --- libi2pd/Crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 2a0a8427..32410daf 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -28,7 +28,7 @@ #else # define LEGACY_OPENSSL 0 # if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 -# define OPENSSL_HKDF 1 +# define OPENSSL_HKDF 1 # define OPENSSL_EDDSA 1 # define OPENSSL_X25519 1 # define OPENSSL_SIPHASH 1 From 7c212bef63358cb3780ee16b38526b009011c86d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2020 11:27:47 -0500 Subject: [PATCH 22/58] add new session to the list after reply received --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 12 ++++-------- libi2pd/Garlic.cpp | 5 +++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 624a2f7f..74443e5e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -181,14 +181,12 @@ namespace garlic { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; - } - uint8_t aepk[32]; - i2p::crypto::GetElligator ()->Decode (out + offset, aepk); // decode back for h + } offset += 32; // KDF1 MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk) - MixHash (aepk, 32); // h = SHA256(h || aepk) + MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) @@ -231,13 +229,11 @@ namespace garlic { LogPrint (eLogError, "Garlic: Can't encode elligator"); return false; - } - uint8_t bepk[32]; - i2p::crypto::GetElligator ()->Decode (out + offset, bepk); // decode back for h + } offset += 32; // KDF for Reply Key Section MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) - MixHash (bepk, 32); // h = SHA256(h || bepk) + MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, aepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 4e9f3d2c..833817f7 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -668,7 +668,6 @@ namespace garlic { session = std::make_shared (this); session->SetRemoteStaticKey (staticKey); - m_ECIESx25519Sessions.emplace (staticKey, session); } return session; } @@ -870,7 +869,9 @@ namespace garlic { // TODO auto session = it->second; - if (!session->NewOutgoingSessionReply (buf, len, handleClove)) + if (session->NewOutgoingSessionReply (buf, len, handleClove)) + m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); + else { LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session reply"); m_ECIESx25519Tags.erase (tag); From 34295adb05f10386fad0f72ab4b925091c314533 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2020 14:26:47 -0500 Subject: [PATCH 23/58] attach LeaseSet clove --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 40 ++++++++++++++++------- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 74443e5e..285eaa7e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -302,18 +302,36 @@ namespace garlic std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) { - uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1; - std::vector v(cloveSize + 3); - uint8_t * payload = v.data (); - payload[0] = eECIESx25519BlkGalicClove; // clove type - htobe16buf (payload + 1, cloveSize); // size - payload[3] = 0; // flag and delivery instructions - payload[4] = msg->GetTypeID (); // I2NP msg type - htobe32buf (payload + 5, msg->GetMsgID ()); // msgID - htobe32buf (payload + 9, msg->GetExpiration ()/1000); // expiration in seconds - memcpy (payload + 13, msg->GetPayload (), msg->GetPayloadLength ()); + size_t payloadLen = 0; + if (payloadLen) + payloadLen += msg->GetPayloadLength () + 13; + auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); + if (leaseSet) + payloadLen += leaseSet->GetPayloadLength () + 13; + std::vector v(payloadLen); + size_t offset = 0; + if (leaseSet) + offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset); + if (msg) + offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset); return v; - } + } + + size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len) + { + if (!msg) return 0; + uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1; + if ((int)len < cloveSize + 3) return 0; + buf[0] = eECIESx25519BlkGalicClove; // clove type + htobe16buf (buf + 1, cloveSize); // size + buf[3] = 0; // flag and delivery instructions + buf[4] = msg->GetTypeID (); // I2NP msg type + htobe32buf (buf + 5, msg->GetMsgID ()); // msgID + htobe32buf (buf + 9, msg->GetExpiration ()/1000); // expiration in seconds + memcpy (buf + 13, msg->GetPayload (), msg->GetPayloadLength ()); + return cloveSize + 3; + } + } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 829f0517..05dfc961 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -81,6 +81,7 @@ namespace garlic bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); std::vector CreatePayload (std::shared_ptr msg); + size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len); private: From 205e807b6645466018d13b769e5f7604784daf4e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Jan 2020 21:42:30 -0500 Subject: [PATCH 24/58] reset keys --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 21 ++++++++++++++------- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 285eaa7e..1276ef3e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -38,17 +38,22 @@ namespace garlic ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): GarlicRoutingSession (owner, true) { - // TODO : use precalculated hashes - static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes - SHA256 ((const uint8_t *)protocolName, 40, m_H); - memcpy (m_CK, m_H, 32); - SHA256 (m_H, 32, m_H); + ResetKeys (); } ECIESX25519AEADRatchetSession::~ECIESX25519AEADRatchetSession () { } + void ECIESX25519AEADRatchetSession::ResetKeys () + { + // TODO : use precalculated hashes + static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes + SHA256 ((const uint8_t *)protocolName, 40, m_H); + memcpy (m_CK, m_H, 32); + SHA256 (m_H, 32, m_H); + } + void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len) { SHA256_CTX ctx; @@ -175,6 +180,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { + ResetKeys (); // we are Alice, bpk is m_RemoteStaticKey size_t offset = 0; if (!GenerateEphemeralKeysAndEncode (out + offset)) @@ -266,7 +272,8 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) { - // TODO + // TODO + LogPrint (eLogDebug, "Garlic: reply received"); return true; } @@ -303,7 +310,7 @@ namespace garlic std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) { size_t payloadLen = 0; - if (payloadLen) + if (msg) payloadLen += msg->GetPayloadLength () + 13; auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); if (leaseSet) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 05dfc961..5777885b 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -72,6 +72,7 @@ namespace garlic private: + void ResetKeys (); void MixHash (const uint8_t * buf, size_t len); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes uint64_t CreateNewSessionTag () const; From fd1ee48dbe7e41ab15448f1369d2f9802a5a0778 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Jan 2020 14:26:40 -0500 Subject: [PATCH 25/58] datetime and padding blocks --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 1276ef3e..29171584 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -5,6 +5,7 @@ #include "Elligator.h" #include "Tag.h" #include "I2PEndian.h" +#include "Timestamp.h" #include "ECIESX25519AEADRatchetSession.h" namespace i2p @@ -309,18 +310,32 @@ namespace garlic std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) { - size_t payloadLen = 0; + size_t payloadLen = 7; // datatime if (msg) payloadLen += msg->GetPayloadLength () + 13; auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); if (leaseSet) - payloadLen += leaseSet->GetPayloadLength () + 13; + payloadLen += leaseSet->GetPayloadLength () + 13; + uint8_t paddingSize; + RAND_bytes (&paddingSize, 1); + paddingSize &= 0x0F; paddingSize++; // 1 - 16 + payloadLen += paddingSize; std::vector v(payloadLen); size_t offset = 0; + // DateTime + v[offset] = eECIESx25519BlkDateTime; offset++; + htobe16buf (v.data () + offset, 4); offset += 2; + htobe32buf (v.data () + offset, i2p::util::GetSecondsSinceEpoch ()); offset += 4; + // LeaseSet if (leaseSet) offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset); + // msg if (msg) offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset); + // padding + v[offset] = eECIESx25519BlkPadding; offset++; + htobe16buf (v.data () + offset, paddingSize); offset += 2; + memset (v.data () + offset, 0, paddingSize); offset += paddingSize; return v; } From 77440c235d24988720009c1bf1d30462ccae5900 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2020 10:03:51 -0500 Subject: [PATCH 26/58] replaced map by unordered_map --- libi2pd/Garlic.h | 12 ++++++------ libi2pd/Tag.h | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index fa37bf66..e3b090cb 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -2,7 +2,7 @@ #define GARLIC_H__ #include -#include +#include #include #include #include @@ -252,14 +252,14 @@ namespace garlic // outgoing sessions int m_NumTags; std::mutex m_SessionsMutex; - std::map m_Sessions; - std::map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session + std::unordered_map m_Sessions; + std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session // incoming - std::map > m_Tags; - std::map m_ECIESx25519Tags; // session tag -> session + std::unordered_map > m_Tags; + std::unordered_map m_ECIESx25519Tags; // session tag -> session // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; - std::map m_DeliveryStatusSessions; // msgID -> session + std::unordered_map m_DeliveryStatusSessions; // msgID -> session public: diff --git a/libi2pd/Tag.h b/libi2pd/Tag.h index 8af82241..010b160f 100644 --- a/libi2pd/Tag.h +++ b/libi2pd/Tag.h @@ -93,4 +93,16 @@ private: } // data } // i2p +namespace std +{ + // hash for std::unordered_map + template struct hash > + { + size_t operator()(const i2p::data::Tag& s) const + { + return s.GetLL ()[0]; + } + }; +} + #endif /* TAG_H__ */ From abe668f1c32d76fce2bb59e52dde52996e283f81 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 28 Jan 2020 10:31:35 -0500 Subject: [PATCH 27/58] fixed build error --- libi2pd/Garlic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index e3b090cb..08bbfc5b 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -255,7 +255,7 @@ namespace garlic std::unordered_map m_Sessions; std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session // incoming - std::unordered_map > m_Tags; + std::unordered_map, std::hash > > m_Tags; std::unordered_map m_ECIESx25519Tags; // session tag -> session // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; From a1dbec0fcbea8dafb9e7b4e123b028f3cc5d4f6e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2020 12:54:26 -0500 Subject: [PATCH 28/58] handle new session reply --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 47 ++++++++++++++++++++++- libi2pd/Garlic.cpp | 21 +++++----- libi2pd/Garlic.h | 1 + 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 29171584..3a732876 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -137,6 +137,7 @@ namespace garlic } if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext) m_State = eSessionStateNewSessionReceived; + GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); HandlePayload (payload.data (), len - 16, handleClove); @@ -273,8 +274,52 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) { - // TODO + // we are Alice LogPrint (eLogDebug, "Garlic: reply received"); + const uint8_t * tag = buf; + buf += 8; len -= 8; // tag + uint8_t bepk[32]; // Bob's ephemeral key + if (!i2p::crypto::GetElligator ()->Decode (buf, bepk)) + { + LogPrint (eLogError, "Garlic: Can't decode elligator"); + return false; + } + buf += 32; len -= 32; + // KDF for Reply Key Section + MixHash (tag, 8); // h = SHA256(h || tag) + MixHash (bepk, 32); // h = SHA256(h || bepk) + uint8_t sharedSecret[32]; + m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + uint8_t nonce[12]; + memset (nonce, 0, 12); // n = 0 + // calulate hash for zero length + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anyting */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only + { + LogPrint (eLogWarning, "Garlic: Reply key section AEAD decryption failed"); + return false; + } + MixHash (buf, 16); // h = SHA256(h || ciphertext) + buf += 16; len -= 16; + // KDF for payload + uint8_t keydata[64]; + i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) + // k_ab = keydata[0:31], k_ba = keydata[32:63] + m_TagsetAB.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) + m_TagsetBA.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) + // decrypt payload + std::vector payload (len - 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keydata, nonce, payload.data (), len - 16, false)) // decrypt + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); + return false; + } + + // TODO: change state + GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); + HandlePayload (payload.data (), len - 16, handleClove); + return true; } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 833817f7..b6a870f0 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -869,23 +869,14 @@ namespace garlic { // TODO auto session = it->second; - if (session->NewOutgoingSessionReply (buf, len, handleClove)) - m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); - else - { + if (!session->NewOutgoingSessionReply (buf, len, handleClove)) LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session reply"); - m_ECIESx25519Tags.erase (tag); - m_ECIESx25519Sessions.erase (session->GetRemoteStaticKey ()); - } + m_ECIESx25519Tags.erase (tag); } else { auto session = std::make_shared (this); - if (session->NewIncomingSession (buf, len, handleClove)) - { - m_ECIESx25519Sessions.emplace (session->GetRemoteStaticKey (), session); - } - else + if (!session->NewIncomingSession (buf, len, handleClove)) LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); } } @@ -950,5 +941,11 @@ namespace garlic { m_ECIESx25519Tags.emplace (tag, session); } + + void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) + { + m_ECIESx25519Sessions.emplace (staticKey, session); + } + } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 08bbfc5b..4e66f75f 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -218,6 +218,7 @@ namespace garlic virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID); void AddECIESx25519SessionTag (uint64_t tag, ECIESX25519AEADRatchetSessionPtr session); + void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); virtual void ProcessGarlicMessage (std::shared_ptr msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); From 48fa10b080168d1a8f6cdde05fdfa628b1f418c0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2020 15:54:11 -0500 Subject: [PATCH 29/58] incoming ECIESX25519AEADRatchet messages hanler --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 19 +++++++++++++++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 8 +++++--- libi2pd/Garlic.cpp | 23 ++++++++++------------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 3a732876..ffda9191 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -86,7 +86,7 @@ namespace garlic return tagsetNsr.GetNextSessionTag (); } - bool ECIESX25519AEADRatchetSession::NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) { if (!GetOwner ()) return false; // we are Bob @@ -219,6 +219,7 @@ namespace garlic } MixHash (out + offset, 16); // h = SHA256(h || ciphertext) + m_State = eSessionStateNewSessionSent; if (GetOwner ()) GetOwner ()->AddECIESx25519SessionTag (CreateNewSessionTag (), shared_from_this ()); @@ -272,7 +273,7 @@ namespace garlic return true; } - bool ECIESX25519AEADRatchetSession::NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) { // we are Alice LogPrint (eLogDebug, "Garlic: reply received"); @@ -323,6 +324,20 @@ namespace garlic return true; } + bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, CloveHandler handleClove) + { + switch (m_State) + { + case eSessionStateNew: + return HandleNewIncomingSession (buf, len, handleClove); + case eSessionStateNewSessionSent: + return HandleNewOutgoingSessionReply (buf, len, handleClove); + default: + return false; + } + return true; + } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr msg) { auto m = NewI2NPMessage (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 5777885b..b8988f6e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -53,7 +53,8 @@ namespace garlic enum SessionState { eSessionStateNew =0, - eSessionStateNewSessionReceived + eSessionStateNewSessionReceived, + eSessionStateNewSessionSent }; public: @@ -63,10 +64,9 @@ namespace garlic ECIESX25519AEADRatchetSession (GarlicDestination * owner); ~ECIESX25519AEADRatchetSession (); + bool HandleNextMessage (const uint8_t * buf, size_t len, CloveHandler handleClove); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); - bool NewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); - bool NewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } @@ -77,6 +77,8 @@ namespace garlic bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes uint64_t CreateNewSessionTag () const; + bool HandleNewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); + bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove); void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index b6a870f0..69ca0335 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -864,21 +864,18 @@ namespace garlic this, std::placeholders::_1, std::placeholders::_2); uint64_t tag; memcpy (&tag, buf, 8); + ECIESX25519AEADRatchetSessionPtr session; auto it = m_ECIESx25519Tags.find (tag); if (it != m_ECIESx25519Tags.end ()) - { - // TODO - auto session = it->second; - if (!session->NewOutgoingSessionReply (buf, len, handleClove)) - LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session reply"); - m_ECIESx25519Tags.erase (tag); - } - else - { - auto session = std::make_shared (this); - if (!session->NewIncomingSession (buf, len, handleClove)) - LogPrint (eLogError, "Garlic: can't decrypt ECIES-X25519-AEAD-Ratchet new session"); - } + { + session = it->second; + m_ECIESx25519Tags.erase (tag); + } + else + session = std::make_shared (this); // incoming + + if (!session->HandleNextMessage (buf, len, handleClove)) + LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); } void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) From cdd068d99aef58a32c155597218d54ba77e84cdf Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2020 19:27:38 -0500 Subject: [PATCH 30/58] correct message size --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index ffda9191..b6820482 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -379,7 +379,7 @@ namespace garlic uint8_t paddingSize; RAND_bytes (&paddingSize, 1); paddingSize &= 0x0F; paddingSize++; // 1 - 16 - payloadLen += paddingSize; + payloadLen += paddingSize + 3; std::vector v(payloadLen); size_t offset = 0; // DateTime @@ -395,7 +395,7 @@ namespace garlic // padding v[offset] = eECIESx25519BlkPadding; offset++; htobe16buf (v.data () + offset, paddingSize); offset += 2; - memset (v.data () + offset, 0, paddingSize); offset += paddingSize; + memset (v.data () + offset, 0, paddingSize); offset += paddingSize; return v; } From 8c800dc178109807863a0751ef6f012a8c658002 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 29 Jan 2020 21:57:10 -0500 Subject: [PATCH 31/58] save aepk from new session message --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 13 ++++++------- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index b6820482..154bec98 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -92,18 +92,17 @@ namespace garlic // we are Bob // KDF1 MixHash (GetOwner ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk) - - uint8_t aepk[32]; // Alice's ephemeral key - if (!i2p::crypto::GetElligator ()->Decode (buf, aepk)) + + if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) { LogPrint (eLogError, "Garlic: Can't decode elligator"); return false; } buf += 32; len -= 32; - MixHash (aepk, 32); // h = SHA256(h || aepk) + MixHash (m_Aepk, 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; - GetOwner ()->Decrypt (aepk, sharedSecret, nullptr); // x25519(bsk, aepk) + GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr); // x25519(bsk, aepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) // decrypt flags/static @@ -217,7 +216,7 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; } - MixHash (out + offset, 16); // h = SHA256(h || ciphertext) + MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) m_State = eSessionStateNewSessionSent; if (GetOwner ()) @@ -244,7 +243,7 @@ namespace garlic MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; - m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, aepk) + m_EphemeralKeys.Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) uint8_t nonce[12]; memset (nonce, 0, 12); // n = 0 diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index b8988f6e..f5cef114 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -89,6 +89,7 @@ namespace garlic private: uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; + uint8_t m_Aepk[32]; // Alice's ephemeral keys TODO: for incoming only i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; RatchetTagSet m_TagsetAB, m_TagsetBA; From 239c8b51720fc1a108b9dd2273c22bc465c0bd8a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2020 11:48:32 -0500 Subject: [PATCH 32/58] destination delivery instructions --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 31 +++++++++++++++-------- libi2pd/ECIESX25519AEADRatchetSession.h | 8 +++++- libi2pd/Garlic.cpp | 6 ++--- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 154bec98..b8ddf577 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -370,8 +370,8 @@ namespace garlic std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) { size_t payloadLen = 7; // datatime - if (msg) - payloadLen += msg->GetPayloadLength () + 13; + if (msg && m_Destination) + payloadLen += msg->GetPayloadLength () + 13 + 32; auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); if (leaseSet) payloadLen += leaseSet->GetPayloadLength () + 13; @@ -389,8 +389,8 @@ namespace garlic if (leaseSet) offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset); // msg - if (msg) - offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset); + if (msg && m_Destination) + offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true); // padding v[offset] = eECIESx25519BlkPadding; offset++; htobe16buf (v.data () + offset, paddingSize); offset += 2; @@ -398,18 +398,27 @@ namespace garlic return v; } - size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len) + size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len, bool isDestination) { if (!msg) return 0; uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1; + if (isDestination) cloveSize += 32; if ((int)len < cloveSize + 3) return 0; buf[0] = eECIESx25519BlkGalicClove; // clove type - htobe16buf (buf + 1, cloveSize); // size - buf[3] = 0; // flag and delivery instructions - buf[4] = msg->GetTypeID (); // I2NP msg type - htobe32buf (buf + 5, msg->GetMsgID ()); // msgID - htobe32buf (buf + 9, msg->GetExpiration ()/1000); // expiration in seconds - memcpy (buf + 13, msg->GetPayload (), msg->GetPayloadLength ()); + htobe16buf (buf + 1, cloveSize); // size + buf += 3; + if (isDestination) + { + *buf = (eGarlicDeliveryTypeDestination << 5); + memcpy (buf + 1, *m_Destination, 32); buf += 32; + } + else + *buf = 0; + buf++; // flag and delivery instructions + *buf = msg->GetTypeID (); // I2NP msg type + htobe32buf (buf + 1, msg->GetMsgID ()); // msgID + htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds + memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ()); return cloveSize + 3; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index f5cef114..ebe8cf13 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -70,6 +70,11 @@ namespace garlic const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } + void SetDestination (const i2p::data::IdentHash& dest) // TODO: + { + if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); + } + private: void ResetKeys (); @@ -84,7 +89,7 @@ namespace garlic bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); std::vector CreatePayload (std::shared_ptr msg); - size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len); + size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len, bool isDestination = false); private: @@ -93,6 +98,7 @@ namespace garlic i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; RatchetTagSet m_TagsetAB, m_TagsetBA; + std::unique_ptr m_Destination;// TODO: might not need it }; } } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 69ca0335..1b34f99c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -669,6 +669,7 @@ namespace garlic session = std::make_shared (this); session->SetRemoteStaticKey (staticKey); } + session->SetDestination (destination->GetIdentHash ()); // TODO: remove return session; } else @@ -860,8 +861,6 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { - auto handleClove = std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, - this, std::placeholders::_1, std::placeholders::_2); uint64_t tag; memcpy (&tag, buf, 8); ECIESX25519AEADRatchetSessionPtr session; @@ -874,7 +873,8 @@ namespace garlic else session = std::make_shared (this); // incoming - if (!session->HandleNextMessage (buf, len, handleClove)) + if (!session->HandleNextMessage (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, + this, std::placeholders::_1, std::placeholders::_2))) LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); } From 85b88b874915dc97bca2470c9dd032276d4b72c4 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 30 Jan 2020 19:30:30 -0500 Subject: [PATCH 33/58] second x25519 for new session reply --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index b8ddf577..11e7edad 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -244,8 +244,10 @@ namespace garlic MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) + m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) - uint8_t nonce[12]; + uint8_t nonce[12]; memset (nonce, 0, 12); // n = 0 // calulate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) @@ -290,8 +292,10 @@ namespace garlic MixHash (bepk, 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) - uint8_t nonce[12]; + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) + GetOwner ()->Decrypt (bepk, sharedSecret, nullptr); // x25519 (ask, bepk) + i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + uint8_t nonce[12]; memset (nonce, 0, 12); // n = 0 // calulate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anyting */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only From 49810eb15351d11d3f2a20d47c32d4a78cbbcb8a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 Feb 2020 17:05:30 -0500 Subject: [PATCH 34/58] common RunnableService --- libi2pd/NTCP2.cpp | 49 +++++++++++------------------------------------ libi2pd/NTCP2.h | 13 ++----------- libi2pd/util.cpp | 39 +++++++++++++++++++++++++++++++++++++ libi2pd/util.h | 38 ++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 49 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 664b917b..e79be97a 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,12 +1,10 @@ /* -* Copyright (c) 2013-2018, The PurpleI2P Project +* Copyright (c) 2013-2020, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree * -* Kovri go write your own code -* */ #include @@ -1143,8 +1141,8 @@ namespace transport } NTCP2Server::NTCP2Server (): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), - m_TerminationTimer (m_Service) + RunnableServiceWithWork ("NTCP2"), + m_TerminationTimer (GetService ()) { } @@ -1155,10 +1153,9 @@ namespace transport void NTCP2Server::Start () { - if (!m_IsRunning) + if (!IsRunning ()) { - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + StartService (); auto& addresses = context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) { @@ -1169,7 +1166,7 @@ namespace transport { try { - m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port))); + m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port))); } catch ( std::exception & ex ) { @@ -1183,7 +1180,7 @@ namespace transport } else if (address->host.is_v6() && context.SupportsV6 ()) { - m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service)); + m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ())); try { m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); @@ -1218,33 +1215,9 @@ namespace transport } m_NTCP2Sessions.clear (); - if (m_IsRunning) - { - m_IsRunning = false; + if (IsRunning ()) m_TerminationTimer.cancel (); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } - } - - void NTCP2Server::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "NTCP2: runtime exception: ", ex.what ()); - } - } + StopService (); } bool NTCP2Server::AddNTCP2Session (std::shared_ptr session, bool incoming) @@ -1282,11 +1255,11 @@ namespace transport void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); - m_Service.post([this, address, port, conn]() + GetService ().post([this, address, port, conn]() { if (this->AddNTCP2Session (conn)) { - auto timer = std::make_shared(m_Service); + auto timer = std::make_shared(GetService ()); auto timeout = NTCP2_CONNECT_TIMEOUT * 5; conn->SetTerminationTimeout(timeout * 2); timer->expires_from_now (boost::posix_time::seconds(timeout)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 93f6a1cc..a63b86b8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -1,12 +1,10 @@ /* -* Copyright (c) 2013-2018, The PurpleI2P Project +* Copyright (c) 2013-2020, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree * -* Kovri go write your own code -* */ #ifndef NTCP2_H__ #define NTCP2_H__ @@ -218,7 +216,7 @@ namespace transport std::list > m_SendQueue; }; - class NTCP2Server + class NTCP2Server: public i2p::util::RunnableServiceWithWork { public: @@ -231,14 +229,11 @@ namespace transport bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); void RemoveNTCP2Session (std::shared_ptr session); std::shared_ptr FindNTCP2Session (const i2p::data::IdentHash& ident); - - boost::asio::io_service& GetService () { return m_Service; }; void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); private: - void Run (); void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); @@ -250,10 +245,6 @@ namespace transport private: - bool m_IsRunning; - std::thread * m_Thread; - boost::asio::io_service m_Service; - boost::asio::io_service::work m_Work; boost::asio::deadline_timer m_TerminationTimer; std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; std::map > m_NTCP2Sessions; diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 448d1307..6ae9fa6b 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -57,6 +57,45 @@ namespace i2p { namespace util { + + void RunnableService::StartService () + { + if (!m_IsRunning) + { + m_IsRunning = true; + m_Thread.reset (new std::thread (std::bind (& RunnableService::Run, this))); + } + } + + void RunnableService::StopService () + { + if (m_IsRunning) + { + m_IsRunning = false; + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + m_Thread = nullptr; + } + } + } + + void RunnableService::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, m_Name, ": runtime exception: ", ex.what ()); + } + } + } + namespace net { #ifdef WIN32 diff --git a/libi2pd/util.h b/libi2pd/util.h index eccdadf7..830a984d 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -122,6 +123,43 @@ namespace util std::mutex m_Mutex; }; + class RunnableService + { + public: + + RunnableService (const std::string& name): m_Name (name), m_IsRunning (false) {} + virtual ~RunnableService () {} + + boost::asio::io_service& GetService () { return m_Service; } + bool IsRunning () const { return m_IsRunning; }; + + void StartService (); + void StopService (); + + private: + + void Run (); + + private: + + std::string m_Name; + bool m_IsRunning; + std::unique_ptr m_Thread; + boost::asio::io_service m_Service; + }; + + class RunnableServiceWithWork: public RunnableService + { + public: + + RunnableServiceWithWork (const std::string& name): + RunnableService (name), m_Work (GetService ()) {} + + private: + + boost::asio::io_service::work m_Work; + }; + namespace net { int GetMTU (const boost::asio::ip::address& localAddress); From 2d154ee640fa4028e669a031c312d362ab2e5c78 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 2 Feb 2020 18:58:58 -0500 Subject: [PATCH 35/58] move RunnableService away from LeaseSetDestination --- libi2pd/Destination.cpp | 108 ++++++++------------------ libi2pd/Destination.h | 20 ++--- libi2pd/util.h | 2 +- libi2pd_client/I2CP.cpp | 27 ++++++- libi2pd_client/I2CP.h | 9 ++- libi2pd_client/MatchedDestination.cpp | 28 +++---- libi2pd_client/MatchedDestination.h | 4 +- 7 files changed, 87 insertions(+), 111 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index ba74f61f..835c8e52 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -7,15 +7,15 @@ #include "Timestamp.h" #include "NetDb.hpp" #include "Destination.h" -#include "util.h" namespace i2p { namespace client { - LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map * params): - m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic), - m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), + LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service, + bool isPublic, const std::map * params): + m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0), + m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service), m_LeaseSetType (DEFAULT_LEASESET_TYPE), m_AuthType (i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE) { @@ -123,77 +123,36 @@ namespace client LeaseSetDestination::~LeaseSetDestination () { - if (m_IsRunning) - Stop (); if (m_Pool) i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); for (auto& it: m_LeaseSetRequests) it.second->Complete (nullptr); } - void LeaseSetDestination::Run () + void LeaseSetDestination::Start () { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "Destination: runtime exception: ", ex.what ()); - } - } + if (m_Nickname.empty ()) + m_Nickname = i2p::data::GetIdentHashAbbreviation (GetIdentHash ()); // set default nickname + LoadTags (); + m_Pool->SetLocalDestination (shared_from_this ()); + m_Pool->SetActive (true); + m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); + m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, + shared_from_this (), std::placeholders::_1)); } - bool LeaseSetDestination::Start () + void LeaseSetDestination::Stop () { - if (!m_IsRunning) + m_CleanupTimer.cancel (); + m_PublishConfirmationTimer.cancel (); + m_PublishVerificationTimer.cancel (); + if (m_Pool) { - if (m_Nickname.empty ()) - m_Nickname = i2p::data::GetIdentHashAbbreviation (GetIdentHash ()); // set default nickname - LoadTags (); - m_IsRunning = true; - m_Pool->SetLocalDestination (shared_from_this ()); - m_Pool->SetActive (true); - m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); - m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer, - shared_from_this (), std::placeholders::_1)); - m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ())); - - return true; + m_Pool->SetLocalDestination (nullptr); + i2p::tunnel::tunnels.StopTunnelPool (m_Pool); } - else - return false; - } - - bool LeaseSetDestination::Stop () - { - if (m_IsRunning) - { - m_CleanupTimer.cancel (); - m_PublishConfirmationTimer.cancel (); - m_PublishVerificationTimer.cancel (); - - m_IsRunning = false; - if (m_Pool) - { - m_Pool->SetLocalDestination (nullptr); - i2p::tunnel::tunnels.StopTunnelPool (m_Pool); - } - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = 0; - } - SaveTags (); - CleanUp (); // GarlicDestination - return true; - } - else - return false; + SaveTags (); + CleanUp (); // GarlicDestination } bool LeaseSetDestination::Reconfigure(std::map params) @@ -864,7 +823,8 @@ namespace client } ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): - LeaseSetDestination (isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), + RunnableService ("Destination"), LeaseSetDestination (GetService (), isPublic, params), + m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_DatagramDestination (nullptr), m_RefCounter (0), m_ReadyChecker(GetService()) { @@ -932,26 +892,28 @@ namespace client ClientDestination::~ClientDestination () { + if (IsRunning ()) + Stop (); } - bool ClientDestination::Start () + void ClientDestination::Start () { - if (LeaseSetDestination::Start ()) + if (!IsRunning ()) { + LeaseSetDestination::Start (); m_StreamingDestination = std::make_shared (GetSharedFromThis ()); // TODO: m_StreamingDestination->Start (); for (auto& it: m_StreamingDestinationsByPorts) it.second->Start (); - return true; + StartService (); } - else - return false; } - bool ClientDestination::Stop () + void ClientDestination::Stop () { - if (LeaseSetDestination::Stop ()) + if (IsRunning ()) { + LeaseSetDestination::Stop (); m_ReadyChecker.cancel(); m_StreamingDestination->Stop (); //m_StreamingDestination->SetOwner (nullptr); @@ -967,10 +929,8 @@ namespace client delete m_DatagramDestination; m_DatagramDestination = nullptr; } - return true; + StopService (); } - else - return false; } #ifdef I2LUA diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index f4483032..5b411c14 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -20,6 +20,7 @@ #include "NetDb.hpp" #include "Streaming.h" #include "Datagram.h" +#include "util.h" namespace i2p { @@ -98,18 +99,16 @@ namespace client public: - LeaseSetDestination (bool isPublic, const std::map * params = nullptr); + LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map * params = nullptr); ~LeaseSetDestination (); const std::string& GetNickname () const { return m_Nickname; }; - virtual bool Start (); - virtual bool Stop (); + virtual void Start (); + virtual void Stop (); /** i2cp reconfigure */ virtual bool Reconfigure(std::map i2cpOpts); - bool IsRunning () const { return m_IsRunning; }; - boost::asio::io_service& GetService () { return m_Service; }; std::shared_ptr GetTunnelPool () { return m_Pool; }; bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; }; std::shared_ptr FindLeaseSet (const i2p::data::IdentHash& ident); @@ -146,7 +145,6 @@ namespace client private: - void Run (); void UpdateLeaseSet (); std::shared_ptr GetLeaseSetMt (); void Publish (); @@ -165,9 +163,7 @@ namespace client private: - volatile bool m_IsRunning; - std::thread * m_Thread; - boost::asio::io_service m_Service; + boost::asio::io_service& m_Service; mutable std::mutex m_RemoteLeaseSetsMutex; std::map > m_RemoteLeaseSets; std::map > m_LeaseSetRequests; @@ -195,7 +191,7 @@ namespace client bool IsPerClientAuth () const { return m_AuthType > 0; }; }; - class ClientDestination: public LeaseSetDestination + class ClientDestination: public i2p::util::RunnableService, public LeaseSetDestination { public: #ifdef I2LUA @@ -209,8 +205,8 @@ namespace client ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); ~ClientDestination (); - virtual bool Start (); - virtual bool Stop (); + virtual void Start (); + virtual void Stop (); const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; diff --git a/libi2pd/util.h b/libi2pd/util.h index 830a984d..febb98b0 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -143,7 +143,7 @@ namespace util private: std::string m_Name; - bool m_IsRunning; + volatile bool m_IsRunning; std::unique_ptr m_Thread; boost::asio::io_service m_Service; }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 78190c89..e06b2db4 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -24,10 +24,35 @@ namespace client { I2CPDestination::I2CPDestination (std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params): - LeaseSetDestination (isPublic, ¶ms), m_Owner (owner), m_Identity (identity) + RunnableService ("I2CP"), LeaseSetDestination (GetService (), isPublic, ¶ms), + m_Owner (owner), m_Identity (identity) { } + I2CPDestination::~I2CPDestination () + { + if (IsRunning ()) + Stop (); + } + + void I2CPDestination::Start () + { + if (!IsRunning ()) + { + LeaseSetDestination::Start (); + StartService (); + } + } + + void I2CPDestination::Stop () + { + if (IsRunning ()) + { + LeaseSetDestination::Stop (); + StopService (); + } + } + void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) { memcpy (m_EncryptionPrivateKey, key, 256); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 0d235161..a51597af 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -15,6 +15,7 @@ #include #include #include +#include "util.h" #include "Destination.h" namespace i2p @@ -61,12 +62,16 @@ namespace client const char I2CP_PARAM_MESSAGE_RELIABILITY[] = "i2cp.messageReliability"; class I2CPSession; - class I2CPDestination: public LeaseSetDestination + class I2CPDestination: public i2p::util::RunnableService, public LeaseSetDestination { public: I2CPDestination (std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params); - + ~I2CPDestination (); + + void Start (); + void Stop (); + void SetEncryptionPrivateKey (const uint8_t * key); void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession diff --git a/libi2pd_client/MatchedDestination.cpp b/libi2pd_client/MatchedDestination.cpp index fa08ec51..48d09b79 100644 --- a/libi2pd_client/MatchedDestination.cpp +++ b/libi2pd_client/MatchedDestination.cpp @@ -45,29 +45,19 @@ namespace client } - bool MatchedTunnelDestination::Start() + void MatchedTunnelDestination::Start() { - if(ClientDestination::Start()) - { - m_ResolveTimer = std::make_shared(GetService()); - GetTunnelPool()->SetCustomPeerSelector(this); - ResolveCurrentLeaseSet(); - return true; - } - else - return false; + ClientDestination::Start(); + m_ResolveTimer = std::make_shared(GetService()); + GetTunnelPool()->SetCustomPeerSelector(this); + ResolveCurrentLeaseSet(); } - bool MatchedTunnelDestination::Stop() + void MatchedTunnelDestination::Stop() { - if(ClientDestination::Stop()) - { - if(m_ResolveTimer) - m_ResolveTimer->cancel(); - return true; - } - else - return false; + ClientDestination::Stop(); + if(m_ResolveTimer) + m_ResolveTimer->cancel(); } diff --git a/libi2pd_client/MatchedDestination.h b/libi2pd_client/MatchedDestination.h index bbeeb503..1d7abf7d 100644 --- a/libi2pd_client/MatchedDestination.h +++ b/libi2pd_client/MatchedDestination.h @@ -14,8 +14,8 @@ namespace client { public: MatchedTunnelDestination(const i2p::data::PrivateKeys& keys, const std::string & remoteName, const std::map * params = nullptr); - bool Start(); - bool Stop(); + void Start(); + void Stop(); bool SelectPeers(i2p::tunnel::Path & peers, int hops, bool inbound); bool OnBuildResult(const i2p::tunnel::Path & peers, bool inbound, i2p::tunnel::TunnelBuildResult result); From b982be5ff58295436d4942f67cbb3411d8031f51 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 3 Feb 2020 16:21:07 -0500 Subject: [PATCH 36/58] handle existing session message --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 64 ++++++++++++++++------- libi2pd/ECIESX25519AEADRatchetSession.h | 17 +++--- libi2pd/Garlic.cpp | 11 ++-- libi2pd/Garlic.h | 11 ++-- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 11e7edad..96c917cd 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -86,7 +86,7 @@ namespace garlic return tagsetNsr.GetNextSessionTag (); } - bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len) { if (!GetOwner ()) return false; // we are Bob @@ -138,12 +138,12 @@ namespace garlic m_State = eSessionStateNewSessionReceived; GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); - HandlePayload (payload.data (), len - 16, handleClove); + HandlePayload (payload.data (), len - 16); return true; } - void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove) + void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len) { size_t offset = 0; while (offset < len) @@ -161,7 +161,7 @@ namespace garlic switch (blk) { case eECIESx25519BlkGalicClove: - handleClove (buf + offset, size); + GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size); break; case eECIESx25519BlkDateTime: LogPrint (eLogDebug, "Garlic: datetime"); @@ -220,7 +220,7 @@ namespace garlic m_State = eSessionStateNewSessionSent; if (GetOwner ()) - GetOwner ()->AddECIESx25519SessionTag (CreateNewSessionTag (), shared_from_this ()); + GetOwner ()->AddECIESx25519SessionTag (CreateNewSessionTag (), 0, shared_from_this ()); return true; } @@ -260,9 +260,12 @@ namespace garlic // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) - // k_ab = keydata[0:31], k_ba = keydata[32:63] - m_TagsetAB.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) - m_TagsetBA.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + memcpy (m_ReceiveKey, keydata, 32); // k_ab = keydata[0:31] + memcpy (m_SendKey, keydata + 32, 32);// k_ba = keydata[32:63] + m_ReceiveTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) + m_ReceiveTagset.NextSessionTagRatchet (); + m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + m_SendTagset.NextSessionTagRatchet (); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt @@ -270,11 +273,12 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; } + m_State = eSessionStateEstablished; return true; } - bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len) { // we are Alice LogPrint (eLogDebug, "Garlic: reply received"); @@ -308,9 +312,12 @@ namespace garlic // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) - // k_ab = keydata[0:31], k_ba = keydata[32:63] - m_TagsetAB.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) - m_TagsetBA.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + memcpy (m_SendKey, keydata, 32); // k_ab = keydata[0:31] + memcpy (m_ReceiveKey, keydata + 32, 32);// k_ba = keydata[32:63] + m_SendTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) + m_SendTagset.NextSessionTagRatchet (); + m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) + m_ReceiveTagset.NextSessionTagRatchet (); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload std::vector payload (len - 16); @@ -320,21 +327,41 @@ namespace garlic return false; } - // TODO: change state + m_State = eSessionStateEstablished; GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); - HandlePayload (payload.data (), len - 16, handleClove); + HandlePayload (payload.data (), len - 16); return true; } - bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, CloveHandler handleClove) + bool ECIESX25519AEADRatchetSession::HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index) + { + uint8_t nonce[12]; + memset (nonce, 0, 12); + htole64buf (nonce + 4, index); // tag's index + // ad = The session tag, 8 bytes + // ciphertext = ENCRYPT(k, n, payload, ad) + len -= 8; // tag + std::vector payload (len - 16); + if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, m_ReceiveKey, nonce, payload.data (), len - 16, false)) // decrypt + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); + return false; + } + HandlePayload (payload.data (), len - 16); + return true; + } + + bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, int index) { switch (m_State) { + case eSessionStateEstablished: + return HandleExistingSessionMessage (buf, len, index); case eSessionStateNew: - return HandleNewIncomingSession (buf, len, handleClove); + return HandleNewIncomingSession (buf, len); case eSessionStateNewSessionSent: - return HandleNewOutgoingSessionReply (buf, len, handleClove); + return HandleNewOutgoingSessionReply (buf, len); default: return false; } @@ -424,8 +451,7 @@ namespace garlic htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ()); return cloveSize + 3; - } - + } } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index ebe8cf13..f9b2de25 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -54,17 +54,16 @@ namespace garlic { eSessionStateNew =0, eSessionStateNewSessionReceived, - eSessionStateNewSessionSent + eSessionStateNewSessionSent, + eSessionStateEstablished }; public: - typedef std::function CloveHandler; - ECIESX25519AEADRatchetSession (GarlicDestination * owner); ~ECIESX25519AEADRatchetSession (); - bool HandleNextMessage (const uint8_t * buf, size_t len, CloveHandler handleClove); + bool HandleNextMessage (const uint8_t * buf, size_t len, int index = 0); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } @@ -82,9 +81,10 @@ namespace garlic bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes uint64_t CreateNewSessionTag () const; - bool HandleNewIncomingSession (const uint8_t * buf, size_t len, CloveHandler handleClove); - bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len, CloveHandler handleClove); - void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); + bool HandleNewIncomingSession (const uint8_t * buf, size_t len); + bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len); + bool HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index); + void HandlePayload (const uint8_t * buf, size_t len); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); @@ -97,7 +97,8 @@ namespace garlic uint8_t m_Aepk[32]; // Alice's ephemeral keys TODO: for incoming only i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; - RatchetTagSet m_TagsetAB, m_TagsetBA; + RatchetTagSet m_SendTagset, m_ReceiveTagset; + uint8_t m_SendKey[32], m_ReceiveKey[32]; std::unique_ptr m_Destination;// TODO: might not need it }; } diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 1b34f99c..7307b9c1 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -864,17 +864,18 @@ namespace garlic uint64_t tag; memcpy (&tag, buf, 8); ECIESX25519AEADRatchetSessionPtr session; + int index = 0; auto it = m_ECIESx25519Tags.find (tag); if (it != m_ECIESx25519Tags.end ()) { - session = it->second; + session = it->second.session; + index = it->second.index; m_ECIESx25519Tags.erase (tag); } else session = std::make_shared (this); // incoming - if (!session->HandleNextMessage (buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, - this, std::placeholders::_1, std::placeholders::_2))) + if (!session->HandleNextMessage (buf, len, index)) LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); } @@ -934,9 +935,9 @@ namespace garlic } } - void GarlicDestination::AddECIESx25519SessionTag (uint64_t tag, ECIESX25519AEADRatchetSessionPtr session) + void GarlicDestination::AddECIESx25519SessionTag (uint64_t tag, int index, ECIESX25519AEADRatchetSessionPtr session) { - m_ECIESx25519Tags.emplace (tag, session); + m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session}); } void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 4e66f75f..d12d0fa7 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -198,6 +198,11 @@ namespace garlic class ECIESX25519AEADRatchetSession; typedef std::shared_ptr ECIESX25519AEADRatchetSessionPtr; + struct ECIESX25519AEADRatchetIndexSession + { + int index; + ECIESX25519AEADRatchetSessionPtr session; + }; class GarlicDestination: public i2p::data::LocalDestination { @@ -217,8 +222,9 @@ namespace garlic void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID); - void AddECIESx25519SessionTag (uint64_t tag, ECIESX25519AEADRatchetSessionPtr session); + void AddECIESx25519SessionTag (uint64_t tag, int index, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); + void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); virtual void ProcessGarlicMessage (std::shared_ptr msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr msg); @@ -245,7 +251,6 @@ namespace garlic // ECIES-X25519-AEAD-Ratchet void HandleECIESx25519 (const uint8_t * buf, size_t len); - void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); private: @@ -257,7 +262,7 @@ namespace garlic std::unordered_map, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session // incoming std::unordered_map, std::hash > > m_Tags; - std::unordered_map m_ECIESx25519Tags; // session tag -> session + std::unordered_map m_ECIESx25519Tags; // session tag -> session // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; std::unordered_map m_DeliveryStatusSessions; // msgID -> session From 969f9aa4364d39efcec625882eb95ee86dc43485 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2020 11:48:56 -0500 Subject: [PATCH 37/58] common RuunableBase with private inheritance --- libi2pd/Destination.cpp | 6 +++--- libi2pd/Destination.h | 3 ++- libi2pd/NTCP2.cpp | 4 ++-- libi2pd/NTCP2.h | 3 ++- libi2pd/util.cpp | 10 ++++----- libi2pd/util.h | 12 +++++------ libi2pd_client/BOB.cpp | 34 ++++++------------------------ libi2pd_client/BOB.h | 9 +++----- libi2pd_client/ClientContext.cpp | 3 +-- libi2pd_client/I2CP.cpp | 6 +++--- libi2pd_client/I2CP.h | 2 +- libi2pd_client/SAM.cpp | 36 ++++++-------------------------- libi2pd_client/SAM.h | 10 +++------ 13 files changed, 43 insertions(+), 95 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 835c8e52..5240cb05 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -823,7 +823,7 @@ namespace client } ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): - RunnableService ("Destination"), LeaseSetDestination (GetService (), isPublic, params), + RunnableService ("Destination"), LeaseSetDestination (GetIOService (), isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_DatagramDestination (nullptr), m_RefCounter (0), m_ReadyChecker(GetService()) @@ -905,7 +905,7 @@ namespace client m_StreamingDestination->Start (); for (auto& it: m_StreamingDestinationsByPorts) it.second->Start (); - StartService (); + StartIOService (); } } @@ -929,7 +929,7 @@ namespace client delete m_DatagramDestination; m_DatagramDestination = nullptr; } - StopService (); + StopIOService (); } } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 5b411c14..529a9adb 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -102,6 +102,7 @@ namespace client LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map * params = nullptr); ~LeaseSetDestination (); const std::string& GetNickname () const { return m_Nickname; }; + boost::asio::io_service& GetService () { return m_Service; }; virtual void Start (); virtual void Stop (); @@ -191,7 +192,7 @@ namespace client bool IsPerClientAuth () const { return m_AuthType > 0; }; }; - class ClientDestination: public i2p::util::RunnableService, public LeaseSetDestination + class ClientDestination: private i2p::util::RunnableService, public LeaseSetDestination { public: #ifdef I2LUA diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e79be97a..034f7e21 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1155,7 +1155,7 @@ namespace transport { if (!IsRunning ()) { - StartService (); + StartIOService (); auto& addresses = context.GetRouterInfo ().GetAddresses (); for (const auto& address: addresses) { @@ -1217,7 +1217,7 @@ namespace transport if (IsRunning ()) m_TerminationTimer.cancel (); - StopService (); + StopIOService (); } bool NTCP2Server::AddNTCP2Session (std::shared_ptr session, bool incoming) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index a63b86b8..7e3c53e8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -216,7 +216,7 @@ namespace transport std::list > m_SendQueue; }; - class NTCP2Server: public i2p::util::RunnableServiceWithWork + class NTCP2Server: private i2p::util::RunnableServiceWithWork { public: @@ -225,6 +225,7 @@ namespace transport void Start (); void Stop (); + boost::asio::io_service& GetService () { return GetIOService (); }; bool AddNTCP2Session (std::shared_ptr session, bool incoming = false); void RemoveNTCP2Session (std::shared_ptr session); diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 6ae9fa6b..051eea5d 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -58,7 +58,7 @@ namespace i2p namespace util { - void RunnableService::StartService () + void RunnableService::StartIOService () { if (!m_IsRunning) { @@ -67,7 +67,7 @@ namespace util } } - void RunnableService::StopService () + void RunnableService::StopIOService () { if (m_IsRunning) { @@ -245,10 +245,10 @@ namespace net #else std::string localAddressUniversal = localAddress.to_string(); #endif - - typedef int (* IPN)(int af, const char *src, void *dst); + + typedef int (* IPN)(int af, const char *src, void *dst); IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton"); - if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found + if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found if(localAddress.is_v4()) { diff --git a/libi2pd/util.h b/libi2pd/util.h index febb98b0..2202ccd9 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -125,16 +125,16 @@ namespace util class RunnableService { - public: + protected: RunnableService (const std::string& name): m_Name (name), m_IsRunning (false) {} virtual ~RunnableService () {} - boost::asio::io_service& GetService () { return m_Service; } + boost::asio::io_service& GetIOService () { return m_Service; } bool IsRunning () const { return m_IsRunning; }; - void StartService (); - void StopService (); + void StartIOService (); + void StopIOService (); private: @@ -150,10 +150,10 @@ namespace util class RunnableServiceWithWork: public RunnableService { - public: + protected: RunnableServiceWithWork (const std::string& name): - RunnableService (name), m_Work (GetService ()) {} + RunnableService (name), m_Work (GetIOService ()) {} private: diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index aba090dc..c7bbdb46 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -743,8 +743,8 @@ namespace client } BOBCommandChannel::BOBCommandChannel (const std::string& address, int port): - m_IsRunning (false), m_Thread (nullptr), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)) + RunnableService ("BOB"), + m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)) { // command -> handler m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler; @@ -794,7 +794,8 @@ namespace client BOBCommandChannel::~BOBCommandChannel () { - Stop (); + if (IsRunning ()) + Stop (); for (const auto& it: m_Destinations) delete it.second; } @@ -802,38 +803,15 @@ namespace client void BOBCommandChannel::Start () { Accept (); - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&BOBCommandChannel::Run, this)); + StartIOService (); } void BOBCommandChannel::Stop () { - m_IsRunning = false; for (auto& it: m_Destinations) it.second->Stop (); m_Acceptor.cancel (); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } - - void BOBCommandChannel::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "BOB: runtime exception: ", ex.what ()); - } - } + StopIOService (); } void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest) diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index 8f1af185..15a0afaf 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.h @@ -7,6 +7,7 @@ #include #include #include +#include "util.h" #include "I2PTunnel.h" #include "I2PService.h" #include "Identity.h" @@ -231,7 +232,7 @@ namespace client }; typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len); - class BOBCommandChannel + class BOBCommandChannel: private i2p::util::RunnableService { public: @@ -241,22 +242,18 @@ namespace client void Start (); void Stop (); - boost::asio::io_service& GetService () { return m_Service; }; + boost::asio::io_service& GetService () { return GetIOService (); }; void AddDestination (const std::string& name, BOBDestination * dest); void DeleteDestination (const std::string& name); BOBDestination * FindDestination (const std::string& name); private: - void Run (); void Accept (); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr session); private: - bool m_IsRunning; - std::thread * m_Thread; - boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; std::map m_Destinations; std::map m_CommandHandlers; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index d14491b2..53e740b3 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -344,8 +344,7 @@ namespace client if (it != m_Destinations.end ()) { LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); - if (!it->second->IsRunning ()) - it->second->Start (); + it->second->Start (); // make sure to start return it->second; } auto localDestination = std::make_shared (keys, isPublic, params); diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index e06b2db4..69b26cab 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -24,7 +24,7 @@ namespace client { I2CPDestination::I2CPDestination (std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params): - RunnableService ("I2CP"), LeaseSetDestination (GetService (), isPublic, ¶ms), + RunnableService ("I2CP"), LeaseSetDestination (GetIOService (), isPublic, ¶ms), m_Owner (owner), m_Identity (identity) { } @@ -40,7 +40,7 @@ namespace client if (!IsRunning ()) { LeaseSetDestination::Start (); - StartService (); + StartIOService (); } } @@ -49,7 +49,7 @@ namespace client if (IsRunning ()) { LeaseSetDestination::Stop (); - StopService (); + StopIOService (); } } diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index a51597af..d4e05b51 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -62,7 +62,7 @@ namespace client const char I2CP_PARAM_MESSAGE_RELIABILITY[] = "i2cp.messageReliability"; class I2CPSession; - class I2CPDestination: public i2p::util::RunnableService, public LeaseSetDestination + class I2CPDestination: private i2p::util::RunnableService, public LeaseSetDestination { public: diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 766a1940..3ddfc940 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1001,9 +1001,9 @@ namespace client } SAMBridge::SAMBridge (const std::string& address, int port): - m_IsRunning (false), m_Thread (nullptr), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), - m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint), + RunnableService ("SAM"), + m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), + m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (GetIOService (), m_DatagramEndpoint), m_SignatureTypes { {"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1}, @@ -1020,7 +1020,7 @@ namespace client SAMBridge::~SAMBridge () { - if (m_IsRunning) + if (IsRunning ()) Stop (); } @@ -1028,14 +1028,11 @@ namespace client { Accept (); ReceiveDatagram (); - m_IsRunning = true; - m_Thread = new std::thread (std::bind (&SAMBridge::Run, this)); + StartIOService (); } void SAMBridge::Stop () { - m_IsRunning = false; - try { m_Acceptor.cancel (); @@ -1048,28 +1045,7 @@ namespace client for (auto& it: m_Sessions) it.second->CloseStreams (); m_Sessions.clear (); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } - } - - void SAMBridge::Run () - { - while (m_IsRunning) - { - try - { - m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "SAM: runtime exception: ", ex.what ()); - } - } + StopIOService (); } void SAMBridge::Accept () diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index aebdccb6..029f3524 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -9,6 +9,7 @@ #include #include #include +#include "util.h" #include "Identity.h" #include "LeaseSet.h" #include "Streaming.h" @@ -174,7 +175,7 @@ namespace client void CloseStreams (); }; - class SAMBridge + class SAMBridge: private i2p::util::RunnableService { public: @@ -184,7 +185,7 @@ namespace client void Start (); void Stop (); - boost::asio::io_service& GetService () { return m_Service; }; + boost::asio::io_service& GetService () { return GetIOService (); }; std::shared_ptr CreateSession (const std::string& id, SAMSessionType type, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); @@ -201,8 +202,6 @@ namespace client private: - void Run (); - void Accept (); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); @@ -211,9 +210,6 @@ namespace client private: - bool m_IsRunning; - std::thread * m_Thread; - boost::asio::io_service m_Service; boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::socket m_DatagramSocket; From cbedebc9dd72623f5aa10ea67474f5e4066c7290 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2020 13:32:16 -0500 Subject: [PATCH 38/58] change minimal MTU size --- libi2pd/util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 051eea5d..c1b741fc 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -324,7 +324,7 @@ namespace net int GetMTU(const boost::asio::ip::address& localAddress) { - const int fallback = 576; // fallback MTU + int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU #ifdef WIN32 return GetMTUWindows(localAddress, fallback); From d0e78be8676c514e1c6a785befc69b3acdb4e5ed Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2020 14:17:23 -0500 Subject: [PATCH 39/58] moved io_service away from ClientDestination --- libi2pd/Destination.cpp | 86 +++++++++++++++++---------- libi2pd/Destination.h | 21 +++++-- libi2pd/api.cpp | 4 +- libi2pd_client/ClientContext.cpp | 4 +- libi2pd_client/MatchedDestination.cpp | 2 +- libi2pd_client/MatchedDestination.h | 2 +- 6 files changed, 77 insertions(+), 42 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 5240cb05..4f6b43ae 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -822,11 +822,12 @@ namespace client } } - ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): - RunnableService ("Destination"), LeaseSetDestination (GetIOService (), isPublic, params), + ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, + bool isPublic, const std::map * params): + LeaseSetDestination (service, isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_DatagramDestination (nullptr), m_RefCounter (0), - m_ReadyChecker(GetService()) + m_ReadyChecker(service) { if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only @@ -892,44 +893,34 @@ namespace client ClientDestination::~ClientDestination () { - if (IsRunning ()) - Stop (); } void ClientDestination::Start () { - if (!IsRunning ()) - { - LeaseSetDestination::Start (); - m_StreamingDestination = std::make_shared (GetSharedFromThis ()); // TODO: - m_StreamingDestination->Start (); - for (auto& it: m_StreamingDestinationsByPorts) - it.second->Start (); - StartIOService (); - } + LeaseSetDestination::Start (); + m_StreamingDestination = std::make_shared (GetSharedFromThis ()); // TODO: + m_StreamingDestination->Start (); + for (auto& it: m_StreamingDestinationsByPorts) + it.second->Start (); } void ClientDestination::Stop () { - if (IsRunning ()) + LeaseSetDestination::Stop (); + m_ReadyChecker.cancel(); + m_StreamingDestination->Stop (); + //m_StreamingDestination->SetOwner (nullptr); + m_StreamingDestination = nullptr; + for (auto& it: m_StreamingDestinationsByPorts) { - LeaseSetDestination::Stop (); - m_ReadyChecker.cancel(); - m_StreamingDestination->Stop (); - //m_StreamingDestination->SetOwner (nullptr); - m_StreamingDestination = nullptr; - for (auto& it: m_StreamingDestinationsByPorts) - { - it.second->Stop (); - //it.second->SetOwner (nullptr); - } - m_StreamingDestinationsByPorts.clear (); - if (m_DatagramDestination) - { - delete m_DatagramDestination; - m_DatagramDestination = nullptr; - } - StopIOService (); + it.second->Stop (); + //it.second->SetOwner (nullptr); + } + m_StreamingDestinationsByPorts.clear (); + if (m_DatagramDestination) + { + delete m_DatagramDestination; + m_DatagramDestination = nullptr; } } @@ -1199,5 +1190,36 @@ namespace client } } } + + RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): + RunnableService ("Destination"), + ClientDestination (GetIOService (), keys, isPublic, params) + { + } + + RunnableClientDestination::~RunnableClientDestination () + { + if (IsRunning ()) + Stop (); + } + + void RunnableClientDestination::Start () + { + if (!IsRunning ()) + { + ClientDestination::Start (); + StartIOService (); + } + } + + void RunnableClientDestination::Stop () + { + if (IsRunning ()) + { + ClientDestination::Stop (); + StopIOService (); + } + } + } } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 529a9adb..ed3abdfb 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -192,7 +192,7 @@ namespace client bool IsPerClientAuth () const { return m_AuthType > 0; }; }; - class ClientDestination: private i2p::util::RunnableService, public LeaseSetDestination + class ClientDestination: public LeaseSetDestination { public: #ifdef I2LUA @@ -203,11 +203,12 @@ namespace client void Ready(ReadyPromise & p); #endif - ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); + ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, + bool isPublic, const std::map * params = nullptr); ~ClientDestination (); - virtual void Start (); - virtual void Stop (); + void Start (); + void Stop (); const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; @@ -281,6 +282,18 @@ namespace client // for HTTP only std::vector > GetAllStreams () const; }; + + class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination + { + public: + + RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params = nullptr); + ~RunnableClientDestination (); + + void Start (); + void Stop (); + }; + } } diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index ca72ae49..0a76bda7 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -77,7 +77,7 @@ namespace api std::shared_ptr CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params) { - auto localDestination = std::make_shared (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); localDestination->Start (); return localDestination; } @@ -86,7 +86,7 @@ namespace api const std::map * params) { i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); - auto localDestination = std::make_shared (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); localDestination->Start (); return localDestination; } diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 53e740b3..37fad236 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -305,7 +305,7 @@ namespace client const std::map * params) { i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); - auto localDestination = std::make_shared (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); std::unique_lock l(m_DestinationsMutex); m_Destinations[localDestination->GetIdentHash ()] = localDestination; localDestination->Start (); @@ -347,7 +347,7 @@ namespace client it->second->Start (); // make sure to start return it->second; } - auto localDestination = std::make_shared (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); std::unique_lock l(m_DestinationsMutex); m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination; localDestination->Start (); diff --git a/libi2pd_client/MatchedDestination.cpp b/libi2pd_client/MatchedDestination.cpp index 48d09b79..3d75a3ca 100644 --- a/libi2pd_client/MatchedDestination.cpp +++ b/libi2pd_client/MatchedDestination.cpp @@ -8,7 +8,7 @@ namespace i2p namespace client { MatchedTunnelDestination::MatchedTunnelDestination(const i2p::data::PrivateKeys & keys, const std::string & remoteName, const std::map * params) - : ClientDestination(keys, false, params), + : RunnableClientDestination(keys, false, params), m_RemoteName(remoteName) {} diff --git a/libi2pd_client/MatchedDestination.h b/libi2pd_client/MatchedDestination.h index 1d7abf7d..67b874e6 100644 --- a/libi2pd_client/MatchedDestination.h +++ b/libi2pd_client/MatchedDestination.h @@ -10,7 +10,7 @@ namespace client /** client tunnel that uses same OBEP as IBGW of each remote lease for a remote destination */ - class MatchedTunnelDestination : public ClientDestination, public i2p::tunnel::ITunnelPeerSelector + class MatchedTunnelDestination : public RunnableClientDestination, public i2p::tunnel::ITunnelPeerSelector { public: MatchedTunnelDestination(const i2p::data::PrivateKeys& keys, const std::string & remoteName, const std::map * params = nullptr); From 9d891ab5dd6def8f9380af254a77a0a8a6db48ab Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 4 Feb 2020 15:31:04 -0500 Subject: [PATCH 40/58] single thread mode for SAM --- libi2pd/Config.cpp | 1 + libi2pd_client/ClientContext.cpp | 59 ++++++++++++++++++++++++-------- libi2pd_client/ClientContext.h | 8 +++++ libi2pd_client/SAM.cpp | 12 ++++--- libi2pd_client/SAM.h | 3 +- 5 files changed, 64 insertions(+), 19 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index e2f4bdd0..9d32cc72 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -131,6 +131,7 @@ namespace config { ("sam.enabled", value()->default_value(true), "Enable or disable SAM Application bridge") ("sam.address", value()->default_value("127.0.0.1"), "SAM listen address") ("sam.port", value()->default_value(7656), "SAM listen port") + ("sam.singlethread", value()->default_value(false), "Sessions run in the SAM bridge's thread") ; options_description bob("BOB options"); diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 37fad236..d72f40a8 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -53,14 +53,19 @@ namespace client // SAM bool sam; i2p::config::GetOption("sam.enabled", sam); - if (sam) { + if (sam) + { std::string samAddr; i2p::config::GetOption("sam.address", samAddr); uint16_t samPort; i2p::config::GetOption("sam.port", samPort); + bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread); LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); - try { - m_SamBridge = new SAMBridge (samAddr, samPort); - m_SamBridge->Start (); - } catch (std::exception& e) { + try + { + m_SamBridge = new SAMBridge (samAddr, samPort, singleThread); + m_SamBridge->Start (); + } + catch (std::exception& e) + { LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); } } @@ -306,20 +311,33 @@ namespace client { i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); auto localDestination = std::make_shared (keys, isPublic, params); - std::unique_lock l(m_DestinationsMutex); - m_Destinations[localDestination->GetIdentHash ()] = localDestination; - localDestination->Start (); + AddLocalDestination (localDestination); + return localDestination; + } + + std::shared_ptr ClientContext::CreateNewLocalDestination ( + boost::asio::io_service& service, bool isPublic, + i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, + const std::map * params) + { + i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); + auto localDestination = std::make_shared (service, keys, isPublic, params); + AddLocalDestination (localDestination); return localDestination; } std::shared_ptr ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map * params) { - MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params); - auto localDestination = std::shared_ptr(cl); + auto localDestination = std::make_shared(keys, name, params); + AddLocalDestination (localDestination); + return localDestination; + } + + void ClientContext::AddLocalDestination (std::shared_ptr localDestination) + { std::unique_lock l(m_DestinationsMutex); m_Destinations[localDestination->GetIdentHash ()] = localDestination; localDestination->Start (); - return localDestination; } void ClientContext::DeleteLocalDestination (std::shared_ptr destination) @@ -348,9 +366,22 @@ namespace client return it->second; } auto localDestination = std::make_shared (keys, isPublic, params); - std::unique_lock l(m_DestinationsMutex); - m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination; - localDestination->Start (); + AddLocalDestination (localDestination); + return localDestination; + } + + std::shared_ptr ClientContext::CreateNewLocalDestination (boost::asio::io_service& service, + const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params) + { + auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); + if (it != m_Destinations.end ()) + { + LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); + it->second->Start (); // make sure to start + return it->second; + } + auto localDestination = std::make_shared (service, keys, isPublic, params); + AddLocalDestination (localDestination); return localDestination; } diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 94aa8594..a239035f 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -68,8 +68,15 @@ namespace client i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, const std::map * params = nullptr); // used by SAM only + std::shared_ptr CreateNewLocalDestination (boost::asio::io_service& service, + bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, + i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, + const std::map * params = nullptr); // same as previous but on external io_service std::shared_ptr CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, const std::map * params = nullptr); + std::shared_ptr CreateNewLocalDestination (boost::asio::io_service& service, + const i2p::data::PrivateKeys& keys, bool isPublic = true, + const std::map * params = nullptr); // same as previous but on external io_service std::shared_ptr CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map * params = nullptr); void DeleteLocalDestination (std::shared_ptr destination); std::shared_ptr FindLocalDestination (const i2p::data::IdentHash& destination) const; @@ -107,6 +114,7 @@ namespace client void VisitTunnels (Visitor v); // Visitor: (I2PService *) -> bool, true means retain void CreateNewSharedLocalDestination (); + void AddLocalDestination (std::shared_ptr localDestination); private: diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 3ddfc940..bc4812bb 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1000,8 +1000,8 @@ namespace client } } - SAMBridge::SAMBridge (const std::string& address, int port): - RunnableService ("SAM"), + SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread): + RunnableService ("SAM"), m_IsSingleThread (singleThread), m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (GetIOService (), m_DatagramEndpoint), m_SignatureTypes @@ -1094,7 +1094,9 @@ namespace client { i2p::data::PrivateKeys keys; if (!keys.FromBase64 (destination)) return nullptr; - localDestination = i2p::client::context.CreateNewLocalDestination (keys, true, params); + localDestination = m_IsSingleThread ? + i2p::client::context.CreateNewLocalDestination (GetIOService (), keys, true, params) : + i2p::client::context.CreateNewLocalDestination (keys, true, params); } else // transient { @@ -1122,7 +1124,9 @@ namespace client } } } - localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, cryptoType, params); + localDestination = m_IsSingleThread ? + i2p::client::context.CreateNewLocalDestination (GetIOService (), true, signatureType, cryptoType, params) : + i2p::client::context.CreateNewLocalDestination (true, signatureType, cryptoType, params); } if (localDestination) { diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 029f3524..5a447c06 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -179,7 +179,7 @@ namespace client { public: - SAMBridge (const std::string& address, int port); + SAMBridge (const std::string& address, int port, bool singleThread); ~SAMBridge (); void Start (); @@ -210,6 +210,7 @@ namespace client private: + bool m_IsSingleThread; boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::socket m_DatagramSocket; From 012f22cc477158c8d7bfb684cd5101c6fbe7b05e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 5 Feb 2020 15:48:51 -0500 Subject: [PATCH 41/58] create session tags for ECIESX25519 --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 52 ++++++++++++++++++----- libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++ libi2pd/Garlic.cpp | 5 ++- libi2pd/Garlic.h | 3 +- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 96c917cd..94ccbce5 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -27,11 +27,13 @@ namespace garlic { i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), nullptr, 0, "STInitialization", m_KeyData.buf); // [sessTag_ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64) memcpy (m_SessTagConstant, m_KeyData.GetSessTagConstant (), 32); + m_NextIndex = 0; } uint64_t RatchetTagSet::GetNextSessionTag () { i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) + m_NextIndex++; return m_KeyData.GetTag (); } @@ -64,6 +66,12 @@ namespace garlic SHA256_Final (m_H, &ctx); } + void ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); + } + bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf) { for (int i = 0; i < 10; i++) @@ -107,7 +115,7 @@ namespace garlic // decrypt flags/static uint8_t nonce[12], fs[32]; - memset (nonce, 0, 12); // n = 0 + CreateNonce (0, nonce); if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, m_CK + 32, nonce, fs, 32, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); @@ -128,7 +136,7 @@ namespace garlic i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) } else // all zeros flags - htole64buf (nonce + 4, 1); // n = 1 + CreateNonce (1, nonce); if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); @@ -199,7 +207,7 @@ namespace garlic i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) // encrypt static key section uint8_t nonce[12]; - memset (nonce, 0, 12); // n = 0 + CreateNonce (0, nonce); if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed "); @@ -220,7 +228,7 @@ namespace garlic m_State = eSessionStateNewSessionSent; if (GetOwner ()) - GetOwner ()->AddECIESx25519SessionTag (CreateNewSessionTag (), 0, shared_from_this ()); + GetOwner ()->AddECIESx25519SessionTag (0, CreateNewSessionTag (), shared_from_this ()); return true; } @@ -248,7 +256,7 @@ namespace garlic m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) uint8_t nonce[12]; - memset (nonce, 0, 12); // n = 0 + CreateNonce (0, nonce); // calulate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) { @@ -266,6 +274,9 @@ namespace garlic m_ReceiveTagset.NextSessionTagRatchet (); m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) m_SendTagset.NextSessionTagRatchet (); + auto numTags = GetOwner ()->GetNumTags (); + for (int i = 0; i < numTags; i++) + GetOwner ()->AddECIESx25519SessionTag (m_ReceiveTagset.GetNextIndex (), m_ReceiveTagset.GetNextSessionTag (), shared_from_this ()); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt @@ -300,7 +311,7 @@ namespace garlic GetOwner ()->Decrypt (bepk, sharedSecret, nullptr); // x25519 (ask, bepk) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) uint8_t nonce[12]; - memset (nonce, 0, 12); // n = 0 + CreateNonce (0, nonce); // calulate hash for zero length if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anyting */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only { @@ -318,6 +329,9 @@ namespace garlic m_SendTagset.NextSessionTagRatchet (); m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) m_ReceiveTagset.NextSessionTagRatchet (); + auto numTags = GetOwner ()->GetNumTags (); + for (int i = 0; i < numTags; i++) + GetOwner ()->AddECIESx25519SessionTag (m_ReceiveTagset.GetNextIndex (), m_ReceiveTagset.GetNextSessionTag (), shared_from_this ()); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload std::vector payload (len - 16); @@ -334,13 +348,26 @@ namespace garlic return true; } + bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) + { + uint8_t nonce[12]; + CreateNonce (m_SendTagset.GetNextIndex (), nonce); // tag's index + uint64_t tag = m_SendTagset.GetNextSessionTag (); + memcpy (out, &tag, 8); + // ad = The session tag, 8 bytes + // ciphertext = ENCRYPT(k, n, payload, ad) + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, m_SendKey, nonce, out + 8, outLen - 8, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); + return false; + } + return true; + } + bool ECIESX25519AEADRatchetSession::HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index) { uint8_t nonce[12]; - memset (nonce, 0, 12); - htole64buf (nonce + 4, index); // tag's index - // ad = The session tag, 8 bytes - // ciphertext = ENCRYPT(k, n, payload, ad) + CreateNonce (index, nonce); // tag's index len -= 8; // tag std::vector payload (len - 16); if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, m_ReceiveKey, nonce, payload.data (), len - 16, false)) // decrypt @@ -378,6 +405,11 @@ namespace garlic switch (m_State) { + case eSessionStateEstablished: + if (!NewExistingSessionMessage (payload.data (), payload.size (), buf, m->maxLen)) + return nullptr; + len += 24; + break; case eSessionStateNew: if (!NewOutgoingSessionMessage (payload.data (), payload.size (), buf, m->maxLen)) return nullptr; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index f9b2de25..acc90e96 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -21,6 +21,7 @@ namespace garlic void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void NextSessionTagRatchet (); uint64_t GetNextSessionTag (); + int GetNextIndex () const { return m_NextIndex; }; private: @@ -35,6 +36,7 @@ namespace garlic } m_KeyData; uint8_t m_SessTagConstant[32]; + int m_NextIndex; }; enum ECIESx25519BlockType @@ -78,6 +80,7 @@ namespace garlic void ResetKeys (); void MixHash (const uint8_t * buf, size_t len); + void CreateNonce (uint64_t seqn, uint8_t * nonce); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes uint64_t CreateNewSessionTag () const; @@ -88,6 +91,8 @@ namespace garlic bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + std::vector CreatePayload (std::shared_ptr msg); size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len, bool isDestination = false); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 7307b9c1..14154eaf 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -418,6 +418,8 @@ namespace garlic m_Sessions.clear (); m_DeliveryStatusSessions.clear (); m_Tags.clear (); + m_ECIESx25519Sessions.clear (); + m_ECIESx25519Tags.clear (); } void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag) { @@ -737,6 +739,7 @@ namespace garlic ++it; } } + // TODO: cleanup ECIESx25519 } void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) @@ -935,7 +938,7 @@ namespace garlic } } - void GarlicDestination::AddECIESx25519SessionTag (uint64_t tag, int index, ECIESX25519AEADRatchetSessionPtr session) + void GarlicDestination::AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session) { m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session}); } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index d12d0fa7..4fdb299e 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -213,6 +213,7 @@ namespace garlic void CleanUp (); void SetNumTags (int numTags) { m_NumTags = numTags; }; + int GetNumTags () const { return m_NumTags; }; std::shared_ptr GetRoutingSession (std::shared_ptr destination, bool attachLeaseSet); void CleanupExpiredTags (); void RemoveDeliveryStatusSession (uint32_t msgID); @@ -222,7 +223,7 @@ namespace garlic void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread void DeliveryStatusSent (ElGamalAESSessionPtr session, uint32_t msgID); - void AddECIESx25519SessionTag (uint64_t tag, int index, ECIESX25519AEADRatchetSessionPtr session); + void AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); From 63e807b0b4eb2a781f5800b508c74b1415aba87b Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 6 Feb 2020 10:53:45 -0500 Subject: [PATCH 42/58] fixed crash on stop --- libi2pd_client/SAM.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index bc4812bb..138e39cf 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1042,9 +1042,12 @@ namespace client LogPrint (eLogError, "SAM: runtime exception: ", ex.what ()); } - for (auto& it: m_Sessions) - it.second->CloseStreams (); - m_Sessions.clear (); + { + std::unique_lock l(m_SessionsMutex); + for (auto& it: m_Sessions) + it.second->CloseStreams (); + m_Sessions.clear (); + } StopIOService (); } From 8e53c30a000882568811b40d3047894c1bfc43f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 7 Feb 2020 22:08:55 -0500 Subject: [PATCH 43/58] correct calls sequence for tag and index --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 94ccbce5..3b604445 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -276,7 +276,11 @@ namespace garlic m_SendTagset.NextSessionTagRatchet (); auto numTags = GetOwner ()->GetNumTags (); for (int i = 0; i < numTags; i++) - GetOwner ()->AddECIESx25519SessionTag (m_ReceiveTagset.GetNextIndex (), m_ReceiveTagset.GetNextSessionTag (), shared_from_this ()); + { + auto index = m_ReceiveTagset.GetNextIndex (); + uint64_t tag = m_ReceiveTagset.GetNextSessionTag (); + GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ()); + } i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt @@ -331,7 +335,11 @@ namespace garlic m_ReceiveTagset.NextSessionTagRatchet (); auto numTags = GetOwner ()->GetNumTags (); for (int i = 0; i < numTags; i++) - GetOwner ()->AddECIESx25519SessionTag (m_ReceiveTagset.GetNextIndex (), m_ReceiveTagset.GetNextSessionTag (), shared_from_this ()); + { + auto index = m_ReceiveTagset.GetNextIndex (); + uint64_t tag = m_ReceiveTagset.GetNextSessionTag (); + GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ()); + } i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload std::vector payload (len - 16); From 694d851cdb59ee0f54e36be1ee7794750425a775 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 8 Feb 2020 21:51:02 -0500 Subject: [PATCH 44/58] Symmetric Key Ratchet --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 37 ++++++++++++++++++----- libi2pd/ECIESX25519AEADRatchetSession.h | 12 +++++--- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 3b604445..b29c27ed 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -21,6 +21,8 @@ namespace garlic // nextRootKey = keydata[0:31] i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf); // [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) + memcpy (m_SymmKeyCK, m_KeyData.buf + 32, 32); + m_NextSymmKeyIndex = 0; } void RatchetTagSet::NextSessionTagRatchet () @@ -32,12 +34,32 @@ namespace garlic uint64_t RatchetTagSet::GetNextSessionTag () { - i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) + i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) m_NextIndex++; return m_KeyData.GetTag (); } + const uint8_t * RatchetTagSet::GetSymmKey (int index) + { + // TODO: store intermediate keys + if (m_NextSymmKeyIndex > 0 && index == m_NextSymmKeyIndex) + { + i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); + m_NextSymmKeyIndex++; + } + else + CalculateSymmKeyCK (index); + return m_CurrentSymmKeyCK + 32; + } + void RatchetTagSet::CalculateSymmKeyCK (int index) + { + i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64) + for (int i = 0; i < index; i++) + i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64) + m_NextSymmKeyIndex = index + 1; + } + ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): GarlicRoutingSession (owner, true) { @@ -268,8 +290,7 @@ namespace garlic // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) - memcpy (m_ReceiveKey, keydata, 32); // k_ab = keydata[0:31] - memcpy (m_SendKey, keydata + 32, 32);// k_ba = keydata[32:63] + // k_ab = keydata[0:31], k_ba = keydata[32:63] m_ReceiveTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) m_ReceiveTagset.NextSessionTagRatchet (); m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) @@ -327,8 +348,7 @@ namespace garlic // KDF for payload uint8_t keydata[64]; i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) - memcpy (m_SendKey, keydata, 32); // k_ab = keydata[0:31] - memcpy (m_ReceiveKey, keydata + 32, 32);// k_ba = keydata[32:63] + // k_ab = keydata[0:31], k_ba = keydata[32:63] m_SendTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) m_SendTagset.NextSessionTagRatchet (); m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) @@ -359,12 +379,13 @@ namespace garlic bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { uint8_t nonce[12]; - CreateNonce (m_SendTagset.GetNextIndex (), nonce); // tag's index + auto index = m_SendTagset.GetNextIndex (); + CreateNonce (index, nonce); // tag's index uint64_t tag = m_SendTagset.GetNextSessionTag (); memcpy (out, &tag, 8); // ad = The session tag, 8 bytes // ciphertext = ENCRYPT(k, n, payload, ad) - if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, m_SendKey, nonce, out + 8, outLen - 8, true)) // encrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, m_SendTagset.GetSymmKey (index), nonce, out + 8, outLen - 8, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; @@ -378,7 +399,7 @@ namespace garlic CreateNonce (index, nonce); // tag's index len -= 8; // tag std::vector payload (len - 16); - if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, m_ReceiveKey, nonce, payload.data (), len - 16, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, m_ReceiveTagset.GetSymmKey (index), nonce, payload.data (), len - 16, false)) // decrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); return false; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index acc90e96..214e47f6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -22,9 +22,14 @@ namespace garlic void NextSessionTagRatchet (); uint64_t GetNextSessionTag (); int GetNextIndex () const { return m_NextIndex; }; + const uint8_t * GetSymmKey (int index); private: - + + void CalculateSymmKeyCK (int index); + + private: + union { uint64_t ll[8]; @@ -35,8 +40,8 @@ namespace garlic uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39] } m_KeyData; - uint8_t m_SessTagConstant[32]; - int m_NextIndex; + uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64]; + int m_NextIndex, m_NextSymmKeyIndex; }; enum ECIESx25519BlockType @@ -103,7 +108,6 @@ namespace garlic i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; RatchetTagSet m_SendTagset, m_ReceiveTagset; - uint8_t m_SendKey[32], m_ReceiveKey[32]; std::unique_ptr m_Destination;// TODO: might not need it }; } From 53a6162b0c3c434823ce6b1ce21ef7971b3d2845 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 9 Feb 2020 17:19:42 -0500 Subject: [PATCH 45/58] generate more receive tags when needed --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 32 ++++++++++++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index b29c27ed..7f17130c 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -295,13 +295,7 @@ namespace garlic m_ReceiveTagset.NextSessionTagRatchet (); m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) m_SendTagset.NextSessionTagRatchet (); - auto numTags = GetOwner ()->GetNumTags (); - for (int i = 0; i < numTags; i++) - { - auto index = m_ReceiveTagset.GetNextIndex (); - uint64_t tag = m_ReceiveTagset.GetNextSessionTag (); - GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ()); - } + GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, keydata, nonce, out + offset, len + 16, true)) // encrypt @@ -310,7 +304,7 @@ namespace garlic return false; } m_State = eSessionStateEstablished; - + return true; } @@ -353,13 +347,7 @@ namespace garlic m_SendTagset.NextSessionTagRatchet (); m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) m_ReceiveTagset.NextSessionTagRatchet (); - auto numTags = GetOwner ()->GetNumTags (); - for (int i = 0; i < numTags; i++) - { - auto index = m_ReceiveTagset.GetNextIndex (); - uint64_t tag = m_ReceiveTagset.GetNextSessionTag (); - GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ()); - } + GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) // decrypt payload std::vector payload (len - 16); @@ -405,6 +393,9 @@ namespace garlic return false; } HandlePayload (payload.data (), len - 16); + if (m_NumReceiveTags > 0)m_NumReceiveTags--; + if (m_NumReceiveTags <= GetOwner ()->GetNumTags ()*2/3) + GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); return true; } @@ -513,6 +504,17 @@ namespace garlic memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ()); return cloveSize + 3; } + + void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (int numTags) + { + for (int i = 0; i < numTags; i++) + { + auto index = m_ReceiveTagset.GetNextIndex (); + uint64_t tag = m_ReceiveTagset.GetNextSessionTag (); + GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ()); + } + m_NumReceiveTags += numTags; + } } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 214e47f6..90e21e8a 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -80,7 +80,7 @@ namespace garlic { if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); } - + private: void ResetKeys (); @@ -101,6 +101,8 @@ namespace garlic std::vector CreatePayload (std::shared_ptr msg); size_t CreateGarlicClove (std::shared_ptr msg, uint8_t * buf, size_t len, bool isDestination = false); + void GenerateMoreReceiveTags (int numTags); + private: uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; @@ -108,6 +110,7 @@ namespace garlic i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; RatchetTagSet m_SendTagset, m_ReceiveTagset; + int m_NumReceiveTags = 0; std::unique_ptr m_Destination;// TODO: might not need it }; } From 09ed57ad425110b87ad64b14ec7147a67a16acd3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 12 Feb 2020 11:09:20 -0500 Subject: [PATCH 46/58] select preferred crypto from LeaseSet2 --- libi2pd/Destination.cpp | 4 ++-- libi2pd/LeaseSet.cpp | 21 ++++++++++++--------- libi2pd/LeaseSet.h | 6 +++--- libi2pd_client/I2CP.cpp | 5 ++++- libi2pd_client/I2CP.h | 3 +++ 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4f6b43ae..6544d120 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -388,7 +388,7 @@ namespace client if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET) leaseSet = std::make_shared (buf + offset, len - offset); // LeaseSet else - leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset); // LeaseSet2 + leaseSet = std::make_shared (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetEncryptionType ()); // LeaseSet2 if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key) { if (leaseSet->GetIdentHash () != GetIdentHash ()) @@ -412,7 +412,7 @@ namespace client auto it2 = m_LeaseSetRequests.find (key); if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey) { - auto ls2 = std::make_shared (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr); + auto ls2 = std::make_shared (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr, GetEncryptionType ()); if (ls2->IsValid ()) { m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index e6373dd9..8d1b9524 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -251,18 +251,19 @@ namespace data memcpy (m_Buffer, buf, len); } - LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases): - LeaseSet (storeLeases), m_StoreType (storeType) + LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): + LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) { - SetBuffer (buf, len); + SetBuffer (buf, len); if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) ReadFromBufferEncrypted (buf, len, nullptr, nullptr); else ReadFromBuffer (buf, len); } - LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret): - LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) + LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, + const uint8_t * secret, CryptoKeyType preferredCrypto): + LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) { ReadFromBufferEncrypted (buf, len, key, secret); } @@ -355,6 +356,8 @@ namespace data offset += propertiesLen; // skip for now. TODO: implement properties if (offset + 1 >= len) return 0; // key sections + CryptoKeyType preferredKeyType = m_EncryptionType; + bool preferredKeyFound = false; int numKeySections = buf[offset]; offset++; for (int i = 0; i < numKeySections; i++) { @@ -362,15 +365,15 @@ namespace data if (offset + 2 >= len) return 0; uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2; if (offset + encryptionKeyLen >= len) return 0; - if (IsStoreLeases ()) // create encryptor with leases only + if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only { - // we pick first valid key, higher key type has higher priority 4-1-0 - // if two keys with of the same type, pick first + // we pick first valid key if preferred not found auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); - if (encryptor && (!m_Encryptor || keyType > m_EncryptionType)) + if (encryptor && (!m_Encryptor || keyType == preferredKeyType)) { m_Encryptor = encryptor; // TODO: atomic m_EncryptionType = keyType; + if (keyType == preferredKeyType) preferredKeyFound = true; } } offset += encryptionKeyLen; diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 84d87e17..a51570f7 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -136,8 +136,8 @@ namespace data { public: - LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true); - LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr); // store type 5, called from local netdb only + LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); + LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only uint8_t GetStoreType () const { return m_StoreType; }; uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; }; bool IsPublic () const { return m_IsPublic; }; @@ -168,7 +168,7 @@ namespace data uint32_t m_PublishedTimestamp = 0; bool m_IsPublic = true, m_IsPublishedEncrypted = false; std::shared_ptr m_TransientVerifier; - CryptoKeyType m_EncryptionType = CRYPTO_KEY_TYPE_ELGAMAL; + CryptoKeyType m_EncryptionType; std::shared_ptr m_Encryptor; // for standardLS2 }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 69b26cab..a14588a8 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -25,7 +25,7 @@ namespace client I2CPDestination::I2CPDestination (std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params): RunnableService ("I2CP"), LeaseSetDestination (GetIOService (), isPublic, ¶ms), - m_Owner (owner), m_Identity (identity) + m_Owner (owner), m_Identity (identity), m_EncryptionKeyType (m_Identity->GetCryptoKeyType ()) { } @@ -581,7 +581,10 @@ namespace client } // TODO: support multiple keys if (currentKey) + { m_Destination->SetEncryptionPrivateKey (currentKey); + m_Destination->SetEncryptionType (currentKeyType); + } m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ()); } diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index d4e05b51..68b4415a 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -73,12 +73,14 @@ namespace client void Stop (); void SetEncryptionPrivateKey (const uint8_t * key); + void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; }; void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession // implements LocalDestination bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; + i2p::data::CryptoKeyType GetEncryptionType () const { return m_EncryptionKeyType; }; std::shared_ptr GetIdentity () const { return m_Identity; }; protected: @@ -98,6 +100,7 @@ namespace client std::shared_ptr m_Owner; std::shared_ptr m_Identity; uint8_t m_EncryptionPrivateKey[256]; + i2p::data::CryptoKeyType m_EncryptionKeyType; std::shared_ptr m_Decryptor; uint64_t m_LeaseSetExpirationTime; }; From 32e2f0b1faf4897db307873bcb2f7ea29c2c54f5 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Feb 2020 16:30:10 -0500 Subject: [PATCH 47/58] correct termination of streaming destination --- libi2pd/Streaming.cpp | 6 ++++-- libi2pd/Streaming.h | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 4f943912..d666d786 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -86,13 +86,13 @@ namespace stream LogPrint (eLogDebug, "Streaming: Stream deleted"); } - void Stream::Terminate () + void Stream::Terminate () // shoudl be called from StreamingDestination::Stop only { m_AckSendTimer.cancel (); m_ReceiveTimer.cancel (); m_ResendTimer.cancel (); //CleanUp (); /* Need to recheck - broke working on windows */ - m_LocalDestination.DeleteStream (shared_from_this ()); + //m_LocalDestination.DeleteStream (shared_from_this ()); } void Stream::CleanUp () @@ -989,6 +989,8 @@ namespace stream m_PendingIncomingStreams.clear (); { std::unique_lock l(m_StreamsMutex); + for (auto it: m_Streams) + it.second->Terminate (); m_Streams.clear (); m_IncomingStreams.clear (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 49962507..3424bb2d 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -180,7 +180,6 @@ namespace stream int GetWindowSize () const { return m_WindowSize; }; int GetRTT () const { return m_RTT; }; - /** don't call me */ void Terminate (); private: From 88594887f9545459cc286b15456ac01b74a5061e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Feb 2020 17:44:36 -0500 Subject: [PATCH 48/58] fixed qt build --- qt/i2pd_qt/i2pd_qt.pro | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 15565c5c..adc2297d 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -62,6 +62,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../libi2pd/TunnelGateway.cpp \ ../../libi2pd/TunnelPool.cpp \ ../../libi2pd/util.cpp \ + ../../libi2pd/Elligator.cpp \ + ../../libi2pd/ECIESX25519AEADRatchetSession.cpp \ ../../libi2pd_client/AddressBook.cpp \ ../../libi2pd_client/BOB.cpp \ ../../libi2pd_client/ClientContext.cpp \ @@ -147,6 +149,8 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../libi2pd/TunnelPool.h \ ../../libi2pd/util.h \ ../../libi2pd/version.h \ + ../../libi2pd/Elligator.h \ + ../../libi2pd/ECIESX25519AEADRatchetSession.h \ ../../libi2pd_client/AddressBook.h \ ../../libi2pd_client/BOB.h \ ../../libi2pd_client/ClientContext.h \ From 47f384a0e093fb3e9b090b137bc0604565fdf412 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Feb 2020 15:14:35 -0500 Subject: [PATCH 49/58] postpone SAM destination termination --- libi2pd_client/SAM.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 138e39cf..d0942221 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -1161,6 +1161,15 @@ namespace client session->localDestination->Release (); session->localDestination->StopAcceptingStreams (); session->CloseStreams (); + if (m_IsSingleThread) + { + auto timer = std::make_shared(GetService ()); + timer->expires_from_now (boost::posix_time::seconds(5)); // postpone destination clean for 5 seconds + timer->async_wait ([timer, session](const boost::system::error_code& ecode) + { + // session's destructor is called here + }); + } } } From 24b48e5d50d2a7aabe68c6ef5e2ef2df069153fd Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 18 Feb 2020 17:45:04 -0500 Subject: [PATCH 50/58] reseeds update --- .../reseed/backup_at_mail.i2p.crt | 32 ------------------- libi2pd/Config.cpp | 3 +- 2 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 contrib/certificates/reseed/backup_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/backup_at_mail.i2p.crt b/contrib/certificates/reseed/backup_at_mail.i2p.crt deleted file mode 100644 index 73b08eaa..00000000 --- a/contrib/certificates/reseed/backup_at_mail.i2p.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFfTCCA2WgAwIBAgIEOprmhjANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY -WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPYmFja3VwQG1haWwu -aTJwMB4XDTEzMTAxMzEzNDQ1NVoXDTIzMTAxMzEzNDQ1NVowbzELMAkGA1UEBhMC -WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255 -bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2JhY2t1cEBtYWls -LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIoAkobXwk/Enf1d -roHyqCyvcJfZJVTwb/LgYWAvCBMCr+RGqlSgtk3g69Y3I0xU08fD2kGt3r5Pwsbr -omXIbJAcccyLqmQ5QX6QgL+X9VpMDp9C4h2RogCrqLBAWw4cuZ4RS9VCpP1Yis7H -uejYqENP86p7BsRnuW/4cYnfunAdMpss4LpRGQXt1nTX+kfgCYgnKFbFqwAHt7yV -Ds+Pe6FuBHPlp+sc1amKRcUnSvhXLsv43VicnT7xYL/kUsN83wrtHA3B4aGDx3aA -3/EzuRmIXQB0BlTZILMEyYwG/nc4OsW82QYrvEZ9BIg9A4lF/wS/KZCICPxLF2zo -dGjnmlgkiA4s8eO+va/ElHyELjckVXqmG1eXHhSkEsDvOQJy01IUuwLinvq7cUbJ -HfJBZJllEg+sLDCv3FkEqN+XjBNFfQN4oNew4w6IPY6YH1INVB9LL0Cmdu4DudLv -TY8OcI8eSfez3hmm+pYQ23PJRYYnvRDnRECyIWBegkckWRh8U/WvZUYUvETK6EDl -/0KpTtfzX6MqHA5D6bTAB8Y3ijGMLrZ/B5vj5yCoZbLiGme9X2moR2k1LEhdhtzV -exsqezCpg6dn48FTX7mHjvR5/r4kz2jqBGmdPUWIIxnjFUzDUK3llVQiHihleHpe -jL4LqnhBGKWFRTaVwaIkBG4zAfIzAgMBAAGjITAfMB0GA1UdDgQWBBQNkfW7bSMl -1/4KDbgwrkf9x1Zu/TANBgkqhkiG9w0BAQ0FAAOCAgEAGg3a3rTf0EznQocmio0T -5gCoL0n8h6yKW/PyPAIELrd9wiYjhJFcWvMTcJJJnVqmAL5vpvhaAFVtAfx70MGa -0DZ7FvytK5hEfF4IqOFDyEEVGJR5rIpVK4MeI1nmwEsxdbW+FhODjtRzgYO8XBME -Xj4aY1FWg9vxc3reUj6PSFsZtsB0aLiRgL9JDovJIiRw0Uqr1v2wXBte5yVCxDge -vTREZtpK4cKetoOa68pwSXI32JwKE18j6bfdKVBCcYQKlKP/3gHGduaDrQv3w32S -DRym5s6MREeTUOtAw4wq46KpdOX8yyAqJPrCfMwS6ORd3t+egqOw0PUnsqb97w4O -lUtrRYvb2cOj60SmRx4vJvItyuHbKqIK7o2e1RcUZPXYoAVx2ww4XB2Wk4D7LSAs -cS7nLj8yAqzJ2qqtBzxu+zILJtkVa12dKF0xmS0BxBp4sCYiBtmAVE8AWQqEuSHA -FrMWqoXcjcfdvvyX487FFWWUE7ZBIn0hee2sK9J9+SPtqczJaN7TF3K3nzo65WJG -1epltmq2Ugjb67Gz7v4y7H23DJ/qhm8yLtCHTj69HTta5I08j6Kut924WLZaiMO/ -4YoEL5AE63X0sxYibKFQiq7FW5nUJA280GRlY3xSMFzlB2ggazrUV3YAWVDhfdnI -flpzWXkFM2D36OUaubfe9YY= ------END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 9d32cc72..4ce51954 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -191,9 +191,10 @@ namespace config { "https://reseed.i2p-projekt.de/," "https://i2p.mooo.com/netDb/," "https://netdb.i2p2.no/," + "https://reseed.i2p2.no/," + "https://reseed2.i2p2.no/," // "https://us.reseed.i2p2.no:444/," // mamoth's shit // "https://uk.reseed.i2p2.no:444/," // mamoth's shit - "https://download.xxlspeed.com/," "https://reseed-fr.i2pd.xyz/," "https://reseed.memcpy.io/," "https://reseed.onion.im/," From f392edd66cafc374a40fed98bcea6c8d58bb88c8 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2020 13:27:28 -0500 Subject: [PATCH 51/58] single thread SAM by default --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 4ce51954..b0f7572d 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -131,7 +131,7 @@ namespace config { ("sam.enabled", value()->default_value(true), "Enable or disable SAM Application bridge") ("sam.address", value()->default_value("127.0.0.1"), "SAM listen address") ("sam.port", value()->default_value(7656), "SAM listen port") - ("sam.singlethread", value()->default_value(false), "Sessions run in the SAM bridge's thread") + ("sam.singlethread", value()->default_value(true), "Sessions run in the SAM bridge's thread") ; options_description bob("BOB options"); From 50450923dfabdfac612210a2f0fa3badcaf213ca Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 19 Feb 2020 20:51:32 -0500 Subject: [PATCH 52/58] don't add extra , to result string --- daemon/I2PControl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index 572292ee..acf054f1 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -394,13 +394,15 @@ namespace client void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { + bool first = true; for (auto it = params.begin (); it != params.end (); it++) { LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); auto it1 = m_RouterInfoHandlers.find (it->first); if (it1 != m_RouterInfoHandlers.end ()) { - if (it != params.begin ()) results << ","; + if (!first) results << ","; + else first = false; (this->*(it1->second))(results); } else From 9c9b723cf5b5f4e8a1cc1bea3cc2d505a796f7af Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2020 15:44:09 -0500 Subject: [PATCH 53/58] delete expired ECIESX25519AEADRatchet sessions and tags --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 1 + libi2pd/ECIESX25519AEADRatchetSession.h | 8 +++++ libi2pd/Garlic.cpp | 36 +++++++++++++++++++++-- libi2pd/Garlic.h | 1 + 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 7f17130c..d2d07343 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -401,6 +401,7 @@ namespace garlic bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, int index) { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); switch (m_State) { case eSessionStateEstablished: diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 90e21e8a..e5836cd4 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -55,6 +55,10 @@ namespace garlic eECIESx25519BlkPadding = 254 }; + + const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second of inactivity we should restart after + const int ECIESX25519_EXPIRATION_TIMEOUT = 600; // in seconds + class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this { enum SessionState @@ -81,6 +85,9 @@ namespace garlic if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); } + bool IsExpired (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_EXPIRATION_TIMEOUT; } + bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; } + private: void ResetKeys (); @@ -109,6 +116,7 @@ namespace garlic uint8_t m_Aepk[32]; // Alice's ephemeral keys TODO: for incoming only i2p::crypto::X25519Keys m_EphemeralKeys; SessionState m_State = eSessionStateNew; + uint64_t m_LastActivityTimestamp = 0; // incoming RatchetTagSet m_SendTagset, m_ReceiveTagset; int m_NumReceiveTags = 0; std::unique_ptr m_Destination;// TODO: might not need it diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 14154eaf..4828ad67 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -739,7 +739,25 @@ namespace garlic ++it; } } - // TODO: cleanup ECIESx25519 + // ECIESx25519 + for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();) + { + if (ts > it->second.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT) + it = m_ECIESx25519Tags.erase (it); + else + ++it; + } + + for (auto it = m_ECIESx25519Sessions.begin (); it != m_ECIESx25519Sessions.end ();) + { + if (it->second->IsExpired (ts)) + { + it->second->SetOwner (nullptr); + it = m_ECIESx25519Sessions.erase (it); + } + else + ++it; + } } void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) @@ -940,12 +958,24 @@ namespace garlic void GarlicDestination::AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session) { - m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session}); + m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session, i2p::util::GetSecondsSinceEpoch ()}); } void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) { - m_ECIESx25519Sessions.emplace (staticKey, session); + i2p::data::Tag<32> staticKeyTag (staticKey); + auto it = m_ECIESx25519Sessions.find (staticKeyTag); + if (it != m_ECIESx25519Sessions.end ()) + { + if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ())) + m_ECIESx25519Sessions.erase (it); + else + { + LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists"); + return; + } + } + m_ECIESx25519Sessions.emplace (staticKeyTag, session); } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 4fdb299e..9c256b48 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -202,6 +202,7 @@ namespace garlic { int index; ECIESX25519AEADRatchetSessionPtr session; + uint64_t creationTime; // seconds since epoch }; class GarlicDestination: public i2p::data::LocalDestination From 7168738835012d109a67bf9796880fa201a5072d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2020 21:05:07 -0500 Subject: [PATCH 54/58] check ctx for null --- libi2pd/CryptoKey.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp index 9881ebef..878e984a 100644 --- a/libi2pd/CryptoKey.cpp +++ b/libi2pd/CryptoKey.cpp @@ -14,6 +14,7 @@ namespace crypto void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) { + if (!ctx) return; ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding); } @@ -24,6 +25,7 @@ namespace crypto bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) { + if (!ctx) return false; return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding); } From 91919c6d64ad9ab70329404441820fcdf2795d03 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 20 Feb 2020 21:07:45 -0500 Subject: [PATCH 55/58] check if both sides are ECIESx25519 --- libi2pd/Garlic.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 4828ad67..c7d0e21d 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -658,7 +658,8 @@ namespace garlic std::shared_ptr GarlicDestination::GetRoutingSession ( std::shared_ptr destination, bool attachLeaseSet) { - if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET) + if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET && + GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET) { ECIESX25519AEADRatchetSessionPtr session; uint8_t staticKey[32]; From 5c308026ac280f699a01e0944deaac3b7698cf30 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Fri, 21 Feb 2020 09:12:57 +0200 Subject: [PATCH 56/58] Pass -dead_strip -dead_strip_dylibs -bind_at_load on macOS --- qt/i2pd_qt/i2pd_qt.pro | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index adc2297d..caa0bd50 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -210,6 +210,9 @@ macx { LIBS += $$BOOSTROOT/lib/libboost_filesystem.a LIBS += $$BOOSTROOT/lib/libboost_program_options.a LIBS += $$UPNPROOT/lib/libminiupnpc.a + LIBS += -Wl,-dead_strip + LIBS += -Wl,-dead_strip_dylibs + LIBS += -Wl,-bind_at_load } linux:!android { From 5115c27e72e85ebf07e146957a3e1fbeca4f70a9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 25 Feb 2020 11:15:30 -0500 Subject: [PATCH 57/58] 2.30.0 --- ChangeLog | 16 ++++++++++++++++ Win32/installer.iss | 2 +- android/build.gradle | 4 ++-- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml | 1 + 9 files changed, 37 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 07110fe2..293764a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,22 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.30.0] - 2020-02-25 +### Added +- Single threaded SAM +- Experimental support of ECIES-X25519-AEAD-Ratchet crypto type +### Changed +- Minimal MTU size is 1280 for ipv6 +- Use unordered_map instead map for destination's sessions and tags list +- Use std::shuffle instead std::random_shuffle +- SAM is single threaded by default +- Reseeds list +### Fixed +- Correct termination of streaming destination +- Extra ',' in RouterInfo response in I2PControl +- SAM crash on session termination +- Storage for Android 10 + ## [2.29.0] - 2019-10-21 ### Added - Client auth flag for b33 address diff --git a/Win32/installer.iss b/Win32/installer.iss index 736c7038..d4f6f247 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.29.0" +#define I2Pd_ver "2.30.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/build.gradle b/android/build.gradle index 291d90ea..844615f8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -30,8 +30,8 @@ android { applicationId "org.purplei2p.i2pd" targetSdkVersion 29 minSdkVersion 14 - versionCode 2290 - versionName "2.29.0" + versionCode 2300 + versionName "2.30.0" ndk { abiFilters 'armeabi-v7a' abiFilters 'x86' diff --git a/appveyor.yml b/appveyor.yml index f6eee9ab..8c4a1a9d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.29.0.{build} +version: 2.30.0.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 31b8d4a5..89e3cee9 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.29.0 +Version: 2.30.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -110,6 +110,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Feb 25 2020 orignal - 2.30.0 +- update to 2.30.0 + * Mon Oct 21 2019 orignal - 2.29.0 - update to 2.29.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 3db99af0..0f91c03b 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.29.0 +Version: 2.30.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -108,6 +108,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Feb 25 2020 orignal - 2.30.0 +- update to 2.30.0 + * Mon Oct 21 2019 orignal - 2.29.0 - update to 2.29.0 diff --git a/debian/changelog b/debian/changelog index f5f98680..da177cbd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.30.0-1) unstable; urgency=medium + + * updated to version 2.30.0/0.9.45 + + -- orignal Tue, 25 Feb 2020 16:00:00 +0000 + i2pd (2.29.0-1) unstable; urgency=medium * updated to version 2.29.0/0.9.43 diff --git a/libi2pd/version.h b/libi2pd/version.h index 2e876fdb..36fbe2ca 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -7,7 +7,7 @@ #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 29 +#define I2PD_VERSION_MINOR 30 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 44 +#define I2P_VERSION_MICRO 45 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index e6cc81d3..09bcf9ac 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,6 +35,7 @@ + From a0d6c654cc86faa2a045f60c03be0ef7c3950237 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 25 Feb 2020 20:08:50 +0300 Subject: [PATCH 58/58] 2.30.0 Signed-off-by: R4SAS --- qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index 09bcf9ac..00b6974a 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,7 +35,7 @@ - +