From 35d62686754a2d959964cf4c52f6fe3689eb6bbb Mon Sep 17 00:00:00 2001 From: Alexandre ZANNI <16578570+noraj@users.noreply.github.com> Date: Sat, 23 Nov 2019 22:52:31 +0100 Subject: [PATCH 01/92] README: explicit linux distro supported close #1440 --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b5fb8f7e..25e6c3e5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ [![GitHub release](https://img.shields.io/github/release/PurpleI2P/i2pd.svg?label=latest%20release)](https://github.com/PurpleI2P/i2pd/releases/latest) [![Snapcraft release](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![License](https://img.shields.io/github/license/PurpleI2P/i2pd.svg)](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE) +[![Packaging status](https://repology.org/badge/tiny-repos/i2pd.svg)](https://repology.org/project/i2pd/versions) i2pd ==== @@ -63,9 +64,10 @@ Build instructions: **Supported systems:** * GNU/Linux - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) + * CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/) + * Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc. * Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd) * Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) -* CentOS / Fedora / Mageia - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/) * Docker image - [![Build Status](https://dockerbuildbadges.quelltext.eu/status.svg?organization=meeh&repository=i2pd)](https://hub.docker.com/r/meeh/i2pd/builds/) * Snap - [![Snap Status](https://build.snapcraft.io/badge/PurpleI2P/i2pd-snap.svg)](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap) * FreeBSD From a33584150930335bbb75f6f53aa940717b8e9d8f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 6 Jan 2020 14:37:40 -0500 Subject: [PATCH 02/92] pass msgID to HandleDeliveryStatus --- libi2pd/Destination.cpp | 10 +++++----- libi2pd/Destination.h | 2 +- libi2pd/Garlic.cpp | 6 +++--- libi2pd/Garlic.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index ca60f0fb..cbbee03a 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -353,7 +353,8 @@ namespace client void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg)); + uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); + m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID)); } void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) @@ -366,7 +367,7 @@ namespace client break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted - HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); + HandleDeliveryStatusMessage (bufbe32toh (buf + I2NP_HEADER_SIZE + DELIVERY_STATUS_MSGID_OFFSET)); break; case eI2NPDatabaseStore: HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); @@ -511,9 +512,8 @@ namespace client LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found"); } - void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) + void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID) { - uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); if (msgID == m_PublishReplyToken) { LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32()); @@ -525,7 +525,7 @@ namespace client shared_from_this (), std::placeholders::_1)); } else - i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); + i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID); } void LeaseSetDestination::SetLeaseSetUpdated () diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index e4489fe0..a6e6fe2d 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -152,7 +152,7 @@ namespace client void HandlePublishDelayTimer (const boost::system::error_code& ecode); void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); - void HandleDeliveryStatusMessage (std::shared_ptr msg); + void HandleDeliveryStatusMessage (uint32_t msgID); void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr requestedBlindedKey = nullptr); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr nextFloodfill, std::shared_ptr request); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 1ee69df5..8cd12464 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -723,9 +723,8 @@ namespace garlic m_DeliveryStatusSessions[msgID] = session; } - void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) + void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID) { - uint32_t msgID = bufbe32toh (msg->GetPayload ()); GarlicRoutingSessionPtr session; { std::unique_lock l(m_DeliveryStatusSessionsMutex); @@ -757,7 +756,8 @@ namespace garlic void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - HandleDeliveryStatusMessage (msg); + uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); + HandleDeliveryStatusMessage (msgID); } void GarlicDestination::SaveTags () diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 4054d88c..bc999df5 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -206,7 +206,7 @@ namespace garlic protected: void HandleGarlicMessage (std::shared_ptr msg); - void HandleDeliveryStatusMessage (std::shared_ptr msg); + void HandleDeliveryStatusMessage (uint32_t msgID); void SaveTags (); void LoadTags (); From 815b6db0bfb811afd996a694736677ff0a63a817 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 6 Jan 2020 15:31:20 -0500 Subject: [PATCH 03/92] HandleCloveI2NPMessage --- libi2pd/Destination.cpp | 17 ++++++++++++----- libi2pd/Destination.h | 5 ++++- libi2pd/Garlic.h | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index cbbee03a..f6855844 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -360,24 +360,31 @@ namespace client void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) { uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; + if (!HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE)) + i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); + } + + bool LeaseSetDestination::HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) + { switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); + HandleDataMessage (payload, len); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted - HandleDeliveryStatusMessage (bufbe32toh (buf + I2NP_HEADER_SIZE + DELIVERY_STATUS_MSGID_OFFSET)); + HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); + HandleDatabaseStoreMessage (payload, len); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); + HandleDatabaseSearchReplyMessage (payload, len); break; default: - i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); + return false; } + return true; } void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index a6e6fe2d..bf08c80c 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -121,7 +121,6 @@ namespace client // implements GarlicDestination std::shared_ptr GetLeaseSet (); std::shared_ptr GetTunnelPool () const { return m_Pool; } - void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); // override GarlicDestination bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); @@ -131,6 +130,10 @@ namespace client protected: + // implements GarlicDestination + void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); + bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len); + void SetLeaseSet (std::shared_ptr newLeaseSet); int GetLeaseSetType () const { return m_LeaseSetType; }; void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; }; diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index bc999df5..fea2c935 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -201,10 +201,10 @@ namespace garlic virtual std::shared_ptr GetLeaseSet () = 0; // TODO virtual std::shared_ptr GetTunnelPool () const = 0; - virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; protected: + virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; // called from clove only void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (uint32_t msgID); From 4afef91359cc59a14d13987c26bf4a0094b94a1e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 6 Jan 2020 16:14:41 -0500 Subject: [PATCH 04/92] invoke HandleCloveI2NPMessage --- libi2pd/Garlic.cpp | 28 +++++++++++++++++++++++++++- libi2pd/Garlic.h | 2 ++ libi2pd/RouterContext.h | 7 ++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 8cd12464..82778ddc 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -913,7 +913,7 @@ namespace garlic switch (blk) { case eECIESx25519BlkGalicClove: - // TODO: + HandleECIESx25519GarlicClove (buf + offset, size); break; case eECIESx25519BlkDateTime: LogPrint (eLogDebug, "Garlic: datetime"); @@ -931,5 +931,31 @@ namespace garlic } } + void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) + { + const uint8_t * buf1 = buf; + uint8_t flag = buf[0]; buf++; // flag + GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); + switch (deliveryType) + { + case eGarlicDeliveryTypeDestination: + buf += 32; // TODO: check destination + // no break here + case eGarlicDeliveryTypeLocal: + { + uint8_t typeID = buf[0]; buf++; // typeid + buf += (4 + 4); // msgID + expiration + ptrdiff_t offset = buf - buf1; + if (offset <= (int)len) + HandleCloveI2NPMessage (typeID, buf, len - offset); + else + LogPrint (eLogError, "Garlic: clove is too long"); + break; + } + // TODO: tunnel + default: + LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); + } + } } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index fea2c935..5ef77638 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -205,6 +205,7 @@ namespace garlic protected: virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; // called from clove only + virtual bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) = 0; void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (uint32_t msgID); @@ -220,6 +221,7 @@ namespace garlic // ECIES-X25519-AEAD-Ratchet void HandleECIESx25519 (const uint8_t * buf, size_t len); void HandleECIESx25519Payload (const uint8_t * buf, size_t len); + void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); private: diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index f6aa281f..47a6f4fa 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -115,12 +115,17 @@ namespace i2p // implements GarlicDestination std::shared_ptr GetLeaseSet () { return nullptr; }; std::shared_ptr GetTunnelPool () const; - void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); // override GarlicDestination void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatusMessage (std::shared_ptr msg); + protected: + + // implements GarlicDestination + void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); + bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented + private: void CreateNewRouter (); From 0007f304d00157ac28ecdac2d970641adf79bec9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 7 Jan 2020 15:20:55 -0500 Subject: [PATCH 05/92] don't pass from to HandleI2NPMessage --- libi2pd/Destination.cpp | 6 +++--- libi2pd/Destination.h | 2 +- libi2pd/Garlic.cpp | 4 ++-- libi2pd/Garlic.h | 2 +- libi2pd/RouterContext.cpp | 6 +++--- libi2pd/RouterContext.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index f6855844..c3f63ffc 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -357,11 +357,10 @@ namespace client m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID)); } - void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) + void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len) { uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; - if (!HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE)) - i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); + LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); } bool LeaseSetDestination::HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) @@ -382,6 +381,7 @@ namespace client HandleDatabaseSearchReplyMessage (payload, len); break; default: + LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID); return false; } return true; diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index bf08c80c..2b7f7bb8 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -131,7 +131,7 @@ namespace client protected: // implements GarlicDestination - void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); + void HandleI2NPMessage (const uint8_t * buf, size_t len); bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len); void SetLeaseSet (std::shared_ptr newLeaseSet); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 82778ddc..e87aae05 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -552,7 +552,7 @@ namespace garlic LogPrint (eLogError, "Garlic: message is too short"); break; } - HandleI2NPMessage (buf, len - offset, from); + HandleI2NPMessage (buf, len - offset); break; case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: type destination"); @@ -563,7 +563,7 @@ namespace garlic LogPrint (eLogError, "Garlic: message is too short"); break; } - HandleI2NPMessage (buf, len - offset, from); + HandleI2NPMessage (buf, len - offset); break; case eGarlicDeliveryTypeTunnel: { diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 5ef77638..6acfce95 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -204,7 +204,7 @@ namespace garlic protected: - virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) = 0; // called from clove only + virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only virtual bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) = 0; void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (uint32_t msgID); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index bf3459d8..2c07c21b 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -27,7 +27,7 @@ namespace i2p void RouterContext::Init () { srand (i2p::util::GetMillisecondsSinceEpoch () % 1000); - m_StartupTime = std::chrono::steady_clock::now(); + m_StartupTime = std::chrono::steady_clock::now(); if (!Load ()) CreateNewRouter (); @@ -692,9 +692,9 @@ namespace i2p return i2p::tunnel::tunnels.GetExploratoryPool (); } - void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from) + void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len) { - i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); + i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); } void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 47a6f4fa..1524270d 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -123,7 +123,7 @@ namespace i2p protected: // implements GarlicDestination - void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr from); + void HandleI2NPMessage (const uint8_t * buf, size_t len); bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented private: From 4f70822b13a1fee29f175fac2d7ca17d56d5b831 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 12 Jan 2020 10:03:30 -0500 Subject: [PATCH 06/92] always persist crypto keys for public destinations --- libi2pd/Destination.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index c3f63ffc..71a5c329 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -879,11 +879,14 @@ namespace client if (it != params->end ()) m_EncryptionKeyType = std::stoi(it->second); } - - if (isPublic && m_EncryptionKeyType == GetIdentity ()->GetCryptoKeyType ()) // TODO: presist key type + + memset (m_EncryptionPrivateKey, 0, 256); + memset (m_EncryptionPublicKey, 0, 256); + if (isPublic) PersistTemporaryKeys (); else i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey); + m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey); if (isPublic) LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); @@ -1172,8 +1175,8 @@ namespace client LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p"); memset (m_EncryptionPrivateKey, 0, 256); memset (m_EncryptionPublicKey, 0, 256); - i2p::data::PrivateKeys::GenerateCryptoKeyPair (GetIdentity ()->GetCryptoKeyType (), m_EncryptionPrivateKey, m_EncryptionPublicKey); - + i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey); + // TODO:: persist crypto key type std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); if (f1) { f1.write ((char *)m_EncryptionPublicKey, 256); From 7ac05f848737ffd6b4ccea05f86aecdd07313ef2 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Mon, 13 Jan 2020 14:47:15 +0200 Subject: [PATCH 07/92] Pass -dead_strip -dead_strip_dylibs -bind_at_load on macOS --- Makefile.osx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.osx b/Makefile.osx index d673d3ef..c6af4fc2 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -2,6 +2,9 @@ CXX = clang++ CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX INCFLAGS = -I/usr/local/include LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDFLAGS += -Wl,-dead_strip +LDFLAGS += -Wl,-dead_strip_dylibs +LDFLAGS += -Wl,-bind_at_load ifeq ($(USE_STATIC),yes) LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread From 61752e2aaba77428de3014e97be864ca2f4f6673 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Jan 2020 22:37:31 -0500 Subject: [PATCH 08/92] correct ciphertext length --- libi2pd/Garlic.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index e87aae05..740b213b 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -836,7 +836,7 @@ namespace garlic // KDF1 // TODO : use precalculated hashes static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes - uint8_t h[64], ck[32]; + uint8_t h[80], ck[32]; SHA256 ((const uint8_t *)protocolName, 40, h); memcpy (ck, h, 32); SHA256 (h, 32, h); @@ -855,7 +855,7 @@ namespace garlic SHA256 (h, 64, h); // h = SHA256(h || aepk) uint8_t sharedSecret[32], keyData[64]; - Decrypt (aepk, sharedSecret, m_Ctx); // x25519 + Decrypt (aepk, sharedSecret, m_Ctx); // x25519(bsk, aepk) i2p::crypto::HKDF (ck, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) memcpy (ck, keyData, 32); // chainKey = keydata[0:31] @@ -867,8 +867,8 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); return; } - memcpy (h + 32, buf, 32); - SHA256 (h, 64, h); // h = SHA256(h || ciphertext) + memcpy (h + 32, buf, 48); + SHA256 (h, 80, h); // h = SHA256(h || ciphertext) buf += 48; len -= 48; // 32 data + 16 poly // decrypt payload std::vector payload (len + 32); uint8_t h1[32]; @@ -877,7 +877,7 @@ namespace garlic if (isStatic) { // static key, fs is apk - Decrypt (fs, sharedSecret, m_Ctx); // DH(bsk, apk) + Decrypt (fs, sharedSecret, m_Ctx); // x25519(bsk, apk) i2p::crypto::HKDF (ck, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) memcpy (ck, keyData, 32); // chainKey = keydata[0:31] memcpy (payload.data (), h, 32); From f651baab25ab6fbcf53e89ac89a13d424f708360 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Jan 2020 15:13:43 -0500 Subject: [PATCH 09/92] ECIESX25519AEADRatchetSession added --- build/CMakeLists.txt | 1 + libi2pd/ECIESX25519AEADRatchetSession.cpp | 160 ++++++++++++++++++++++ libi2pd/ECIESX25519AEADRatchetSession.h | 49 +++++++ libi2pd/Garlic.cpp | 132 +----------------- libi2pd/Garlic.h | 13 -- 5 files changed, 217 insertions(+), 138 deletions(-) create mode 100644 libi2pd/ECIESX25519AEADRatchetSession.cpp create mode 100644 libi2pd/ECIESX25519AEADRatchetSession.h diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index a9cf3a83..2577fb1b 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -83,6 +83,7 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/NTCP2.cpp" "${LIBI2PD_SRC_DIR}/Blinding.cpp" "${LIBI2PD_SRC_DIR}/Elligator.cpp" + "${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp" ) if (WITH_WEBSOCKETS) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp new file mode 100644 index 00000000..a258e8f7 --- /dev/null +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -0,0 +1,160 @@ +#include +#include +#include "Log.h" +#include "Crypto.h" +#include "Elligator.h" +#include "Tag.h" +#include "I2PEndian.h" +#include "Garlic.h" +#include "ECIESX25519AEADRatchetSession.h" + +namespace i2p +{ +namespace garlic +{ + + ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession () + { + // 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); + } + + ECIESX25519AEADRatchetSession::~ECIESX25519AEADRatchetSession () + { + } + + void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len) + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, len); + SHA256_Final (m_H, &ctx); + } + + bool ECIESX25519AEADRatchetSession::NewIncomingSession (const i2p::data::LocalDestination& dest, + const uint8_t * buf, size_t len, CloveI2NPMsgHandler handleCloveI2NPMsg) + { + // we are Bob + // KDF1 + MixHash (dest.GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk) + + uint8_t aepk[32]; // Alice's ephemeral key + if (!i2p::crypto::GetElligator ()->Decode (buf, aepk)) + { + LogPrint (eLogError, "Garlic: Can't decode elligator"); + return false; + } + buf += 32; len -= 32; + MixHash (aepk, 32); // h = SHA256(h || aepk) + + uint8_t sharedSecret[32], keyData[64]; + dest.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] + + // 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 + { + LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); + return false; + } + MixHash (buf, 48); // h = SHA256(h || ciphertext) + buf += 48; len -= 48; // 32 data + 16 poly + + // decrypt payload + std::vector payload (len - 16); + // KDF2 for payload + bool isStatic = !i2p::data::Tag<32> (fs).IsZero (); + if (isStatic) + { + // static key, fs is apk + dest.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] + } + 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 + { + LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); + return false; + } + if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext) + + HandlePayload (payload.data (), len - 16, handleCloveI2NPMsg); + + return true; + } + + void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg) + { + size_t offset = 0; + while (offset < len) + { + uint8_t blk = buf[offset]; + offset++; + auto size = bufbe16toh (buf + offset); + offset += 2; + LogPrint (eLogDebug, "Garlic: Block type ", (int)blk, " of size ", size); + if (size > len) + { + LogPrint (eLogError, "Garlic: Unexpected block length ", size); + break; + } + switch (blk) + { + case eECIESx25519BlkGalicClove: + HandleClove (buf + offset, size, handleCloveI2NPMsg); + break; + case eECIESx25519BlkDateTime: + LogPrint (eLogDebug, "Garlic: datetime"); + break; + case eECIESx25519BlkOptions: + LogPrint (eLogDebug, "Garlic: options"); + break; + case eECIESx25519BlkPadding: + LogPrint (eLogDebug, "NTCP2: padding"); + break; + default: + LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk); + } + offset += size; + } + } + + void ECIESX25519AEADRatchetSession::HandleClove (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg) + { + const uint8_t * buf1 = buf; + uint8_t flag = buf[0]; buf++; // flag + GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); + switch (deliveryType) + { + case eGarlicDeliveryTypeDestination: + buf += 32; // TODO: check destination + // no break here + case eGarlicDeliveryTypeLocal: + { + uint8_t typeID = buf[0]; buf++; // typeid + buf += (4 + 4); // msgID + expiration + ptrdiff_t offset = buf - buf1; + if (offset <= (int)len) + handleCloveI2NPMsg (typeID, buf, len - offset); + else + LogPrint (eLogError, "Garlic: clove is too long"); + break; + } + // TODO: tunnel + default: + LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); + } + } +} +} + + diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h new file mode 100644 index 00000000..dd28c669 --- /dev/null +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -0,0 +1,49 @@ +#ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__ +#define ECIES_X25519_AEAD_RATCHET_SESSION_H__ + +#include +#include +#include "Identity.h" + +namespace i2p +{ +namespace garlic +{ + enum ECIESx25519BlockType + { + eECIESx25519BlkDateTime = 0, + eECIESx25519BlkSessionID = 1, + eECIESx25519BlkTermination = 4, + eECIESx25519BlkOptions = 5, + eECIESx25519BlkNextSessionKey = 7, + eECIESx25519BlkGalicClove = 11, + eECIESx25519BlkPadding = 254 + }; + + class ECIESX25519AEADRatchetSession + { + public: + + typedef std::function CloveI2NPMsgHandler; + + ECIESX25519AEADRatchetSession (); + ~ECIESX25519AEADRatchetSession (); + + bool NewIncomingSession (const i2p::data::LocalDestination& dest, const uint8_t * buf, size_t len, + CloveI2NPMsgHandler handleCloveI2NPMsg); + + private: + + void MixHash (const uint8_t * buf, size_t len); + + void HandlePayload (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg); + void HandleClove (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg); + + private: + + uint8_t m_H[32], m_CK[32]; + }; +} +} + +#endif diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 740b213b..de8d6944 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -1,10 +1,8 @@ #include -#include #include "I2PEndian.h" #include #include #include "Crypto.h" -#include "Elligator.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "Tunnel.h" @@ -13,6 +11,7 @@ #include "Timestamp.h" #include "Log.h" #include "FS.h" +#include "ECIESX25519AEADRatchetSession.h" #include "Garlic.h" namespace i2p @@ -833,129 +832,12 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { - // KDF1 - // TODO : use precalculated hashes - static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes - uint8_t h[80], ck[32]; - SHA256 ((const uint8_t *)protocolName, 40, h); - memcpy (ck, h, 32); - SHA256 (h, 32, h); - // we are Bob - memcpy (h + 32, GetEncryptionPublicKey (), 32); - SHA256 (h, 64, h); // h = SHA256(h || bpk) - - uint8_t aepk[32]; - if (!i2p::crypto::GetElligator ()->Decode (buf, aepk)) - { - LogPrint (eLogError, "Garlic: Can't decode elligator"); - return; - } - buf += 32; len -= 32; - memcpy (h + 32, aepk, 32); - SHA256 (h, 64, h); // h = SHA256(h || aepk) - - uint8_t sharedSecret[32], keyData[64]; - Decrypt (aepk, sharedSecret, m_Ctx); // x25519(bsk, aepk) - i2p::crypto::HKDF (ck, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) - memcpy (ck, keyData, 32); // chainKey = keydata[0:31] - - // decrypt flags/static - uint8_t nonce[12], fs[32]; - memset (nonce, 0, 12); // n = 0 - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, h, 32, keyData + 32, nonce, fs, 32, false)) // decrypt - { - LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed "); - return; - } - memcpy (h + 32, buf, 48); - SHA256 (h, 80, h); // h = SHA256(h || ciphertext) - buf += 48; len -= 48; // 32 data + 16 poly - // decrypt payload - std::vector payload (len + 32); uint8_t h1[32]; - // KDF2 for payload - bool isStatic = !i2p::data::Tag<32> (fs).IsZero (); - if (isStatic) - { - // static key, fs is apk - Decrypt (fs, sharedSecret, m_Ctx); // x25519(bsk, apk) - i2p::crypto::HKDF (ck, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64) - memcpy (ck, keyData, 32); // chainKey = keydata[0:31] - memcpy (payload.data (), h, 32); - memcpy (payload.data () + 32, buf, len); // h || ciphertext - SHA256 (payload.data (), len + 32, h1); - } - else // all zeros flags - htole64buf (nonce + 4, 1); // n = 1 - if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, h, 32, keyData + 32, nonce, payload.data () + 32, len - 16, false)) // decrypt - { - LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); - return; - } - if (isStatic) memcpy (h, h1, 32); // h = SHA256(h || ciphertext) - HandleECIESx25519Payload (payload.data () + 32, len - 16); - } - - void GarlicDestination::HandleECIESx25519Payload (const uint8_t * buf, size_t len) - { - size_t offset = 0; - while (offset < len) - { - uint8_t blk = buf[offset]; - offset++; - auto size = bufbe16toh (buf + offset); - offset += 2; - LogPrint (eLogDebug, "Garlic: Block type ", (int)blk, " of size ", size); - if (size > len) - { - LogPrint (eLogError, "Garlic: Unexpected block length ", size); - break; - } - switch (blk) - { - case eECIESx25519BlkGalicClove: - HandleECIESx25519GarlicClove (buf + offset, size); - break; - case eECIESx25519BlkDateTime: - LogPrint (eLogDebug, "Garlic: datetime"); - break; - case eECIESx25519BlkOptions: - LogPrint (eLogDebug, "Garlic: options"); - break; - case eECIESx25519BlkPadding: - LogPrint (eLogDebug, "NTCP2: padding"); - break; - default: - LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk); - } - offset += size; - } - } - - void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) - { - const uint8_t * buf1 = buf; - uint8_t flag = buf[0]; buf++; // flag - GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); - switch (deliveryType) - { - case eGarlicDeliveryTypeDestination: - buf += 32; // TODO: check destination - // no break here - case eGarlicDeliveryTypeLocal: - { - uint8_t typeID = buf[0]; buf++; // typeid - buf += (4 + 4); // msgID + expiration - ptrdiff_t offset = buf - buf1; - if (offset <= (int)len) - HandleCloveI2NPMessage (typeID, buf, len - offset); - else - LogPrint (eLogError, "Garlic: clove is too long"); - break; - } - // TODO: tunnel - default: - LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); - } + ECIESX25519AEADRatchetSession session; + session.NewIncomingSession (*this, buf, len, + [this](uint8_t typeID, const uint8_t * payload, size_t len) + { + HandleCloveI2NPMessage (typeID, payload,len); + }); } } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 6acfce95..44ab2e82 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -165,17 +165,6 @@ namespace garlic //using GarlicRoutingSessionPtr = std::shared_ptr; typedef std::shared_ptr GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8 - enum ECIESx25519BlockType - { - eECIESx25519BlkDateTime = 0, - eECIESx25519BlkSessionID = 1, - eECIESx25519BlkTermination = 4, - eECIESx25519BlkOptions = 5, - eECIESx25519BlkNextSessionKey = 7, - eECIESx25519BlkGalicClove = 11, - eECIESx25519BlkPadding = 254 - }; - class GarlicDestination: public i2p::data::LocalDestination { public: @@ -220,8 +209,6 @@ namespace garlic // ECIES-X25519-AEAD-Ratchet void HandleECIESx25519 (const uint8_t * buf, size_t len); - void HandleECIESx25519Payload (const uint8_t * buf, size_t len); - void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); private: From 376bf6ba72af16d4d5ef2e75dfc1277176806c42 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Jan 2020 19:22:42 -0500 Subject: [PATCH 10/92] correct message size for ECIESx25519 --- libi2pd/Garlic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index de8d6944..5dfdfe79 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -457,7 +457,7 @@ namespace garlic // tag not found. Handle depending on encryption type if (GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET) { - HandleECIESx25519 (buf, length - 4); + HandleECIESx25519 (buf, length); return; } // otherwise assume ElGamal/AES From bcfe44db54a83f3f3206bb97e9c7b921a2e86da0 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 12:47:08 -0500 Subject: [PATCH 11/92] handle tunnel delivery instructioin for ECIESx25519 --- libi2pd/Destination.cpp | 4 +- libi2pd/Destination.h | 2 +- libi2pd/ECIESX25519AEADRatchetSession.cpp | 38 ++----------- libi2pd/ECIESX25519AEADRatchetSession.h | 7 ++- libi2pd/Garlic.cpp | 65 ++++++++++++++++++++--- libi2pd/Garlic.h | 3 +- libi2pd/RouterContext.h | 2 +- 7 files changed, 73 insertions(+), 48 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 71a5c329..ba74f61f 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -359,11 +359,11 @@ namespace client void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len) { - uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET]; + I2NPMessageType typeID = (I2NPMessageType)(buf[I2NP_HEADER_TYPEID_OFFSET]); LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); } - bool LeaseSetDestination::HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) + bool LeaseSetDestination::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { switch (typeID) { diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index 2b7f7bb8..f4483032 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -132,7 +132,7 @@ namespace client // implements GarlicDestination void HandleI2NPMessage (const uint8_t * buf, size_t len); - bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len); + bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len); void SetLeaseSet (std::shared_ptr newLeaseSet); int GetLeaseSetType () const { return m_LeaseSetType; }; diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index a258e8f7..96efe5e6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -5,7 +5,6 @@ #include "Elligator.h" #include "Tag.h" #include "I2PEndian.h" -#include "Garlic.h" #include "ECIESX25519AEADRatchetSession.h" namespace i2p @@ -36,7 +35,7 @@ namespace garlic } bool ECIESX25519AEADRatchetSession::NewIncomingSession (const i2p::data::LocalDestination& dest, - const uint8_t * buf, size_t len, CloveI2NPMsgHandler handleCloveI2NPMsg) + const uint8_t * buf, size_t len, CloveHandler handleClove) { // we are Bob // KDF1 @@ -87,12 +86,12 @@ namespace garlic } if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext) - HandlePayload (payload.data (), len - 16, handleCloveI2NPMsg); + HandlePayload (payload.data (), len - 16, handleClove); return true; } - void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg) + void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove) { size_t offset = 0; while (offset < len) @@ -110,7 +109,7 @@ namespace garlic switch (blk) { case eECIESx25519BlkGalicClove: - HandleClove (buf + offset, size, handleCloveI2NPMsg); + handleClove (buf + offset, size); break; case eECIESx25519BlkDateTime: LogPrint (eLogDebug, "Garlic: datetime"); @@ -119,7 +118,7 @@ namespace garlic LogPrint (eLogDebug, "Garlic: options"); break; case eECIESx25519BlkPadding: - LogPrint (eLogDebug, "NTCP2: padding"); + LogPrint (eLogDebug, "Garlic: padding"); break; default: LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk); @@ -127,33 +126,6 @@ namespace garlic offset += size; } } - - void ECIESX25519AEADRatchetSession::HandleClove (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg) - { - const uint8_t * buf1 = buf; - uint8_t flag = buf[0]; buf++; // flag - GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); - switch (deliveryType) - { - case eGarlicDeliveryTypeDestination: - buf += 32; // TODO: check destination - // no break here - case eGarlicDeliveryTypeLocal: - { - uint8_t typeID = buf[0]; buf++; // typeid - buf += (4 + 4); // msgID + expiration - ptrdiff_t offset = buf - buf1; - if (offset <= (int)len) - handleCloveI2NPMsg (typeID, buf, len - offset); - else - LogPrint (eLogError, "Garlic: clove is too long"); - break; - } - // TODO: tunnel - default: - LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); - } - } } } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index dd28c669..aa482d54 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -24,20 +24,19 @@ namespace garlic { public: - typedef std::function CloveI2NPMsgHandler; + typedef std::function CloveHandler; ECIESX25519AEADRatchetSession (); ~ECIESX25519AEADRatchetSession (); bool NewIncomingSession (const i2p::data::LocalDestination& dest, const uint8_t * buf, size_t len, - CloveI2NPMsgHandler handleCloveI2NPMsg); + CloveHandler handleClove); private: void MixHash (const uint8_t * buf, size_t len); - void HandlePayload (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg); - void HandleClove (const uint8_t * buf, size_t len, CloveI2NPMsgHandler& handleCloveI2NPMsg); + void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove); private: diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 5dfdfe79..aa715e0c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -833,11 +833,64 @@ namespace garlic void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len) { ECIESX25519AEADRatchetSession session; - session.NewIncomingSession (*this, buf, len, - [this](uint8_t typeID, const uint8_t * payload, size_t len) - { - HandleCloveI2NPMessage (typeID, payload,len); - }); - } + session.NewIncomingSession (*this, buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove, + this, std::placeholders::_1, std::placeholders::_2)); + } + + void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) + { + const uint8_t * buf1 = buf; + uint8_t flag = buf[0]; buf++; // flag + GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); + switch (deliveryType) + { + case eGarlicDeliveryTypeDestination: + LogPrint (eLogDebug, "Garlic: type destination"); + buf += 32; // TODO: check destination + // no break here + case eGarlicDeliveryTypeLocal: + { + LogPrint (eLogDebug, "Garlic: type local"); + I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid + buf += (4 + 4); // msgID + expiration + ptrdiff_t offset = buf - buf1; + if (offset <= (int)len) + HandleCloveI2NPMessage (typeID, buf, len - offset); + else + LogPrint (eLogError, "Garlic: clove is too long"); + break; + } + case eGarlicDeliveryTypeTunnel: + { + LogPrint (eLogDebug, "Garlic: type tunnel"); + // gwHash and gwTunnel sequence is reverted + const uint8_t * gwHash = buf; + buf += 32; + ptrdiff_t offset = buf - buf1; + if (offset + 13 > (int)len) + { + LogPrint (eLogError, "Garlic: message is too short"); + break; + } + uint32_t gwTunnel = bufbe32toh (buf); buf += 4; + I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid + buf += (4 + 4); // msgID + expiration + offset += 13; + if (GetTunnelPool ()) + { + auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel (); + if (tunnel) + tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset)); + else + LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); + } + else + LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel"); + break; + } + default: + LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); + } + } } } diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 44ab2e82..30e6ff4b 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -194,7 +194,7 @@ namespace garlic protected: virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only - virtual bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) = 0; + virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) = 0; void HandleGarlicMessage (std::shared_ptr msg); void HandleDeliveryStatusMessage (uint32_t msgID); @@ -209,6 +209,7 @@ 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: diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 1524270d..dfc05fe7 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -124,7 +124,7 @@ namespace i2p // implements GarlicDestination void HandleI2NPMessage (const uint8_t * buf, size_t len); - bool HandleCloveI2NPMessage (uint8_t typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented + bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented private: From d7d964bf57fe1cc42b142c53cd6b3593178a734d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Jan 2020 14:31:01 -0500 Subject: [PATCH 12/92] 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 () - { - 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 GarlicRoutingSession::MessageConfirmed (uint32_t msgID) - { - TagsConfirmed (msgID); - if (msgID == m_LeaseSetUpdateMsgID) - { - m_LeaseSetUpdateStatus = eLeaseSetUpToDate; - m_LeaseSetUpdateMsgID = 0; - LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); - } - else - CleanupExpiredTags (); - } - - 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 () + ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner, + std::shared_ptr destination, int numTags, bool attachLeaseSet): + GarlicRoutingSession (owner, destination, attachLeaseSet), m_NumTags (numTags) { - 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 (); + // create new session tags and session key + RAND_bytes (m_SessionKey, 32); + m_Encryption.SetKey (m_SessionKey); } - bool GarlicRoutingSession::CleanupUnconfirmedTags () + ElGamalAESSession::ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag) { - 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; + memcpy (m_SessionKey, sessionKey, 32); + m_Encryption.SetKey (m_SessionKey); + m_SessionTags.push_back (sessionTag); + m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); } - 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,43 +116,87 @@ 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; } - 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); - size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID); + 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 TagsConfirmed (uint32_t msgID); - UnconfirmedTags * GenerateSessionTags (); + 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; - 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; - std::shared_ptr m_SharedRoutingPath; public: // for HTTP only - size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; + 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 + //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); + size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID); + + void TagsConfirmed (uint32_t msgID); + UnconfirmedTags * GenerateSessionTags (); + + private: + + i2p::crypto::AESKey m_SessionKey; + std::list m_SessionTags; + int m_NumTags; + std::map > m_UnconfirmedTagsMsgs; // msgID->tags + + i2p::crypto::CBCEncryption m_Encryption; + + public: + // for HTTP only + 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 13/92] 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 14/92] 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 15/92] 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 16/92] 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 17/92] 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 18/92] 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 19/92] 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 20/92] 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 21/92] 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 22/92] 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 23/92] 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 24/92] 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 25/92] 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 26/92] 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 27/92] session tag for ECIESx25519 sessions --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 51 ++++++++++++++--------- libi2pd/ECIESX25519AEADRatchetSession.h | 21 ++++++++-- libi2pd/Garlic.cpp | 33 ++++++++++++--- libi2pd/Garlic.h | 4 +- 4 files changed, 80 insertions(+), 29 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: - - uint8_t m_CK[64], m_SessTagConstant[32]; + + union + { + uint64_t ll[8]; + uint8_t buf[64]; + + 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 28/92] 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 29/92] 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 30/92] 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 31/92] 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 32/92] 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 33/92] 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 34/92] 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 35/92] 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 36/92] 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 37/92] 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 38/92] 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 39/92] 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 40/92] 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 41/92] 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 42/92] 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 43/92] 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 44/92] 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 45/92] 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 46/92] 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 ()); - } - } - } - - bool LeaseSetDestination::Start () - { - if (!m_IsRunning) - { - 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; - } - else - return false; + 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::Stop () + void LeaseSetDestination::Stop () { - if (m_IsRunning) + m_CleanupTimer.cancel (); + m_PublishConfirmationTimer.cancel (); + m_PublishVerificationTimer.cancel (); + if (m_Pool) { - 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; + m_Pool->SetLocalDestination (nullptr); + i2p::tunnel::tunnels.StopTunnelPool (m_Pool); } - 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 47/92] 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 48/92] 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 49/92] 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 50/92] 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 51/92] 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 52/92] create session tags for ECIESX25519 --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 50 +++++++++++++++++++---- libi2pd/ECIESX25519AEADRatchetSession.h | 5 +++ libi2pd/Garlic.cpp | 5 ++- libi2pd/Garlic.h | 3 +- 4 files changed, 52 insertions(+), 11 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::HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index) + bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) { uint8_t nonce[12]; - memset (nonce, 0, 12); - htole64buf (nonce + 4, index); // tag's index + 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]; + 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 53/92] 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 54/92] 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 55/92] 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 56/92] 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 57/92] 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 58/92] 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 59/92] 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 60/92] 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 61/92] 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 62/92] 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 63/92] 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 64/92] 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 65/92] 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 66/92] 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 67/92] 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 68/92] 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 69/92] 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 @@ - + From 2c6e041ae2f1f930fd953013506151c829ee61ce Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 26 Feb 2020 13:41:35 +0000 Subject: [PATCH 70/92] rpm: make package buildable on mageia cauldron (#1476) --- contrib/rpm/i2pd-git.spec | 12 ++++++++++-- contrib/rpm/i2pd.spec | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 89e3cee9..f9571ca0 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -55,14 +55,22 @@ cd build %endif %endif +%if 0%{?mageia} > 7 +pushd build make %{?_smp_mflags} +popd +%else +make %{?_smp_mflags} +%endif %install -cd build +pushd build + %if 0%{?mageia} -cd build +pushd build %endif + chrpath -d i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 0f91c03b..b3cca8ab 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -53,14 +53,22 @@ cd build %endif %endif +%if 0%{?mageia} > 7 +pushd build make %{?_smp_mflags} +popd +%else +make %{?_smp_mflags} +%endif %install -cd build +pushd build + %if 0%{?mageia} -cd build +pushd build %endif + chrpath -d i2pd install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf From b02c9fb118be455c73873d7ec291b089323da4e3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Feb 2020 14:03:08 -0500 Subject: [PATCH 71/92] enable C++17 for gcc --- Makefile.linux | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index d1ccf143..9db660c2 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -15,13 +15,14 @@ ifeq ($(shell expr match $(CXX) 'clang'),5) NEEDED_CXXFLAGS += -std=c++11 else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 NEEDED_CXXFLAGS += -std=c++11 -else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7 +else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # gcc 4.7 - 4.9 NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 - NEEDED_CXXFLAGS += -std=c++0x -else ifeq ($(shell expr match ${CXXVER} "[5-9]"),1) # gcc >= 5 +else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6 NEEDED_CXXFLAGS += -std=c++11 LDLIBS = -latomic +else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc >= 7 + NEEDED_CXXFLAGS += -std=c++17 + LDLIBS = -latomic else # not supported $(error Compiler too old) endif From 1893127e8468e67e0cc5ccd7ffcda8686d441490 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Feb 2020 14:05:51 -0500 Subject: [PATCH 72/92] use fold expression if C++17 --- libi2pd/Log.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libi2pd/Log.h b/libi2pd/Log.h index b11c6763..ba10b5e9 100644 --- a/libi2pd/Log.h +++ b/libi2pd/Log.h @@ -161,6 +161,7 @@ void LogPrint (std::stringstream& s, TValue&& arg) noexcept s << std::forward(arg); } +#if (__cplusplus < 201703L) // below C++ 17 /** internal usage only -- folding args array to single string */ template void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept @@ -168,6 +169,7 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept LogPrint (s, std::forward(arg)); LogPrint (s, std::forward(args)...); } +#endif /** * @brief Create log message and send it to queue @@ -184,7 +186,11 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept // fold message to single string std::stringstream ss(""); +#if (__cplusplus >= 201703L) // C++ 17 or higher + (LogPrint (ss, std::forward(args)), ...); +#else LogPrint (ss, std::forward(args)...); +#endif auto msg = std::make_shared(level, std::time(nullptr), ss.str()); msg->tid = std::this_thread::get_id(); From e0cb26bd9e247c982219e639bc9b05cfacf46f11 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 28 Feb 2020 14:15:41 -0500 Subject: [PATCH 73/92] fixed fallthough warning for C++17 --- libi2pd/Garlic.cpp | 2 +- libi2pd/Identity.cpp | 2 +- libi2pd/RouterContext.cpp | 2 +- libi2pd/Streaming.cpp | 2 +- libi2pd_client/SOCKS.cpp | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index c7d0e21d..597602fb 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -911,7 +911,7 @@ namespace garlic case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: type destination"); buf += 32; // TODO: check destination - // no break here + [[fallthrough]]; // no break here case eGarlicDeliveryTypeLocal: { LogPrint (eLogDebug, "Garlic: type local"); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index de94732f..5116ecd8 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -723,7 +723,7 @@ namespace data case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); - // no break here + [[fallthrough]]; // no break here case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); break; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 2c07c21b..c282f095 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -338,7 +338,7 @@ namespace i2p { case low : /* not set */; break; case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P' - case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; // no break here, extra + high means 'X' + case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; [[fallthrough]]; // no break here, extra + high means 'X' case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; } m_RouterInfo.SetCaps (caps); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index d666d786..e486fa79 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -847,7 +847,7 @@ namespace stream break; case 2: m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time - // no break here + [[fallthrough]]; // no break here case 4: if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); UpdateCurrentRemoteLease (); // pick another lease diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index 8a67901c..c01aa212 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -433,6 +433,7 @@ namespace proxy break; case CMD_UDP: if (m_socksv == SOCKS5) break; + [[fallthrough]]; default: LogPrint(eLogError, "SOCKS: invalid command: ", ((int)*sock_buff)); SocksRequestFailed(SOCKS5_GEN_FAIL); From ed574f9d792dd0d390d631a006b85055eea9b5bc Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 28 Feb 2020 23:05:26 +0300 Subject: [PATCH 74/92] use C++17 if available when configuring with cmake --- build/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 2577fb1b..3a723c45 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -184,16 +184,16 @@ else() set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above endif () -# check for c++11 support +# check for c++17 & c++11 support include(CheckCXXCompilerFlag) +CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED) -CHECK_CXX_COMPILER_FLAG("-std=c++0x" CXX0X_SUPPORTED) -if (CXX11_SUPPORTED) +if (CXX17_SUPPORTED) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17" ) +elseif (CXX11_SUPPORTED) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -elseif (CXX0X_SUPPORTED) # gcc 4.6 - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" ) -elseif (NOT MSVC) - message(SEND_ERROR "C++11 standard not seems to be supported by compiler. Too old version?") +else + message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") endif () if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") From 2ac2da41cfa673b0ec001b700e310d63332fcc39 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 28 Feb 2020 23:28:41 +0300 Subject: [PATCH 75/92] cmake: fix else statement --- build/CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 3a723c45..f5c1280e 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -188,13 +188,13 @@ endif () include(CheckCXXCompilerFlag) CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED) -if (CXX17_SUPPORTED) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17" ) -elseif (CXX11_SUPPORTED) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -else +if(CXX17_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") +elseif(CXX11_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +else() message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") -endif () +endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe") From fe1724e7e694ab3c05492cb2dbfdae454fcf18a0 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 28 Feb 2020 23:41:42 +0300 Subject: [PATCH 76/92] switch travis-ci to xenial --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c55f1885..af47f458 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ cache: os: - linux #- osx -dist: trusty +dist: xenial sudo: required compiler: - g++ From 2ffe62ba41bffb03e2042bf4d7cc7188a2a2393d Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 29 Feb 2020 09:21:50 -0500 Subject: [PATCH 77/92] [[fallthrough]] if C++17 only --- libi2pd/Garlic.cpp | 5 ++++- libi2pd/Identity.cpp | 5 ++++- libi2pd/RouterContext.cpp | 6 +++++- libi2pd/Streaming.cpp | 5 ++++- libi2pd_client/SOCKS.cpp | 2 ++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 597602fb..45c97172 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -911,7 +911,10 @@ namespace garlic case eGarlicDeliveryTypeDestination: LogPrint (eLogDebug, "Garlic: type destination"); buf += 32; // TODO: check destination - [[fallthrough]]; // no break here +#if (__cplusplus >= 201703L) // C++ 17 or higher + [[fallthrough]]; +#endif + // no break here case eGarlicDeliveryTypeLocal: { LogPrint (eLogDebug, "Garlic: type local"); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 5116ecd8..3f9633ed 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -723,7 +723,10 @@ namespace data case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); - [[fallthrough]]; // no break here +#if (__cplusplus >= 201703L) // C++ 17 or higher + [[fallthrough]]; +#endif + // no break here case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); break; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index c282f095..6c63ef79 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -338,7 +338,11 @@ namespace i2p { case low : /* not set */; break; case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P' - case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; [[fallthrough]]; // no break here, extra + high means 'X' + case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; + #if (__cplusplus >= 201703L) // C++ 17 or higher + [[fallthrough]]; + #endif + // no break here, extra + high means 'X' case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; } m_RouterInfo.SetCaps (caps); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index e486fa79..b5f935fe 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -847,7 +847,10 @@ namespace stream break; case 2: m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time - [[fallthrough]]; // no break here +#if (__cplusplus >= 201703L) // C++ 17 or higher + [[fallthrough]]; +#endif + // no break here case 4: if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); UpdateCurrentRemoteLease (); // pick another lease diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index c01aa212..8742d4c5 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -433,7 +433,9 @@ namespace proxy break; case CMD_UDP: if (m_socksv == SOCKS5) break; +#if (__cplusplus >= 201703L) // C++ 17 or higher [[fallthrough]]; +#endif default: LogPrint(eLogError, "SOCKS: invalid command: ", ((int)*sock_buff)); SocksRequestFailed(SOCKS5_GEN_FAIL); From 97f0347715920c2e628c7ac40c9a065cfe94b5ef Mon Sep 17 00:00:00 2001 From: r4sas Date: Sat, 29 Feb 2020 23:08:43 +0000 Subject: [PATCH 78/92] Update android stuff: * switch to c++17 * use boost 1.72.0 * disable minify in release * enable apk splitting (separate apk for every ABI) * add version to output apk name Signed-off-by: r4sas --- android/build.gradle | 21 ++++++++++++++++++--- android/jni/Android.mk | 16 ++++++++-------- android/jni/Application.mk | 6 +++--- android_binary_only/jni/Android.mk | 16 ++++++++-------- android_binary_only/jni/Application.mk | 6 +++--- 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 844615f8..6fcb4521 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -32,6 +32,7 @@ android { minSdkVersion 14 versionCode 2300 versionName "2.30.0" + setProperty("archivesBaseName", archivesBaseName + "-" + versionName) ndk { abiFilters 'armeabi-v7a' abiFilters 'x86' @@ -56,9 +57,10 @@ android { splits { abi { // change that to true if you need splitted apk - enable false + enable true reset() - include "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + //include "armeabi-v7a", "arm64-v8a", "x86", "x86_64" + include "armeabi-v7a", "x86" universalApk true } } @@ -72,7 +74,7 @@ android { } buildTypes { release { - minifyEnabled true + minifyEnabled false signingConfig signingConfigs.orignal proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' } @@ -87,3 +89,16 @@ android { targetCompatibility = '1.8' } } + +ext.abiCodes = ['armeabi-v7a':1, 'x86':2, 'arm64-v8a':3, 'x86_64':4] +import com.android.build.OutputFile + +android.applicationVariants.all { variant -> + variant.outputs.each { output -> + def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) + + if (baseAbiVersionCode != null) { + output.versionCodeOverride = baseAbiVersionCode + variant.versionCode + } + } +} diff --git a/android/jni/Android.mk b/android/jni/Android.mk index d44fcc5a..2376509e 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -25,29 +25,29 @@ include $(BUILD_SHARED_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_system -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_date_time -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_filesystem -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_program_options -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 6d51ac1a..0c291661 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,15 +9,15 @@ NDK_TOOLCHAIN_VERSION := clang #APP_STL := c++_shared APP_STL := c++_static -# Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 -fexceptions -frtti +# Enable c++17 extensions in source code +APP_CPPFLAGS += -std=c++17 -fexceptions -frtti APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif -# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0 # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git diff --git a/android_binary_only/jni/Android.mk b/android_binary_only/jni/Android.mk index 7e73b23d..a59e32e5 100755 --- a/android_binary_only/jni/Android.mk +++ b/android_binary_only/jni/Android.mk @@ -26,29 +26,29 @@ include $(BUILD_EXECUTABLE) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_system -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_date_time -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_filesystem -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := boost_program_options -LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a -LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include +LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) diff --git a/android_binary_only/jni/Application.mk b/android_binary_only/jni/Application.mk index 655bf430..bb4afac3 100755 --- a/android_binary_only/jni/Application.mk +++ b/android_binary_only/jni/Application.mk @@ -9,8 +9,8 @@ APP_PLATFORM := android-14 NDK_TOOLCHAIN_VERSION := clang APP_STL := c++_static -# Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE +# Enable c++17 extensions in source code +APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP APP_LDFLAGS += -rdynamic -fPIE -pie @@ -21,7 +21,7 @@ endif # Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead. #APP_OPTIM := debug -# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0 # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git From 4f0da87a7a11e399aedb6fedb67c037de5a6aaa0 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sun, 1 Mar 2020 14:35:24 +0000 Subject: [PATCH 79/92] add ntcp2proxy support --- libi2pd/Config.cpp | 7 +- libi2pd/NTCP2.cpp | 599 +++++++++++++++++++++++++++++------------ libi2pd/NTCP2.h | 67 +++-- libi2pd/Transports.cpp | 80 ++++-- 4 files changed, 534 insertions(+), 219 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index b0f7572d..4050f769 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -61,6 +61,7 @@ namespace config { ("ntcp", value()->default_value(false), "Enable NTCP transport (default: disabled)") ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") + ("ntcp2proxy", value()->default_value(""), "Proxy URL for NTCP2 transport") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") @@ -305,16 +306,16 @@ namespace config { std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; std::cout << m_OptionsDesc; exit(EXIT_SUCCESS); - } + } else if (m_Options.count("version")) { std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; - std::cout << "Boost version " + std::cout << "Boost version " << BOOST_VERSION / 100000 << "." // maj. version << BOOST_VERSION / 100 % 1000 << "." // min. version << BOOST_VERSION % 100 // patch version << std::endl; -#if defined(OPENSSL_VERSION_TEXT) +#if defined(OPENSSL_VERSION_TEXT) std::cout << OPENSSL_VERSION_TEXT << std::endl; #endif #if defined(LIBRESSL_VERSION_TEXT) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 034f7e21..a3c42790 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -20,19 +20,21 @@ #include "Transports.h" #include "NetDb.hpp" #include "NTCP2.h" +#include "HTTP.h" +#include "util.h" namespace i2p { namespace transport { NTCP2Establisher::NTCP2Establisher (): - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) - { + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) + { } - NTCP2Establisher::~NTCP2Establisher () - { - delete[] m_SessionRequestBuffer; + NTCP2Establisher::~NTCP2Establisher () + { + delete[] m_SessionRequestBuffer; delete[] m_SessionCreatedBuffer; delete[] m_SessionConfirmedBuffer; } @@ -54,22 +56,22 @@ namespace transport void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) { - static const uint8_t protocolNameHash[] = - { - 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, - 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 + static const uint8_t protocolNameHash[] = + { + 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, + 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") - static const uint8_t hh[32] = - { - 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, - 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e + static const uint8_t hh[32] = + { + 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, + 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) - memcpy (m_CK, protocolNameHash, 32); + memcpy (m_CK, protocolNameHash, 32); // h = SHA256(hh || rs) SHA256_CTX ctx; SHA256_Init (&ctx); - SHA256_Update (&ctx, hh, 32); - SHA256_Update (&ctx, rs, 32); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, rs, 32); SHA256_Final (m_H, &ctx); // h = SHA256(h || epub) MixHash (epub, 32); @@ -83,25 +85,25 @@ namespace transport { KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralKeys, m_RemoteStaticKey, GetPub ()); } - + void NTCP2Establisher::KDF1Bob () { - KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); + KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); } void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) - { - MixHash (sessionRequest + 32, 32); // encrypted payload + { + MixHash (sessionRequest + 32, 32); // encrypted payload int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) MixHash (sessionRequest + 64, paddingLength); - MixHash (epub, 32); + MixHash (epub, 32); // x25519 between remote pub and ephemaral priv uint8_t inputKeyMaterial[32]; m_EphemeralKeys.Agree (GetRemotePub (), inputKeyMaterial); - + MixKey (inputKeyMaterial); } @@ -109,7 +111,7 @@ namespace transport { KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); } - + void NTCP2Establisher::KDF2Bob () { KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); @@ -118,14 +120,14 @@ namespace transport void NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; - i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); + i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); MixKey (inputKeyMaterial); } void NTCP2Establisher::KDF3Bob () { uint8_t inputKeyMaterial[32]; - m_EphemeralKeys.Agree (m_RemoteStaticKey, inputKeyMaterial); + m_EphemeralKeys.Agree (m_RemoteStaticKey, inputKeyMaterial); MixKey (inputKeyMaterial); } @@ -146,30 +148,30 @@ namespace transport encryption.SetKey (m_RemoteIdentHash); encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X - encryption.GetIV (m_IV); // save IV for SessionCreated + encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block KDF1Alice (); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); options[0] = i2p::context.GetNetID (); // network ID - options[1] = 2; // ver + options[1] = 2; // ver htobe16buf (options + 2, paddingLength); // padLen - // m3p2Len + // m3p2Len auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen (); - m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options + m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options htobe16buf (options + 4, m3p2Len); - // fill m3p2 payload (RouterInfo block) + // fill m3p2 payload (RouterInfo block) m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; m3p2[0] = eNTCP2BlkRouterInfo; // block htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI - m3p2[3] = 0; // flag + m3p2[3] = 0; // flag memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved - // sign and encrypt options, use m_H as AD + // 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, GetH (), 32, GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt @@ -179,7 +181,7 @@ namespace transport { auto paddingLen = rand () % (287 - 64); m_SessionCreatedBufferLen = paddingLen + 64; - m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; + m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // encrypt Y i2p::crypto::CBCEncryption encryption; @@ -187,12 +189,12 @@ namespace transport encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - KDF2Bob (); + KDF2Bob (); uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB - // sign and encrypt options, use m_H as AD + // 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, GetH (), 32, GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt @@ -205,9 +207,9 @@ namespace transport MixHash (m_SessionCreatedBuffer + 32, 32); // encrypted payload int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) - MixHash (m_SessionCreatedBuffer + 64, paddingLength); + MixHash (m_SessionCreatedBuffer + 64, paddingLength); - // part1 48 bytes + // part1 48 bytes i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, GetH (), 32, GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt } @@ -215,14 +217,14 @@ namespace transport { // part 2 // update AD again - MixHash (m_SessionConfirmedBuffer, 48); + MixHash (m_SessionConfirmedBuffer, 48); // encrypt m3p2, it must be filled in SessionRequest - KDF3Alice (); + KDF3Alice (); uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; - i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, GetH (), 32, GetK (), 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) - } + } bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen) { @@ -231,7 +233,7 @@ namespace transport decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); - decryption.GetIV (m_IV); // save IV for SessionCreated + decryption.GetIV (m_IV); // save IV for SessionCreated // decryption key for next block KDF1Bob (); // verify MAC and decrypt options block (32 bytes), use m_H as AD @@ -245,7 +247,7 @@ namespace transport LogPrint (eLogWarning, "NTCP2: SessionRequest networkID ", (int)options[0], " mismatch. Expected ", i2p::context.GetNetID ()); return false; } - if (options[1] == 2) // ver is always 2 + if (options[1] == 2) // ver is always 2 { paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; @@ -253,11 +255,11 @@ namespace transport if (m3p2Len < 16) { LogPrint (eLogWarning, "NTCP2: SessionRequest m3p2len=", m3p2Len, " is too short"); - return false; - } + return false; + } // check timestamp auto ts = i2p::util::GetSecondsSinceEpoch (); - uint32_t tsA = bufbe32toh (options + 8); + uint32_t tsA = bufbe32toh (options + 8); if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW) { LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew"); @@ -274,8 +276,8 @@ namespace transport { LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed "); return false; - } - return true; + } + return true; } bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen) @@ -294,11 +296,11 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, GetH (), 32, GetK (), nonce, payload, 16, false)) // decrypt { - // options + // options paddingLen = bufbe16toh(payload + 2); // check timestamp auto ts = i2p::util::GetSecondsSinceEpoch (); - uint32_t tsB = bufbe32toh (payload + 8); + uint32_t tsB = bufbe32toh (payload + 8); if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW) { LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", (int)(ts - tsB), " exceeds clock skew"); @@ -306,10 +308,10 @@ namespace transport } } else - { + { LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed "); return false; - } + } return true; } @@ -320,7 +322,7 @@ namespace transport int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) MixHash (m_SessionCreatedBuffer + 64, paddingLength); - + 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 "); @@ -332,9 +334,9 @@ namespace transport bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf) { // update AD again - MixHash (m_SessionConfirmedBuffer, 48); + MixHash (m_SessionConfirmedBuffer, 48); - KDF3Bob (); + KDF3Bob (); 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 @@ -350,8 +352,8 @@ namespace transport } NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): - TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), - m_Server (server), m_Socket (m_Server.GetService ()), + TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), + m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_Establisher (new NTCP2Establisher), m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr), @@ -371,10 +373,82 @@ namespace transport memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); } else - LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } } + void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + { + + // build request + size_t sz = 0; + uint8_t buff[256]; + uint8_t readbuff[256]; + buff[0] = 0x05; + buff[1] = 0x01; + buff[2] = 0x00; + + if(addrtype == eIP4Address) + { + buff[3] = 0x01; + auto addr = boost::asio::ip::address::from_string(host).to_v4(); + auto addrbytes = addr.to_bytes(); + auto addrsize = addrbytes.size(); + memcpy(buff+4, addrbytes.data(), addrsize); + } + else if (addrtype == eIP6Address) + { + buff[3] = 0x04; + auto addr = boost::asio::ip::address::from_string(host).to_v6(); + auto addrbytes = addr.to_bytes(); + auto addrsize = addrbytes.size(); + memcpy(buff+4, addrbytes.data(), addrsize); + } + else if (addrtype == eHostname) + { + buff[3] = 0x03; + size_t addrsize = host.size(); + sz = addrsize + 1 + 4; + if (2 + sz > sizeof(buff)) + { + // too big + return; + } + buff[4] = (uint8_t) addrsize; + memcpy(buff+5, host.c_str(), addrsize); + } + htobe16buf(buff+sz, port); + sz += 2; + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, sz), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t written) { + if(ec) + { + LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message()); + return; + } + }); + + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 10), [=](const boost::system::error_code & e, std::size_t transferred) { + if(e) + { + LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message()); + } + else if(transferred == sz) + { + if( readbuff[1] == 0x00) + { + timer->cancel(); + conn->ClientLogin(); + return; + } + } + if(!e) + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + timer->cancel(); + conn->Terminate(); + }); + } + + NTCP2Session::~NTCP2Session () { delete[] m_NextReceivedBuffer; @@ -425,8 +499,8 @@ namespace transport void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) { - memset (nonce, 0, 4); - htole64buf (nonce + 4, seqn); + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); } @@ -442,7 +516,7 @@ namespace transport memcpy (h + 32, "siphash", 7); i2p::crypto::HKDF (master, h, 39, "", master, 32); // sip_master = HKDF(ask_master, h || "siphash") i2p::crypto::HKDF (master, nullptr, 0, "", k); // sipkeys_ab, sipkeys_ba = HKDF(sip_master, zerolen) - memcpy (m_Sipkeysab, k, 32); memcpy (m_Sipkeysba, k + 32, 32); + memcpy (m_Sipkeysab, k, 32); memcpy (m_Sipkeysba, k + 32, 32); } @@ -451,8 +525,8 @@ namespace transport m_Establisher->CreateSessionRequestMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - } + std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { @@ -500,7 +574,7 @@ namespace transport } else SendSessionCreated (); - } + } else Terminate (); } @@ -520,9 +594,9 @@ namespace transport void NTCP2Session::SendSessionCreated () { m_Establisher->CreateSessionCreatedMessage (); - // send message + // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -577,9 +651,9 @@ namespace transport { uint8_t nonce[12]; CreateNonce (1, nonce); // set nonce to 1 - m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); + m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); memset (nonce, 0, 12); // set nonce back to 0 - m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); + m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -594,12 +668,12 @@ namespace transport Terminate (); } else - { + { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); // Alice data phase keys m_SendKey = m_Kab; - m_ReceiveKey = m_Kba; + m_ReceiveKey = m_Kba; SetSipKeys (m_Sipkeysab, m_Sipkeysba); memcpy (m_ReceiveIV.buf, m_Sipkeysba + 16, 8); memcpy (m_SendIV.buf, m_Sipkeysab + 16, 8); @@ -609,7 +683,7 @@ namespace transport // TODO: remove // m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); // SendQueue (); - } + } } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -623,7 +697,7 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); - m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -652,7 +726,7 @@ namespace transport KeyDerivationFunctionDataPhase (); // Bob data phase keys m_SendKey = m_Kba; - m_ReceiveKey = m_Kab; + m_ReceiveKey = m_Kab; SetSipKeys (m_Sipkeysba, m_Sipkeysab); memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); @@ -660,8 +734,8 @@ namespace transport // process RI if (buf[0] != eNTCP2BlkRouterInfo) { - LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); - Terminate (); + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); + Terminate (); return; } auto size = bufbe16toh (buf.data () + 1); @@ -675,33 +749,33 @@ namespace transport i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag if (ri.IsUnreachable ()) { - LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); - SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); + LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); return; } if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes { - LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed"); - SendTerminationAndTerminate (eNTCP2Message3Error); + LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2Message3Error); return; } auto addr = ri.GetNTCP2Address (false); // any NTCP2 address if (!addr) { - LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); + LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); Terminate (); return; } if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) { - LogPrint (eLogError, "NTCP2: Static key mismatch in SessionConfirmed"); - SendTerminationAndTerminate (eNTCP2IncorrectSParameter); + LogPrint (eLogError, "NTCP2: Static key mismatch in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2IncorrectSParameter); return; } i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice // TODO: process options - - // ready to communicate + + // ready to communicate auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); m_Server.AddNTCP2Session (shared_from_this (), true); @@ -720,13 +794,13 @@ namespace transport { #if OPENSSL_SIPHASH m_SendSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16); - m_SendMDCtx = EVP_MD_CTX_create (); + m_SendMDCtx = EVP_MD_CTX_create (); EVP_PKEY_CTX *ctx = nullptr; EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, m_SendSipKey); - EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); + EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); m_ReceiveSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16); - m_ReceiveMDCtx = EVP_MD_CTX_create (); + m_ReceiveMDCtx = EVP_MD_CTX_create (); ctx = nullptr; EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, m_ReceiveSipKey); EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); @@ -770,9 +844,9 @@ namespace transport { #if OPENSSL_SIPHASH EVP_DigestSignInit (m_ReceiveMDCtx, nullptr, nullptr, nullptr, nullptr); - EVP_DigestSignUpdate (m_ReceiveMDCtx, m_ReceiveIV.buf, 8); - size_t l = 8; - EVP_DigestSignFinal (m_ReceiveMDCtx, m_ReceiveIV.buf, &l); + EVP_DigestSignUpdate (m_ReceiveMDCtx, m_ReceiveIV.buf, 8); + size_t l = 8; + EVP_DigestSignFinal (m_ReceiveMDCtx, m_ReceiveIV.buf, &l); #else i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); #endif @@ -780,7 +854,7 @@ namespace transport m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); if (m_NextReceivedLen >= 16) - { + { if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; boost::system::error_code ec; @@ -798,7 +872,7 @@ namespace transport { LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short"); Terminate (); - } + } } } @@ -825,7 +899,7 @@ namespace transport uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) - { + { LogPrint (eLogDebug, "NTCP2: received message decrypted"); ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore @@ -835,7 +909,7 @@ namespace transport { LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed "); SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure); - } + } } } @@ -858,7 +932,7 @@ namespace transport { case eNTCP2BlkDateTime: LogPrint (eLogDebug, "NTCP2: datetime"); - break; + break; case eNTCP2BlkOptions: LogPrint (eLogDebug, "NTCP2: options"); break; @@ -881,11 +955,11 @@ namespace transport nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); nextMsg->FromNTCP2 (); - m_Handler.PutNextMessage (nextMsg); + m_Handler.PutNextMessage (nextMsg); break; } case eNTCP2BlkTermination: - if (size >= 9) + if (size >= 9) { LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 8])); Terminate (); @@ -908,46 +982,46 @@ namespace transport { #if OPENSSL_SIPHASH EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr); - EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8); - size_t l = 8; - EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l); + EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8); + size_t l = 8; + EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l); #else i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); #endif // length must be in BigEndian htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key)); LogPrint (eLogDebug, "NTCP2: sent length ", frameLen); - } + } void NTCP2Session::SendI2NPMsgs (std::vector >& msgs) { if (msgs.empty () || IsTerminated ()) return; - + size_t totalLen = 0; std::vector > encryptBufs; - std::vector bufs; + std::vector bufs; std::shared_ptr first; uint8_t * macBuf = nullptr; - for (auto& it: msgs) - { + for (auto& it: msgs) + { it->ToNTCP2 (); auto buf = it->GetNTCP2Header (); auto len = it->GetNTCP2Length (); // block header - buf -= 3; + buf -= 3; buf[0] = eNTCP2BlkI2NPMessage; // blk htobe16buf (buf + 1, len); // size - len += 3; - totalLen += len; + len += 3; + totalLen += len; encryptBufs.push_back ( {buf, len} ); if (&it == &msgs.front ()) // first message { // allocate two bytes for length buf -= 2; len += 2; first = it; - } + } if (&it == &msgs.back () && it->len + 16 < it->maxLen) // last message - { + { // if it's long enough we add padding and MAC to it // create padding block auto paddingLen = CreatePaddingBlock (totalLen, buf + len, it->maxLen - it->len - 16); @@ -960,8 +1034,8 @@ namespace transport macBuf = buf + len; // allocate 16 bytes for MAC len += 16; - } - + } + bufs.push_back (boost::asio::buffer (buf, len)); } @@ -973,42 +1047,42 @@ namespace transport auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16); // and padding block to encrypt and send if (paddingLen) - encryptBufs.push_back ( {m_NextSendBuffer, paddingLen} ); + encryptBufs.push_back ( {m_NextSendBuffer, paddingLen} ); bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16)); macBuf = m_NextSendBuffer + paddingLen; - totalLen += paddingLen; + totalLen += paddingLen; } uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block - + // send buffers - m_IsSending = true; + m_IsSending = true; boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleI2NPMsgsSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); - } + } void NTCP2Session::HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector > msgs) { HandleNextFrameSent (ecode, bytes_transferred); // msgs get destroyed here } - + void NTCP2Session::EncryptAndSendNextBuffer (size_t payloadLen) { - if (IsTerminated ()) + if (IsTerminated ()) { delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; - return; + return; } // encrypt uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; - i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); + i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer); // send - m_IsSending = true; + m_IsSending = true; boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, payloadLen + 16 + 2), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -1017,23 +1091,23 @@ namespace transport { m_IsSending = false; delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; - + if (ecode) { if (ecode != boost::asio::error::operation_aborted) LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ()); Terminate (); - } + } else - { + { m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumSentBytes += bytes_transferred; i2p::transport::transports.UpdateSentBytes (bytes_transferred); LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred); SendQueue (); - } + } } - + void NTCP2Session::SendQueue () { if (!m_SendQueue.empty ()) @@ -1043,7 +1117,7 @@ namespace transport while (!m_SendQueue.empty ()) { auto msg = m_SendQueue.front (); - size_t len = msg->GetNTCP2Length (); + size_t len = msg->GetNTCP2Length (); if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header { msgs.push_back (msg); @@ -1059,12 +1133,12 @@ namespace transport break; } SendI2NPMsgs (msgs); - } + } } size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len) { - if (len < 3) return 0; + if (len < 3) return 0; len -= 3; if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; @@ -1073,10 +1147,10 @@ namespace transport if (paddingSize) paddingSize = rand () % paddingSize; buf[0] = eNTCP2BlkPadding; // blk htobe16buf (buf + 1, paddingSize); // size - memset (buf + 3, 0, paddingSize); + memset (buf + 3, 0, paddingSize); return paddingSize + 3; - } - + } + void NTCP2Session::SendRouterInfo () { if (!IsEstablished ()) return; @@ -1094,14 +1168,158 @@ namespace transport EncryptAndSendNextBuffer (payloadLen); } + void NTCP2Server::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port) + { + m_ProxyType = proxytype; + m_ProxyAddress = addr; + m_ProxyPort = port; + } + + void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + { + if(ecode) + { + LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); + timer->cancel(); + conn->Terminate(); + return; + } + if(m_ProxyType == eSocksProxy) + { + // TODO: support username/password auth etc + uint8_t buff[3] = {0x05, 0x01, 0x00}; + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), [=] (const boost::system::error_code & ec, std::size_t transferred) { + (void) transferred; + if(ec) + { + LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); + } + }); + uint8_t readbuff[2]; + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 2), [=](const boost::system::error_code & ec, std::size_t transferred) + { + LogPrint(eLogError, "NTCP2: ", transferred); + if(ec) + { + LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + return; + } + else if(transferred == 2) + { + if(readbuff[1] == 0xba) + { + AfterSocksHandshake(conn, timer, host, port, addrtype); + return; + } + else if (readbuff[1] == 0xff) + { + LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); + timer->cancel(); + conn->Terminate(); + return; + } + LogPrint(eLogError, "NTCP2:", readbuff[1]); + } + LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); + timer->cancel(); + conn->Terminate(); + }); + } + else if(m_ProxyType == eHTTPProxy) + { + i2p::http::HTTPReq req; + req.method = "CONNECT"; + req.version ="HTTP/1.1"; + if(addrtype == eIP6Address) + req.uri = "[" + host + "]:" + std::to_string(port); + else + req.uri = host + ":" + std::to_string(port); + + boost::asio::streambuf writebuff; + std::ostream out(&writebuff); + out << req.to_string(); + + boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t transferred) { + (void) transferred; + if(ec) + LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); + }); + + boost::asio::streambuf * readbuff = new boost::asio::streambuf; + boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", [=] (const boost::system::error_code & ec, std::size_t transferred) { + if(ec) + { + LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + } + else + { + readbuff->commit(transferred); + i2p::http::HTTPRes res; + if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) + { + if(res.code == 200) + { + timer->cancel(); + conn->ClientLogin(); + delete readbuff; + return; + } + else + { + LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); + } + } + else + LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); + timer->cancel(); + conn->Terminate(); + delete readbuff; + } + }); + } + else + LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); + } + + void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) + { + if(m_ProxyEndpoint == nullptr) + { + return; + } + GetService().post([=]() { + if (this->AddNTCP2Session (conn)) + { + + auto timer = std::make_shared(GetService()); + auto timeout = NTCP_CONNECT_TIMEOUT * 5; + conn->SetTerminationTimeout(timeout * 2); + timer->expires_from_now (boost::posix_time::seconds(timeout)); + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + conn->Terminate (); + } + }); + conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); + } + }); + } + void NTCP2Session::SendTermination (NTCP2TerminationReason reason) { if (!m_SendKey || !m_SendSipKey) return; - m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block + m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block // termination block m_NextSendBuffer[2] = eNTCP2BlkTermination; m_NextSendBuffer[3] = 0; m_NextSendBuffer[4] = 9; // 9 bytes block size - htobe64buf (m_NextSendBuffer + 5, m_ReceiveSequenceNumber); + htobe64buf (m_NextSendBuffer + 5, m_ReceiveSequenceNumber); m_NextSendBuffer[13] = (uint8_t)reason; // padding block auto paddingSize = CreatePaddingBlock (12, m_NextSendBuffer + 14, 19); @@ -1125,13 +1343,13 @@ namespace transport if (m_IsTerminated) return; for (auto it: msgs) m_SendQueue.push_back (it); - if (!m_IsSending) - SendQueue (); + if (!m_IsSending) + SendQueue (); else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE) { LogPrint (eLogWarning, "NTCP2: outgoing messages queue size exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE); Terminate (); - } + } } void NTCP2Session::SendLocalRouterInfo () @@ -1142,6 +1360,7 @@ namespace transport NTCP2Server::NTCP2Server (): RunnableServiceWithWork ("NTCP2"), + m_ProxyType(eNoProxy), m_Resolver(GetService ()), m_ProxyEndpoint(nullptr), m_TerminationTimer (GetService ()) { } @@ -1156,45 +1375,69 @@ namespace transport if (!IsRunning ()) { StartIOService (); - auto& addresses = context.GetRouterInfo ().GetAddresses (); - for (const auto& address: addresses) + if(UsingProxy()) + { + LogPrint(eLogError, "NTCP2: USING PROXY "); + // TODO: resolve proxy until it is resolved + boost::asio::ip::tcp::resolver::query q(m_ProxyAddress, std::to_string(m_ProxyPort)); + boost::system::error_code e; + auto itr = m_Resolver.resolve(q, e); + if(e) + { + LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message()); + } + else + { + m_ProxyEndpoint = new boost::asio::ip::tcp::endpoint(*itr); + if (m_ProxyEndpoint) + { + LogPrint(eLogError, "NTCP2: m_ProxyEndpoint %s", m_ProxyEndpoint); + } + } + } + else { - if (!address) continue; - if (address->IsPublishedNTCP2 ()) + LogPrint(eLogError, "NTCP2: NOTUSING PROXY "); + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (const auto& address: addresses) { - if (address->host.is_v4()) + if (!address) continue; + if (address->IsPublishedNTCP2 ()) { - try + if (address->host.is_v4()) { - 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 ) - { - LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what()); - continue; + try + { + 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 ) + { + LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what()); + continue; + } + + LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port); + auto conn = std::make_shared(*this); + m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); } - - LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port); - auto conn = std::make_shared(*this); - m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); - } - else if (address->host.is_v6() && context.SupportsV6 ()) - { - m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ())); - try + else if (address->host.is_v6() && context.SupportsV6 ()) { - m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); - m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); - m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true)); - m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); - m_NTCP2V6Acceptor->listen (); - - LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port); - auto conn = std::make_shared (*this); - m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1)); - } catch ( std::exception & ex ) { - LogPrint(eLogError, "NTCP2: failed to bind to ip6 port ", address->port); - continue; + m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ())); + try + { + m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); + m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); + m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true)); + m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); + m_NTCP2V6Acceptor->listen (); + + LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port); + auto conn = std::make_shared (*this); + m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1)); + } catch ( std::exception & ex ) { + LogPrint(eLogError, "NTCP2: failed to bind to ip6 port ", address->port); + continue; + } } } } @@ -1216,14 +1459,21 @@ namespace transport m_NTCP2Sessions.clear (); if (IsRunning ()) + { m_TerminationTimer.cancel (); + if(m_ProxyEndpoint) + { + delete m_ProxyEndpoint; + m_ProxyEndpoint = nullptr; + } + } StopIOService (); } bool NTCP2Server::AddNTCP2Session (std::shared_ptr session, bool incoming) { if (!session) return false; - if (incoming) + if (incoming) m_PendingIncomingSessions.remove (session); if (!session->GetRemoteIdentity ()) return false; auto& ident = session->GetRemoteIdentity ()->GetIdentHash (); @@ -1255,7 +1505,7 @@ 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); - GetService ().post([this, address, port, conn]() + GetService ().post([this, address, port, conn]() { if (this->AddNTCP2Session (conn)) { @@ -1263,7 +1513,7 @@ namespace transport auto timeout = NTCP2_CONNECT_TIMEOUT * 5; conn->SetTerminationTimeout(timeout * 2); timer->expires_from_now (boost::posix_time::seconds(timeout)); - timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) { if (ecode != boost::asio::error::operation_aborted) { @@ -1391,4 +1641,3 @@ namespace transport } } } - diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 7e3c53e8..9e784c88 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -28,7 +28,7 @@ namespace i2p namespace transport { - const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; + const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; const int NTCP2_MAX_PADDING_RATIO = 6; // in % const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds @@ -36,7 +36,7 @@ namespace transport const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds - const int NTCP2_CLOCK_SKEW = 60; // in seconds + const int NTCP2_CLOCK_SKEW = 60; // in seconds const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up enum NTCP2BlockType @@ -46,8 +46,8 @@ namespace transport eNTCP2BlkRouterInfo, // 2 eNTCP2BlkI2NPMessage, // 3 eNTCP2BlkTermination, // 4 - eNTCP2BlkPadding = 254 - }; + eNTCP2BlkPadding = 254 + }; enum NTCP2TerminationReason { @@ -69,16 +69,16 @@ namespace transport eNTCP2RouterInfoSignatureVerificationFail, // 15 eNTCP2IncorrectSParameter, // 16 eNTCP2Banned, // 17 - }; - + }; + // RouterInfo flags - const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; + const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; struct NTCP2Establisher { NTCP2Establisher (); ~NTCP2Establisher (); - + const uint8_t * GetPub () const { return m_EphemeralKeys.GetPublicKey (); }; const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set @@ -114,19 +114,20 @@ namespace transport uint8_t m_RemoteEphemeralPublicKey[32]; // x25519 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; + uint16_t m3p2Len; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; - }; + }; class NTCP2Server; class NTCP2Session: public TransportSession, public std::enable_shared_from_this { public: - NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); + + NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCP2Session (); void Terminate (); void TerminateByTimeout (); @@ -138,9 +139,9 @@ namespace transport bool IsEstablished () const { return m_IsEstablished; }; bool IsTerminated () const { return m_IsTerminated; }; - void ClientLogin (); // Alice + void ClientLogin (); // Alice void ServerLogin (); // Bob - + void SendLocalRouterInfo (); // after handshake void SendI2NPMessages (const std::vector >& msgs); @@ -193,15 +194,15 @@ namespace transport std::unique_ptr m_Establisher; // data phase - uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32]; + uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32]; const uint8_t * m_SendKey, * m_ReceiveKey; -#if OPENSSL_SIPHASH +#if OPENSSL_SIPHASH EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey; EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx; #else const uint8_t * m_SendSipKey, * m_ReceiveSipKey; #endif - uint16_t m_NextReceivedLen; + uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; union { @@ -220,6 +221,20 @@ namespace transport { public: + enum RemoteAddressType + { + eIP4Address, + eIP6Address, + eHostname + }; + + enum ProxyType + { + eNoProxy, + eSocksProxy, + eHTTPProxy + }; + NTCP2Server (); ~NTCP2Server (); @@ -230,15 +245,23 @@ 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); - + + void ConnectWithProxy (const std::string& addr, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn); void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); + void AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype); + + + bool UsingProxy() const { return m_ProxyType != eNoProxy; }; + void UseProxy(ProxyType proxy, const std::string & address, uint16_t port); + private: void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); - void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); + void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType adddrtype); // timer void ScheduleTermination (); @@ -248,9 +271,15 @@ namespace transport boost::asio::deadline_timer m_TerminationTimer; std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; - std::map > m_NTCP2Sessions; + std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; + ProxyType m_ProxyType; + std::string m_ProxyAddress; + uint16_t m_ProxyPort; + boost::asio::ip::tcp::resolver m_Resolver; + boost::asio::ip::tcp::endpoint * m_ProxyEndpoint; + public: // for HTTP/I2PControl diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 42a605a4..34ec25f4 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -157,6 +157,7 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy); + std::string ntcp2proxy; i2p::config::GetOption("ntcp2proxy", ntcp2proxy); i2p::http::URL proxyurl; uint16_t softLimit, hardLimit, threads; i2p::config::GetOption("limits.ntcpsoft", softLimit); @@ -196,13 +197,36 @@ namespace transport LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy); return; } - // create NTCP2. TODO: move to acceptor + // create NTCP2. TODO: move to acceptor bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { - m_NTCP2Server = new NTCP2Server (); - m_NTCP2Server->Start (); - } + if(ntcp2proxy.size()) + { + if(proxyurl.parse(ntcp2proxy)) + { + if(proxyurl.schema == "socks" || proxyurl.schema == "http") + { + m_NTCP2Server = new NTCP2Server (); + NTCP2Server::ProxyType proxytype = NTCP2Server::eSocksProxy; + + if (proxyurl.schema == "http") + proxytype = NTCP2Server::eHTTPProxy; + + m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port) ; + m_NTCP2Server->Start(); + } + else + LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy); + } + else + LogPrint(eLogError, "Transports: invalid NTCP2 proxy url ", ntcp2proxy); + return; + } + + // m_NTCP2Server = new NTCP2Server (); + // m_NTCP2Server->Start (); + } // create acceptors auto& addresses = context.GetRouterInfo ().GetAddresses (); @@ -405,24 +429,36 @@ namespace transport { if (peer.router) // we have RI already { - if (!peer.numAttempts) // NTCP2 - { - peer.numAttempts++; - if (m_NTCP2Server) // we support NTCP2 - { - // NTCP2 have priority over NTCP - auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only - if (address) - { - auto s = std::make_shared (*m_NTCP2Server, peer.router); - m_NTCP2Server->Connect (address->host, address->port, s); - return true; - } - } - } + if (!peer.numAttempts) // NTCP2 + { + peer.numAttempts++; + if (m_NTCP2Server) // we support NTCP2 + { + // NTCP2 have priority over NTCP + auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + + if(m_NTCP2Server->UsingProxy()) + { + NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address; + std::string addr = address->host.to_string(); + + if(address->host.is_v6()) + remote = NTCP2Server::eIP6Address; + + m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s); + } + else + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + } + } if (peer.numAttempts == 1) // NTCP1 { - peer.numAttempts++; + peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { @@ -650,14 +686,14 @@ namespace transport { auto before = it->second.sessions.size (); it->second.sessions.remove (session); - if (it->second.sessions.empty ()) + if (it->second.sessions.empty ()) { if (it->second.delayedMessages.size () > 0) { if (before > 0) // we had an active session before it->second.numAttempts = 0; // start over ConnectToPeer (ident, it->second); - } + } else { std::unique_lock l(m_PeersMutex); From ae20e3aa953fb9926b9ca14838df578d9dcefe40 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Mar 2020 11:24:18 -0500 Subject: [PATCH 80/92] NTCP2 proxy --- libi2pd/NTCP2.cpp | 144 +++++++++++++++++++++++----------------------- libi2pd/NTCP2.h | 4 +- 2 files changed, 73 insertions(+), 75 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a3c42790..10cc3d89 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1175,16 +1175,18 @@ namespace transport m_ProxyPort = port; } - void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + { + if (ecode) { - if(ecode) - { - LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); - timer->cancel(); - conn->Terminate(); - return; - } - if(m_ProxyType == eSocksProxy) + LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); + timer->cancel(); + conn->Terminate(); + return; + } + switch (m_ProxyType) + { + case eSocksProxy: { // TODO: support username/password auth etc uint8_t buff[3] = {0x05, 0x01, 0x00}; @@ -1196,7 +1198,8 @@ namespace transport } }); uint8_t readbuff[2]; - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 2), [=](const boost::system::error_code & ec, std::size_t transferred) + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 2), + [=](const boost::system::error_code & ec, std::size_t transferred) { LogPrint(eLogError, "NTCP2: ", transferred); if(ec) @@ -1226,71 +1229,73 @@ namespace transport timer->cancel(); conn->Terminate(); }); + break; } - else if(m_ProxyType == eHTTPProxy) - { - i2p::http::HTTPReq req; - req.method = "CONNECT"; - req.version ="HTTP/1.1"; - if(addrtype == eIP6Address) - req.uri = "[" + host + "]:" + std::to_string(port); - else - req.uri = host + ":" + std::to_string(port); + case eHTTPProxy: + { + i2p::http::HTTPReq req; + req.method = "CONNECT"; + req.version ="HTTP/1.1"; + if(addrtype == eIP6Address) + req.uri = "[" + host + "]:" + std::to_string(port); + else + req.uri = host + ":" + std::to_string(port); - boost::asio::streambuf writebuff; - std::ostream out(&writebuff); - out << req.to_string(); + boost::asio::streambuf writebuff; + std::ostream out(&writebuff); + out << req.to_string(); - boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t transferred) { - (void) transferred; - if(ec) - LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); - }); + boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t transferred) { + (void) transferred; + if(ec) + LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); + }); - boost::asio::streambuf * readbuff = new boost::asio::streambuf; - boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", [=] (const boost::system::error_code & ec, std::size_t transferred) { - if(ec) - { - LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - } - else + boost::asio::streambuf * readbuff = new boost::asio::streambuf; + boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", + [=] (const boost::system::error_code & ec, std::size_t transferred) { - readbuff->commit(transferred); - i2p::http::HTTPRes res; - if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) + if(ec) + { + LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + } + else { - if(res.code == 200) + readbuff->commit(transferred); + i2p::http::HTTPRes res; + if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) { - timer->cancel(); - conn->ClientLogin(); - delete readbuff; - return; + if(res.code == 200) + { + timer->cancel(); + conn->ClientLogin(); + delete readbuff; + return; + } + else + { + LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); + } } else - { - LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); - } + LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); + timer->cancel(); + conn->Terminate(); + delete readbuff; } - else - LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); - timer->cancel(); - conn->Terminate(); - delete readbuff; - } - }); - } - else - LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); + }); + break; + } + default: + LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); + } } void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) { - if(m_ProxyEndpoint == nullptr) - { - return; - } + if(!m_ProxyEndpoint) return GetService().post([=]() { if (this->AddNTCP2Session (conn)) { @@ -1359,9 +1364,8 @@ namespace transport } NTCP2Server::NTCP2Server (): - RunnableServiceWithWork ("NTCP2"), - m_ProxyType(eNoProxy), m_Resolver(GetService ()), m_ProxyEndpoint(nullptr), - m_TerminationTimer (GetService ()) + RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), + m_Resolver(GetService ()) { } @@ -1388,11 +1392,9 @@ namespace transport } else { - m_ProxyEndpoint = new boost::asio::ip::tcp::endpoint(*itr); + m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr)); if (m_ProxyEndpoint) - { - LogPrint(eLogError, "NTCP2: m_ProxyEndpoint %s", m_ProxyEndpoint); - } + LogPrint(eLogError, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint); } } else @@ -1461,11 +1463,7 @@ namespace transport if (IsRunning ()) { m_TerminationTimer.cancel (); - if(m_ProxyEndpoint) - { - delete m_ProxyEndpoint; - m_ProxyEndpoint = nullptr; - } + m_ProxyEndpoint = nullptr; } StopIOService (); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 9e784c88..11ae5995 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -274,11 +274,11 @@ namespace transport std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; - ProxyType m_ProxyType; + ProxyType m_ProxyType =eNoProxy; std::string m_ProxyAddress; uint16_t m_ProxyPort; boost::asio::ip::tcp::resolver m_Resolver; - boost::asio::ip::tcp::endpoint * m_ProxyEndpoint; + std::unique_ptr m_ProxyEndpoint; public: From e969d58689a6a5f57e896ef6b8e0dab649904c8b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 1 Mar 2020 15:11:54 -0500 Subject: [PATCH 81/92] handle ntcp2.proxy parameter --- libi2pd/Config.cpp | 4 +- libi2pd/NTCP2.cpp | 135 +++++++++++++++++++++-------------------- libi2pd/Transports.cpp | 12 ++-- 3 files changed, 78 insertions(+), 73 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 4050f769..521ebf65 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -60,8 +60,7 @@ namespace config { ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") ("ntcp", value()->default_value(false), "Enable NTCP transport (default: disabled)") ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") - ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2proxy", value()->default_value(""), "Proxy URL for NTCP2 transport") + ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") @@ -240,6 +239,7 @@ namespace config { ("ntcp2.published", value()->default_value(true), "Publish NTCP2 (default: enabled)") ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ("ntcp2.addressv6", value()->default_value("::"), "Address to bind NTCP2 on") + ("ntcp2.proxy", value()->default_value(""), "Proxy URL for NTCP2 transport") ; options_description nettime("Time sync options"); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 10cc3d89..c46dbd81 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1189,46 +1189,48 @@ namespace transport case eSocksProxy: { // TODO: support username/password auth etc - uint8_t buff[3] = {0x05, 0x01, 0x00}; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), [=] (const boost::system::error_code & ec, std::size_t transferred) { - (void) transferred; - if(ec) - { - LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); - } - }); - uint8_t readbuff[2]; - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 2), - [=](const boost::system::error_code & ec, std::size_t transferred) - { - LogPrint(eLogError, "NTCP2: ", transferred); - if(ec) - { - LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - return; - } - else if(transferred == 2) - { - if(readbuff[1] == 0xba) + static const uint8_t buff[3] = {0x05, 0x01, 0x00}; + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), + [] (const boost::system::error_code & ec, std::size_t transferred) + { + (void) transferred; + if(ec) { - AfterSocksHandshake(conn, timer, host, port, addrtype); - return; + LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); } - else if (readbuff[1] == 0xff) + }); + auto readbuff = std::make_shared >(); + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(*readbuff, 2), + [this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred) + { + LogPrint(eLogError, "NTCP2: ", transferred); + if(ec) { - LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); + LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); timer->cancel(); conn->Terminate(); return; } - LogPrint(eLogError, "NTCP2:", readbuff[1]); - } - LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); - timer->cancel(); - conn->Terminate(); - }); + else if(transferred == 2) + { + if((*readbuff)[1] == 0xba) + { + AfterSocksHandshake(conn, timer, host, port, addrtype); + return; + } + else if ((*readbuff)[1] == 0xff) + { + LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); + timer->cancel(); + conn->Terminate(); + return; + } + LogPrint(eLogError, "NTCP2:", (*readbuff)[1]); + } + LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); + timer->cancel(); + conn->Terminate(); + }); break; } case eHTTPProxy: @@ -1245,47 +1247,47 @@ namespace transport std::ostream out(&writebuff); out << req.to_string(); - boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t transferred) { - (void) transferred; - if(ec) - LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); - }); + boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), + [](const boost::system::error_code & ec, std::size_t transferred) + { + (void) transferred; + if(ec) + LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); + }); boost::asio::streambuf * readbuff = new boost::asio::streambuf; boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", - [=] (const boost::system::error_code & ec, std::size_t transferred) - { - if(ec) - { - LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - } - else + [this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred) { - readbuff->commit(transferred); - i2p::http::HTTPRes res; - if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) + if(ec) + { + LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + } + else { - if(res.code == 200) + readbuff->commit(transferred); + i2p::http::HTTPRes res; + if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) { - timer->cancel(); - conn->ClientLogin(); - delete readbuff; - return; + if(res.code == 200) + { + timer->cancel(); + conn->ClientLogin(); + delete readbuff; + return; + } + else + LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); } else - { - LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); - } + LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); + timer->cancel(); + conn->Terminate(); + delete readbuff; } - else - LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); - timer->cancel(); - conn->Terminate(); - delete readbuff; - } - }); + }); break; } default: @@ -1304,7 +1306,8 @@ namespace transport auto timeout = NTCP_CONNECT_TIMEOUT * 5; conn->SetTerminationTimeout(timeout * 2); timer->expires_from_now (boost::posix_time::seconds(timeout)); - timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) { + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + { if (ecode != boost::asio::error::operation_aborted) { LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 34ec25f4..8a36c5aa 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -157,7 +157,7 @@ namespace transport m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy); - std::string ntcp2proxy; i2p::config::GetOption("ntcp2proxy", ntcp2proxy); + std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy); i2p::http::URL proxyurl; uint16_t softLimit, hardLimit, threads; i2p::config::GetOption("limits.ntcpsoft", softLimit); @@ -201,7 +201,7 @@ namespace transport bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { - if(ntcp2proxy.size()) + if(!ntcp2proxy.empty()) { if(proxyurl.parse(ntcp2proxy)) { @@ -223,9 +223,11 @@ namespace transport LogPrint(eLogError, "Transports: invalid NTCP2 proxy url ", ntcp2proxy); return; } - - // m_NTCP2Server = new NTCP2Server (); - // m_NTCP2Server->Start (); + else + { + m_NTCP2Server = new NTCP2Server (); + m_NTCP2Server->Start (); + } } // create acceptors From 35e8424293e62be087e4a0b5daac11153e46169a Mon Sep 17 00:00:00 2001 From: potatowipedlifereverse Date: Mon, 2 Mar 2020 01:47:48 +0300 Subject: [PATCH 82/92] preinit webview+configparser+README.md tabulation fixes configparser to comments dont need pre init webview readme changes delete submodules webview in main menu webview pre init delete modules delete submodules --- .gitmodules | 0 android/AndroidManifest.xml | 1 + android/README.md | 19 ++++++++++++++++ android/res/layout/webview.xml | 13 +++++++++++ android/res/menu/options_main.xml | 4 ++++ android/res/values/strings.xml | 1 + .../src/org/purplei2p/i2pd/I2PDActivity.java | 22 +++++++++++++++++++ 7 files changed, 60 insertions(+) create mode 100644 .gitmodules create mode 100644 android/README.md create mode 100644 android/res/layout/webview.xml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e69de29b diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 71526701..a95e3773 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -17,6 +17,7 @@ android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light.DarkActionBar" android:requestLegacyExternalStorage="true" + android:usesCleartextTraffic="true" > diff --git a/android/README.md b/android/README.md new file mode 100644 index 00000000..de6a16c3 --- /dev/null +++ b/android/README.md @@ -0,0 +1,19 @@ +# how to compile? +## Install the gradle + NDK or use android-studio +[![https://gradle.org/install/]](https://gradle.org/install/) + +## Install the depencies +``` +git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0 +git clone https://github.com/PurpleI2P/android-ifaddrs.git +git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +``` +## Set libs in jni/Application.mk on 24 line: +``` +# change to your own +I2PD_LIBS_PATH = /home/user/i2pd/android/ +``` + +## compile apk file +gradle clean assembleRelease diff --git a/android/res/layout/webview.xml b/android/res/layout/webview.xml new file mode 100644 index 00000000..d13be23e --- /dev/null +++ b/android/res/layout/webview.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/android/res/menu/options_main.xml b/android/res/menu/options_main.xml index 089c2700..b0f23bd2 100644 --- a/android/res/menu/options_main.xml +++ b/android/res/menu/options_main.xml @@ -12,6 +12,10 @@ android:id="@+id/action_graceful_stop" android:orderInCategory="98" android:title="@string/action_graceful_stop" /> + Battery Optimizations Your Android OS version does not support showing the dialog for battery optimizations for applications. Planned shutdown canceled + Start webview diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 89881b42..7949e8d0 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -39,15 +39,23 @@ import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; + import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; // For future package update checking +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + + import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS; public class I2PDActivity extends Activity { + private WebView webView; + private static final String TAG = "i2pdActvt"; private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; @@ -56,6 +64,7 @@ public class I2PDActivity extends Activity { private TextView textView; private boolean assetsCopied; private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/"; + //private ConfigParser parser = new ConfigParser(i2pdpath); // TODO: private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); @@ -262,6 +271,16 @@ public class I2PDActivity extends Activity { case R.id.action_battery_otimizations: onActionBatteryOptimizations(); return true; + case R.id.action_start_webview: + setContentView(R.layout.webview); + this.webView = (WebView) findViewById(R.id.webview1); + this.webView.setWebViewClient(new WebViewClient()); + + WebSettings webSettings = this.webView.getSettings(); + webSettings.setBuiltInZoomControls(true); + webSettings.setJavaScriptEnabled(false); + this.webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort + break; } return super.onOptionsItemSelected(item); @@ -617,4 +636,7 @@ public class I2PDActivity extends Activity { } System.exit(0); } + public String getI2pdpath(){ + return this.i2pdpath; + } } From b6368170ed4049859f8c3e22e11a3a1def7ce159 Mon Sep 17 00:00:00 2001 From: wipedlifepotato <60944239+wipedlifepotato@users.noreply.github.com> Date: Mon, 2 Mar 2020 04:00:28 +0300 Subject: [PATCH 83/92] Update README.md --- android/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/README.md b/android/README.md index de6a16c3..e0850b15 100644 --- a/android/README.md +++ b/android/README.md @@ -1,6 +1,6 @@ # how to compile? ## Install the gradle + NDK or use android-studio -[![https://gradle.org/install/]](https://gradle.org/install/) +[https://gradle.org/install/](https://gradle.org/install/) ## Install the depencies ``` From c6ccb373a22ed6df9f5c13f7ca20a77a9ecaf339 Mon Sep 17 00:00:00 2001 From: potatowipedlifereverse Date: Mon, 2 Mar 2020 05:04:37 +0300 Subject: [PATCH 84/92] del geti2pdpath --- android/src/org/purplei2p/i2pd/I2PDActivity.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 7949e8d0..258bafe2 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -636,7 +636,4 @@ public class I2PDActivity extends Activity { } System.exit(0); } - public String getI2pdpath(){ - return this.i2pdpath; - } } From 2d3fad2cdbf01f2fa19e4a9fb708db80ca432902 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Mar 2020 16:24:00 -0500 Subject: [PATCH 85/92] correct proxy buffers --- libi2pd/NTCP2.cpp | 450 +++++++++++++++++++++++----------------------- 1 file changed, 226 insertions(+), 224 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index c46dbd81..3dfd6250 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -377,78 +377,6 @@ namespace transport } } - void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) - { - - // build request - size_t sz = 0; - uint8_t buff[256]; - uint8_t readbuff[256]; - buff[0] = 0x05; - buff[1] = 0x01; - buff[2] = 0x00; - - if(addrtype == eIP4Address) - { - buff[3] = 0x01; - auto addr = boost::asio::ip::address::from_string(host).to_v4(); - auto addrbytes = addr.to_bytes(); - auto addrsize = addrbytes.size(); - memcpy(buff+4, addrbytes.data(), addrsize); - } - else if (addrtype == eIP6Address) - { - buff[3] = 0x04; - auto addr = boost::asio::ip::address::from_string(host).to_v6(); - auto addrbytes = addr.to_bytes(); - auto addrsize = addrbytes.size(); - memcpy(buff+4, addrbytes.data(), addrsize); - } - else if (addrtype == eHostname) - { - buff[3] = 0x03; - size_t addrsize = host.size(); - sz = addrsize + 1 + 4; - if (2 + sz > sizeof(buff)) - { - // too big - return; - } - buff[4] = (uint8_t) addrsize; - memcpy(buff+5, host.c_str(), addrsize); - } - htobe16buf(buff+sz, port); - sz += 2; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, sz), boost::asio::transfer_all(), [=](const boost::system::error_code & ec, std::size_t written) { - if(ec) - { - LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message()); - return; - } - }); - - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 10), [=](const boost::system::error_code & e, std::size_t transferred) { - if(e) - { - LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message()); - } - else if(transferred == sz) - { - if( readbuff[1] == 0x00) - { - timer->cancel(); - conn->ClientLogin(); - return; - } - } - if(!e) - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); - timer->cancel(); - conn->Terminate(); - }); - } - - NTCP2Session::~NTCP2Session () { delete[] m_NextReceivedBuffer; @@ -1168,158 +1096,6 @@ namespace transport EncryptAndSendNextBuffer (payloadLen); } - void NTCP2Server::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port) - { - m_ProxyType = proxytype; - m_ProxyAddress = addr; - m_ProxyPort = port; - } - - void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) - { - if (ecode) - { - LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); - timer->cancel(); - conn->Terminate(); - return; - } - switch (m_ProxyType) - { - case eSocksProxy: - { - // TODO: support username/password auth etc - static const uint8_t buff[3] = {0x05, 0x01, 0x00}; - boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), - [] (const boost::system::error_code & ec, std::size_t transferred) - { - (void) transferred; - if(ec) - { - LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); - } - }); - auto readbuff = std::make_shared >(); - boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(*readbuff, 2), - [this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred) - { - LogPrint(eLogError, "NTCP2: ", transferred); - if(ec) - { - LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - return; - } - else if(transferred == 2) - { - if((*readbuff)[1] == 0xba) - { - AfterSocksHandshake(conn, timer, host, port, addrtype); - return; - } - else if ((*readbuff)[1] == 0xff) - { - LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); - timer->cancel(); - conn->Terminate(); - return; - } - LogPrint(eLogError, "NTCP2:", (*readbuff)[1]); - } - LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); - timer->cancel(); - conn->Terminate(); - }); - break; - } - case eHTTPProxy: - { - i2p::http::HTTPReq req; - req.method = "CONNECT"; - req.version ="HTTP/1.1"; - if(addrtype == eIP6Address) - req.uri = "[" + host + "]:" + std::to_string(port); - else - req.uri = host + ":" + std::to_string(port); - - boost::asio::streambuf writebuff; - std::ostream out(&writebuff); - out << req.to_string(); - - boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), - [](const boost::system::error_code & ec, std::size_t transferred) - { - (void) transferred; - if(ec) - LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); - }); - - boost::asio::streambuf * readbuff = new boost::asio::streambuf; - boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", - [this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred) - { - if(ec) - { - LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); - timer->cancel(); - conn->Terminate(); - } - else - { - readbuff->commit(transferred); - i2p::http::HTTPRes res; - if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) - { - if(res.code == 200) - { - timer->cancel(); - conn->ClientLogin(); - delete readbuff; - return; - } - else - LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); - } - else - LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); - timer->cancel(); - conn->Terminate(); - delete readbuff; - } - }); - break; - } - default: - LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); - } - } - - void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) - { - if(!m_ProxyEndpoint) return - GetService().post([=]() { - if (this->AddNTCP2Session (conn)) - { - - auto timer = std::make_shared(GetService()); - auto timeout = NTCP_CONNECT_TIMEOUT * 5; - conn->SetTerminationTimeout(timeout * 2); - timer->expires_from_now (boost::posix_time::seconds(timeout)); - timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); - conn->Terminate (); - } - }); - conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); - } - }); - } - void NTCP2Session::SendTermination (NTCP2TerminationReason reason) { if (!m_SendKey || !m_SendSipKey) return; @@ -1640,5 +1416,231 @@ namespace transport ScheduleTermination (); } } + + void NTCP2Server::UseProxy(ProxyType proxytype, const std::string & addr, uint16_t port) + { + m_ProxyType = proxytype; + m_ProxyAddress = addr; + m_ProxyPort = port; + } + + void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + { + if (ecode) + { + LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); + timer->cancel(); + conn->Terminate(); + return; + } + switch (m_ProxyType) + { + case eSocksProxy: + { + // TODO: support username/password auth etc + static const uint8_t buff[3] = {0x05, 0x01, 0x00}; + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(), + [] (const boost::system::error_code & ec, std::size_t transferred) + { + (void) transferred; + if(ec) + { + LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); + } + }); + auto readbuff = std::make_shared >(2); + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2), + [this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred) + { + if(ec) + { + LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + return; + } + else if(transferred == 2) + { + if((*readbuff)[1] == 0x00) + { + AfterSocksHandshake(conn, timer, host, port, addrtype); + return; + } + else if ((*readbuff)[1] == 0xff) + { + LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); + timer->cancel(); + conn->Terminate(); + return; + } + LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]); + } + LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); + timer->cancel(); + conn->Terminate(); + }); + break; + } + case eHTTPProxy: + { + i2p::http::HTTPReq req; + req.method = "CONNECT"; + req.version ="HTTP/1.1"; + if(addrtype == eIP6Address) + req.uri = "[" + host + "]:" + std::to_string(port); + else + req.uri = host + ":" + std::to_string(port); + + boost::asio::streambuf writebuff; + std::ostream out(&writebuff); + out << req.to_string(); + + boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), + [](const boost::system::error_code & ec, std::size_t transferred) + { + (void) transferred; + if(ec) + LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); + }); + + boost::asio::streambuf * readbuff = new boost::asio::streambuf; + boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", + [this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred) + { + if(ec) + { + LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); + timer->cancel(); + conn->Terminate(); + } + else + { + readbuff->commit(transferred); + i2p::http::HTTPRes res; + if(res.parse(boost::asio::buffer_cast(readbuff->data()), readbuff->size()) > 0) + { + if(res.code == 200) + { + timer->cancel(); + conn->ClientLogin(); + delete readbuff; + return; + } + else + LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); + } + else + LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); + timer->cancel(); + conn->Terminate(); + delete readbuff; + } + }); + break; + } + default: + LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); + } + } + + void NTCP2Server::ConnectWithProxy (const std::string& host, uint16_t port, RemoteAddressType addrtype, std::shared_ptr conn) + { + if(!m_ProxyEndpoint) return; + GetService().post([this, host, port, addrtype, conn]() { + if (this->AddNTCP2Session (conn)) + { + + auto timer = std::make_shared(GetService()); + auto timeout = NTCP_CONNECT_TIMEOUT * 5; + conn->SetTerminationTimeout(timeout * 2); + timer->expires_from_now (boost::posix_time::seconds(timeout)); + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + conn->Terminate (); + } + }); + conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer, host, port, addrtype)); + } + }); + } + + void NTCP2Server::AfterSocksHandshake(std::shared_ptr conn, std::shared_ptr timer, const std::string & host, uint16_t port, RemoteAddressType addrtype) + { + // build request + size_t sz = 0; + auto buff = std::make_shared >(256); + auto readbuff = std::make_shared >(256); + (*buff)[0] = 0x05; + (*buff)[1] = 0x01; + (*buff)[2] = 0x00; + + if(addrtype == eIP4Address) + { + (*buff)[3] = 0x01; + auto addr = boost::asio::ip::address::from_string(host).to_v4(); + auto addrbytes = addr.to_bytes(); + auto addrsize = addrbytes.size(); + memcpy(buff->data () + 4, addrbytes.data(), addrsize); + } + else if (addrtype == eIP6Address) + { + (*buff)[3] = 0x04; + auto addr = boost::asio::ip::address::from_string(host).to_v6(); + auto addrbytes = addr.to_bytes(); + auto addrsize = addrbytes.size(); + memcpy(buff->data () + 4, addrbytes.data(), addrsize); + } + else if (addrtype == eHostname) + { + (*buff)[3] = 0x03; + size_t addrsize = host.size(); + sz = addrsize + 1 + 4; + if (2 + sz > buff->size ()) + { + // too big + return; + } + (*buff)[4] = (uint8_t) addrsize; + memcpy(buff->data() + 5, host.c_str(), addrsize); + } + htobe16buf(buff->data () + sz, port); + sz += 2; + boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(), + [](const boost::system::error_code & ec, std::size_t written) + { + if(ec) + { + LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message()); + return; + } + }); + + boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 10), + [timer, conn, sz, readbuff](const boost::system::error_code & e, std::size_t transferred) + { + if(e) + { + LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message()); + } + else if(transferred == sz) + { + if((*readbuff)[1] == 0x00) + { + timer->cancel(); + conn->ClientLogin(); + return; + } + } + if(!e) + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + timer->cancel(); + conn->Terminate(); + }); + } + } } From 1e9a53da3fead5b1caaea7145ef90eb411bc2ff7 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Mar 2020 15:54:09 -0500 Subject: [PATCH 86/92] delete stream by id for HTTP interface --- libi2pd/Destination.cpp | 10 ++++++++++ libi2pd/Destination.h | 1 + libi2pd/Streaming.cpp | 9 +++++++++ libi2pd/Streaming.h | 1 + 4 files changed, 21 insertions(+) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 6544d120..d4620ed9 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -1191,6 +1191,16 @@ namespace client } } + bool ClientDestination::DeleteStream (uint32_t recvStreamID) + { + if (m_StreamingDestination->DeleteStream (recvStreamID)) + return true; + for (auto it: m_StreamingDestinationsByPorts) + if (it.second->DeleteStream (recvStreamID)) + return true; + return false; + } + RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params): RunnableService ("Destination"), ClientDestination (GetIOService (), keys, isPublic, params) diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index ed3abdfb..23ed5188 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -281,6 +281,7 @@ namespace client // for HTTP only std::vector > GetAllStreams () const; + bool DeleteStream (uint32_t recvStreamID); }; class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index b5f935fe..97a653f5 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -1128,6 +1128,15 @@ namespace stream } } + bool StreamingDestination::DeleteStream (uint32_t recvStreamID) + { + auto it = m_Streams.find (recvStreamID); + if (it == m_Streams.end ()) + return false; + DeleteStream (it->second); + return true; + } + void StreamingDestination::SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 3424bb2d..9962ad8d 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -250,6 +250,7 @@ namespace stream std::shared_ptr CreateNewOutgoingStream (std::shared_ptr remote, int port = 0); void DeleteStream (std::shared_ptr stream); + bool DeleteStream (uint32_t recvStreamID); void SetAcceptor (const Acceptor& acceptor); void ResetAcceptor (); bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; From 5eec580727df7d2865f6478ccb21498fafa2556f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Mar 2020 18:31:22 -0500 Subject: [PATCH 87/92] delete strem from destination upon termination --- libi2pd/Streaming.cpp | 7 ++++--- libi2pd/Streaming.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 97a653f5..3efcfb99 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -86,13 +86,14 @@ namespace stream LogPrint (eLogDebug, "Streaming: Stream deleted"); } - void Stream::Terminate () // shoudl be called from StreamingDestination::Stop only + void Stream::Terminate (bool deleteFromDestination) // 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 ()); + if (deleteFromDestination) + m_LocalDestination.DeleteStream (shared_from_this ()); } void Stream::CleanUp () @@ -993,7 +994,7 @@ namespace stream { std::unique_lock l(m_StreamsMutex); for (auto it: m_Streams) - it.second->Terminate (); + it.second->Terminate (false); // we delete here m_Streams.clear (); m_IncomingStreams.clear (); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9962ad8d..985a7eca 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -180,7 +180,7 @@ namespace stream int GetWindowSize () const { return m_WindowSize; }; int GetRTT () const { return m_RTT; }; - void Terminate (); + void Terminate (bool deleteFromDestination = true); private: From 51d018acc61c84aca55d669a2157fdcf3e8cd4c3 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 5 Mar 2020 04:14:39 +0300 Subject: [PATCH 88/92] webconsole: add stream closing Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 180 ++++++++++++++++++++++++++++-------------- daemon/HTTPServer.h | 1 + 2 files changed, 121 insertions(+), 60 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 7dc6a9d2..36e26785 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -54,6 +54,7 @@ namespace http { " body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n" " a, .slide label { text-decoration: none; color: #894C84; }\r\n" " a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n" + " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial;}\r\n" " .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n" " .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n" " .left { float: left; position: absolute; }\r\n" @@ -64,10 +65,11 @@ namespace http { " .tunnel.building { color: #434343; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" " table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" - " .slide p, .slide [type='checkbox']{ display:none; }\r\n" - " .slide [type='checkbox']:checked ~ p { display:block; margin-top: 0; padding: 0; }\r\n" + " .slide p, .slide [type='checkbox'] { display: none; }\r\n" + " .slide [type='checkbox']:checked ~ p { display: block; margin-top: 0; padding: 0; }\r\n" " .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n" " .enabled:after { color: #56B734; content: \"Enabled\" }\r\n" + " .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" "\r\n"; const char HTTP_PAGE_TUNNELS[] = "tunnels"; @@ -89,10 +91,12 @@ namespace http { const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config"; const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel"; + const char HTTP_COMMAND_KILLSTREAM[] = "closestream"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_ADDRESS[] = "address"; static std::string ConvertTime (uint64_t time); + std::map HTTPConnection::m_Tokens; static void ShowUptime (std::stringstream& s, int seconds) { @@ -203,10 +207,7 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - void ShowStatus ( - std::stringstream& s, - bool includeHiddenContent, - i2p::http::OutputFormatEnum outputFormat) + void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat) { s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); @@ -253,12 +254,12 @@ namespace http { ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; - s << "
"; - if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { - s << "\r\n\r\n

\r\n"; - } - if(includeHiddenContent) { - s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; + s << "

"; + if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { + s << "\r\n\r\n

\r\n"; + } + if(includeHiddenContent) { + s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; s << "Our external address:" << "
\r\n" ; @@ -292,12 +293,12 @@ namespace http { } s << address->host.to_string() << ":" << address->port << "
\r\n"; } - } + } s << "

\r\n
\r\n"; - if(outputFormat==OutputFormatEnum::forQtUi) { - s << "
"; - } - s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; + if(outputFormat==OutputFormatEnum::forQtUi) { + s << "
"; + } + s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
\r\n"; @@ -308,17 +309,17 @@ namespace http { s << "Client Tunnels: " << std::to_string(clientTunnelCount) << " "; s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n
\r\n"; - if(outputFormat==OutputFormatEnum::forWebConsole) { - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); - s << "\r\n"; - s << "
Services
ServiceState
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; - } + if(outputFormat==OutputFormatEnum::forWebConsole) { + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); + s << "\r\n"; + s << "
Services
ServiceState
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; + } } void ShowLocalDestinations (std::stringstream& s) @@ -352,7 +353,7 @@ namespace http { static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr dest) { - s << "Base64:
\r\n
\r\n
\r\n"; if (dest->IsEncryptedLeaseSet ()) { @@ -403,19 +404,21 @@ namespace http { s << "
\r\n"; } - void ShowLocalDestination (std::stringstream& s, const std::string& b32) + void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token) { s << "Local Destination:
\r\n
\r\n"; i2p::data::IdentHash ident; ident.FromBase32 (b32); auto dest = i2p::client::context.FindLocalDestination (ident); + if (dest) { ShowLeaseSetDestination (s, dest); // show streams - s << "\r\n"; - s << ""; - s << ""; + s << "
Streams
StreamIDDestination
\r\n\r\n\r\n"; + s << ""; + s << ""; s << ""; s << ""; s << ""; @@ -424,13 +427,20 @@ namespace http { s << ""; s << ""; s << ""; - s << "\r\n"; + s << "\r\n\r\n\r\n"; for (const auto& it: dest->GetAllStreams ()) { + auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()); s << ""; - s << ""; - s << ""; + s << ""; + if (it->GetRecvStreamID ()) { + s << ""; + } else { + s << ""; s << ""; s << ""; s << ""; @@ -441,7 +451,7 @@ namespace http { s << ""; s << "\r\n"; } - s << "
Streams
StreamID"; // Stream closing button column + s << "DestinationSentReceivedOutRTTWindowStatus
" << it->GetSendStreamID () << "" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "" << it->GetRecvStreamID () << ""; + } + s << "" << streamDest << "" << it->GetNumSentBytes () << "" << it->GetNumReceivedBytes () << "" << it->GetSendQueueSize () << "" << (int)it->GetStatus () << "
"; + s << "\r\n"; } } @@ -858,7 +868,8 @@ namespace http { m_Socket->close (); } - bool HTTPConnection::CheckAuth (const HTTPReq & req) { + bool HTTPConnection::CheckAuth (const HTTPReq & req) + { /* method #1: http://user:pass@127.0.0.1:7070/ */ if (req.uri.find('@') != std::string::npos) { URL url; @@ -920,7 +931,7 @@ namespace http { } else if (req.uri.find("cmd=") != std::string::npos) { HandleCommand (req, res, s); } else { - ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole); + ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole); res.add_header("Refresh", "10"); } ShowPageTail (s); @@ -930,7 +941,23 @@ namespace http { SendReply (res, content); } - std::map HTTPConnection::m_Tokens; + uint32_t HTTPConnection::CreateToken () + { + uint32_t token; + RAND_bytes ((uint8_t *)&token, 4); + token &= 0x7FFFFFFF; // clear first bit + auto ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_Tokens.begin (); it != m_Tokens.end (); ) + { + if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT) + it = m_Tokens.erase (it); + else + ++it; + } + m_Tokens[token] = ts; + return token; + } + void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) { std::map params; @@ -947,18 +974,7 @@ namespace http { ShowTunnels (s); else if (page == HTTP_PAGE_COMMANDS) { - uint32_t token; - RAND_bytes ((uint8_t *)&token, 4); - token &= 0x7FFFFFFF; // clear first bit - auto ts = i2p::util::GetSecondsSinceEpoch (); - for (auto it = m_Tokens.begin (); it != m_Tokens.end (); ) - { - if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT) - it = m_Tokens.erase (it); - else - ++it; - } - m_Tokens[token] = ts; + uint32_t token = CreateToken (); ShowCommands (s, token); } else if (page == HTTP_PAGE_TRANSIT_TUNNELS) @@ -966,7 +982,10 @@ namespace http { else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) ShowLocalDestinations (s); else if (page == HTTP_PAGE_LOCAL_DESTINATION) - ShowLocalDestination (s, params["b32"]); + { + uint32_t token = CreateToken (); + ShowLocalDestination (s, params["b32"], token); + } else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION) ShowI2CPLocalDestination (s, params["i2cp_id"]); else if (page == HTTP_PAGE_SAM_SESSIONS) @@ -992,7 +1011,10 @@ namespace http { url.parse(req.uri); url.parse_query(params); + std::string webroot; i2p::config::GetOption("http.webroot", webroot); + std::string redirect = "5; url=" + webroot + "?page=commands"; std::string token = params["token"]; + if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ()) { ShowError(s, "Invalid token"); @@ -1008,36 +1030,74 @@ namespace http { i2p::context.SetAcceptsTunnels (true); else if (cmd == HTTP_COMMAND_DISABLE_TRANSIT) i2p::context.SetAcceptsTunnels (false); - else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { + else if (cmd == HTTP_COMMAND_SHUTDOWN_START) + { i2p::context.SetAcceptsTunnels (false); #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) Daemon.gracefulShutdownInterval = 10*60; #elif defined(WIN32_APP) i2p::win32::GracefulShutdown (); #endif - } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { + } + else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) + { i2p::context.SetAcceptsTunnels (true); #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) Daemon.gracefulShutdownInterval = 0; #elif defined(WIN32_APP) i2p::win32::StopGracefulShutdown (); #endif - } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { + } + else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) + { #ifndef WIN32_APP Daemon.running = false; #else i2p::win32::StopWin32App (); #endif - } else if (cmd == HTTP_COMMAND_LOGLEVEL){ + } + else if (cmd == HTTP_COMMAND_LOGLEVEL) + { std::string level = params["level"]; SetLogLevel (level); - } else { + } + else if (cmd == HTTP_COMMAND_KILLSTREAM) + { + std::string b32 = params["b32"]; + uint32_t streamID = std::stoul(params["streamID"], nullptr); + + i2p::data::IdentHash ident; + ident.FromBase32 (b32); + auto dest = i2p::client::context.FindLocalDestination (ident); + + if (streamID) + { + if (dest) + { + if(dest->DeleteStream (streamID)) + s << "SUCCESS: Stream closed

\r\n"; + else + s << "ERROR: Stream not found or already was closed

\r\n"; + } + else + s << "ERROR: Destination not found

\r\n"; + } + else + s << "ERROR: StreamID can be null

\r\n"; + + s << "Return to destination page
\r\n"; + s << "

You will be redirected back in 5 seconds"; + redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32; + res.add_header("Refresh", redirect.c_str()); + return; + } + else + { res.code = 400; ShowError(s, "Unknown command: " + cmd); return; } - std::string webroot; i2p::config::GetOption("http.webroot", webroot); - std::string redirect = "5; url=" + webroot + "?page=commands"; + s << "SUCCESS: Command accepted

\r\n"; s << "Back to commands list
\r\n"; s << "

You will be redirected in 5 seconds"; diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index 3d32ed2b..f5ac95fc 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -35,6 +35,7 @@ namespace http void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data); void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data); void SendReply (HTTPRes & res, std::string & content); + uint32_t CreateToken (); private: From dd9b5faa5c072c24aadf4ca6c31d6ac00be992e1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Mar 2020 18:44:15 -0500 Subject: [PATCH 89/92] fixed crash on termination --- libi2pd_client/I2CP.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index a14588a8..c09b7f4d 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -814,8 +814,11 @@ namespace client { m_IsRunning = false; m_Acceptor.cancel (); - for (auto& it: m_Sessions) - it.second->Stop (); + { + auto sessions = m_Sessions; + for (auto& it: sessions) + it.second->Stop (); + } m_Sessions.clear (); m_Service.stop (); if (m_Thread) From 64da62dbe69be040215babad89fc481f0e429c00 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Mar 2020 18:46:40 -0500 Subject: [PATCH 90/92] alsways store latest symmkey --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 33 ++++++++++++++--------- libi2pd/ECIESX25519AEADRatchetSession.h | 4 +-- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index d2d07343..a066dc17 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -39,25 +39,28 @@ namespace garlic return m_KeyData.GetTag (); } - const uint8_t * RatchetTagSet::GetSymmKey (int index) + void RatchetTagSet::GetSymmKey (int index, uint8_t * key) { - // TODO: store intermediate keys - if (m_NextSymmKeyIndex > 0 && index == m_NextSymmKeyIndex) + if (m_NextSymmKeyIndex > 0 && index >= m_NextSymmKeyIndex) { - i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); - m_NextSymmKeyIndex++; + auto num = index + 1 - m_NextSymmKeyIndex; + for (int i = 0; i < num; i++) + i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); + m_NextSymmKeyIndex += num; + memcpy (key, m_CurrentSymmKeyCK + 32, 32); } else - CalculateSymmKeyCK (index); - return m_CurrentSymmKeyCK + 32; + CalculateSymmKeyCK (index, key); } - void RatchetTagSet::CalculateSymmKeyCK (int index) + void RatchetTagSet::CalculateSymmKeyCK (int index, uint8_t * key) { - i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64) + // TODO: store intermediate keys + uint8_t currentSymmKeyCK[64]; + i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", 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; + i2p::crypto::HKDF (currentSymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64) + memcpy (key, currentSymmKeyCK + 32, 32); } ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): @@ -373,7 +376,9 @@ namespace garlic 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_SendTagset.GetSymmKey (index), nonce, out + 8, outLen - 8, true)) // encrypt + uint8_t key[32]; + m_SendTagset.GetSymmKey (index, key); + if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; @@ -387,7 +392,9 @@ 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_ReceiveTagset.GetSymmKey (index), nonce, payload.data (), len - 16, false)) // decrypt + uint8_t key[32]; + m_ReceiveTagset.GetSymmKey (index, key); + if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, key, 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 e5836cd4..f23c569c 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -22,11 +22,11 @@ namespace garlic void NextSessionTagRatchet (); uint64_t GetNextSessionTag (); int GetNextIndex () const { return m_NextIndex; }; - const uint8_t * GetSymmKey (int index); + void GetSymmKey (int index, uint8_t * key); private: - void CalculateSymmKeyCK (int index); + void CalculateSymmKeyCK (int index, uint8_t * key); private: From 4adc741de319ee2afc6f51f180fff33db63869b6 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Mar 2020 18:13:41 -0400 Subject: [PATCH 91/92] send DeliveryStatusMsg for LeaseSet --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 53 ++++++++++++++++++-- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + libi2pd/Garlic.cpp | 60 ++++++++++++++--------- libi2pd/Garlic.h | 11 +++-- 4 files changed, 96 insertions(+), 29 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index a066dc17..5f2eb5c8 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -6,6 +6,8 @@ #include "Tag.h" #include "I2PEndian.h" #include "Timestamp.h" +#include "Tunnel.h" +#include "TunnelPool.h" #include "ECIESX25519AEADRatchetSession.h" namespace i2p @@ -460,12 +462,22 @@ namespace garlic std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg) { + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); size_t payloadLen = 7; // datatime if (msg && m_Destination) payloadLen += msg->GetPayloadLength () + 13 + 32; - auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()); - if (leaseSet) + auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated) ? CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()) : nullptr; + std::shared_ptr deliveryStatus; + if (leaseSet) + { payloadLen += leaseSet->GetPayloadLength () + 13; + deliveryStatus = CreateEncryptedDeliveryStatusMsg (leaseSet->GetMsgID ()); + payloadLen += deliveryStatus->GetPayloadLength () + 49; + if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous + SetLeaseSetUpdateStatus (eLeaseSetSubmitted); + SetLeaseSetUpdateMsgID (leaseSet->GetMsgID ()); + SetLeaseSetSubmissionTime (ts); + } uint8_t paddingSize; RAND_bytes (&paddingSize, 1); paddingSize &= 0x0F; paddingSize++; // 1 - 16 @@ -475,10 +487,13 @@ namespace garlic // DateTime v[offset] = eECIESx25519BlkDateTime; offset++; htobe16buf (v.data () + offset, 4); offset += 2; - htobe32buf (v.data () + offset, i2p::util::GetSecondsSinceEpoch ()); offset += 4; + htobe32buf (v.data () + offset, ts/1000); offset += 4; // in seconds // LeaseSet if (leaseSet) offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset); + // DeliveryStatus + if (deliveryStatus) + offset += CreateDeliveryStatusClove (deliveryStatus, v.data () + offset, payloadLen - offset); // msg if (msg && m_Destination) offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true); @@ -513,6 +528,38 @@ namespace garlic return cloveSize + 3; } + size_t ECIESX25519AEADRatchetSession::CreateDeliveryStatusClove (std::shared_ptr msg, uint8_t * buf, size_t len) + { + uint16_t cloveSize = msg->GetPayloadLength () + 9 + 37 /* delivery instruction */; + if ((int)len < cloveSize + 3) return 0; + buf[0] = eECIESx25519BlkGalicClove; // clove type + htobe16buf (buf + 1, cloveSize); // size + buf += 3; + if (GetOwner ()) + { + auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel (); + if (inboundTunnel) + { + // delivery instructions + *buf = eGarlicDeliveryTypeTunnel << 5; buf++; // delivery instructions flag tunnel + // hash and tunnelID sequence is reversed for Garlic + memcpy (buf, inboundTunnel->GetNextIdentHash (), 32); buf += 32;// To Hash + htobe32buf (buf, inboundTunnel->GetNextTunnelID ()); buf += 4;// tunnelID + } + else + { + LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus"); + return 0; + } + htobe32buf (buf + 1, msg->GetMsgID ()); // msgID + htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds + memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ()); + } + else + return 0; + return cloveSize + 3; + } + void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (int numTags) { for (int i = 0; i < numTags; i++) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index f23c569c..4d273c13 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -107,6 +107,7 @@ 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); + size_t CreateDeliveryStatusClove (std::shared_ptr msg, uint8_t * buf, size_t len); void GenerateMoreReceiveTags (int numTags); diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 45c97172..dd63572c 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -58,6 +58,34 @@ namespace garlic m_SharedRoutingPath = path; } + bool GarlicRoutingSession::MessageConfirmed (uint32_t msgID) + { + if (msgID == GetLeaseSetUpdateMsgID ()) + { + SetLeaseSetUpdateStatus (eLeaseSetUpToDate); + SetLeaseSetUpdateMsgID (0); + LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); + return true; + } + return false; + } + + std::shared_ptr GarlicRoutingSession::CreateEncryptedDeliveryStatusMsg (uint32_t msgID) + { + auto msg = CreateDeliveryStatusMsg (msgID); + if (GetOwner ()) + { + //encrypt + uint8_t key[32], tag[32]; + RAND_bytes (key, 32); // random session key + RAND_bytes (tag, 32); // random session tag + GetOwner ()->SubmitSessionKey (key, tag); + ElGamalAESSession garlic (key, tag); + msg = garlic.WrapSingleMessage (msg); + } + return msg; + } + ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner, std::shared_ptr destination, int numTags, bool attachLeaseSet): GarlicRoutingSession (owner, attachLeaseSet), @@ -289,19 +317,12 @@ namespace garlic htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID size += 4; // create msg - auto msg = CreateDeliveryStatusMsg (msgID); - if (GetOwner ()) - { - //encrypt - uint8_t key[32], tag[32]; - RAND_bytes (key, 32); // random session key - RAND_bytes (tag, 32); // random session tag - GetOwner ()->SubmitSessionKey (key, tag); - ElGamalAESSession garlic (key, tag); - msg = garlic.WrapSingleMessage (msg); - } - memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); - size += msg->GetLength (); + auto msg = CreateEncryptedDeliveryStatusMsg (msgID); + if (msg) + { + memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); + size += msg->GetLength (); + } // fill clove uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec uint32_t cloveID; @@ -334,17 +355,12 @@ namespace garlic return tags; } - void ElGamalAESSession::MessageConfirmed (uint32_t msgID) + bool ElGamalAESSession::MessageConfirmed (uint32_t msgID) { TagsConfirmed (msgID); - if (msgID == GetLeaseSetUpdateMsgID ()) - { - SetLeaseSetUpdateStatus (eLeaseSetUpToDate); - SetLeaseSetUpdateMsgID (0); - LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); - } - else + if (!GarlicRoutingSession::MessageConfirmed (msgID)) CleanupExpiredTags (); + return true; } void ElGamalAESSession::TagsConfirmed (uint32_t msgID) @@ -775,7 +791,7 @@ namespace garlic void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID) { - ElGamalAESSessionPtr session; + GarlicRoutingSessionPtr session; { std::unique_lock l(m_DeliveryStatusSessionsMutex); auto it = m_DeliveryStatusSessions.find (msgID); diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 9c256b48..be0ac117 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -104,7 +104,8 @@ namespace garlic virtual ~GarlicRoutingSession (); virtual std::shared_ptr WrapSingleMessage (std::shared_ptr msg) = 0; virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession - + virtual bool MessageConfirmed (uint32_t msgID); + void SetLeaseSetUpdated () { if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; @@ -118,7 +119,7 @@ namespace garlic GarlicDestination * GetOwner () const { return m_Owner; } void SetOwner (GarlicDestination * owner) { m_Owner = owner; } - + protected: LeaseSetUpdateStatus GetLeaseSetUpdateStatus () const { return m_LeaseSetUpdateStatus; } @@ -127,6 +128,8 @@ namespace garlic void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; } void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; } + std::shared_ptr CreateEncryptedDeliveryStatusMsg (uint32_t msgID); + private: GarlicDestination * m_Owner; @@ -165,7 +168,7 @@ namespace garlic std::shared_ptr WrapSingleMessage (std::shared_ptr msg); - void MessageConfirmed (uint32_t msgID); + bool MessageConfirmed (uint32_t msgID); bool CleanupExpiredTags (); // returns true if something left bool CleanupUnconfirmedTags (); // returns true if something has been deleted @@ -267,7 +270,7 @@ namespace garlic std::unordered_map m_ECIESx25519Tags; // session tag -> session // DeliveryStatus std::mutex m_DeliveryStatusSessionsMutex; - std::unordered_map m_DeliveryStatusSessions; // msgID -> session + std::unordered_map m_DeliveryStatusSessions; // msgID -> session public: From 3c534798643d9b0e7f7a529b24beacd679732281 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 8 Mar 2020 20:58:59 -0400 Subject: [PATCH 92/92] update LeaseSet for ECIESX25519AEADRatchet sessions --- libi2pd/Garlic.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index dd63572c..9ac5540f 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -810,8 +810,12 @@ namespace garlic void GarlicDestination::SetLeaseSetUpdated () { - std::unique_lock l(m_SessionsMutex); - for (auto& it: m_Sessions) + { + std::unique_lock l(m_SessionsMutex); + for (auto& it: m_Sessions) + it.second->SetLeaseSetUpdated (); + } + for (auto& it: m_ECIESx25519Sessions) it.second->SetLeaseSetUpdated (); }